diff --git a/README.md b/README.md index 1c4a7087..8251b889 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Authorization: Bearer - 客户端先经 gateway 调 `JoinRoom`,让用户进入 `room-service` presence。 - 客户端再用腾讯云 IM SDK 登录并加入 `room_id` 对应的群组。 -- `gateway-service` 创建房间时从 access token 取当前 `user_id` 写入 `RequestMeta.actor_user_id`;`room-service` 由该 actor 收敛 owner 和默认 host,外部 CreateRoom 请求体不接收 `owner_user_id` 和 `host_user_id`。 +- `gateway-service` 创建房间时从 access token 取当前 `user_id` 写入 `RequestMeta.actor_user_id`;`room-service` 由该 actor 收敛 owner,外部 CreateRoom 请求体不接收 `owner_user_id`。 - `X-Request-ID`/`request_id` 由后端生成,只做链路追踪;写操作的 `command_id` 由前端按用户动作生成,用于服务端幂等。 - `room-service` 在 `CreateRoom` 时通过腾讯云 IM REST API 创建同名群组。 - `room-service` 在上下麦、禁言、踢人、送礼等命令提交后,通过腾讯云 IM REST API 发送房间系统自定义消息。 diff --git a/api/proto/activity/v1/activity.pb.go b/api/proto/activity/v1/activity.pb.go index 220147ae..75a682c2 100644 --- a/api/proto/activity/v1/activity.pb.go +++ b/api/proto/activity/v1/activity.pb.go @@ -3735,6 +3735,983 @@ func (x *SetTaskDefinitionStatusResponse) GetTask() *TaskDefinition { return nil } +// RegistrationRewardConfig 是注册奖励的当前配置;enabled=false 时保留配置但不自动发放。 +type RegistrationRewardConfig 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"` + Enabled bool `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled,omitempty"` + RewardType string `protobuf:"bytes,3,opt,name=reward_type,json=rewardType,proto3" json:"reward_type,omitempty"` + CoinAmount int64 `protobuf:"varint,4,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` + ResourceGroupId int64 `protobuf:"varint,5,opt,name=resource_group_id,json=resourceGroupId,proto3" json:"resource_group_id,omitempty"` + DailyLimit int64 `protobuf:"varint,6,opt,name=daily_limit,json=dailyLimit,proto3" json:"daily_limit,omitempty"` + UpdatedByAdminId int64 `protobuf:"varint,7,opt,name=updated_by_admin_id,json=updatedByAdminId,proto3" json:"updated_by_admin_id,omitempty"` + CreatedAtMs int64 `protobuf:"varint,8,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,9,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` +} + +func (x *RegistrationRewardConfig) Reset() { + *x = RegistrationRewardConfig{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegistrationRewardConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegistrationRewardConfig) ProtoMessage() {} + +func (x *RegistrationRewardConfig) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[49] + 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 RegistrationRewardConfig.ProtoReflect.Descriptor instead. +func (*RegistrationRewardConfig) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{49} +} + +func (x *RegistrationRewardConfig) GetAppCode() string { + if x != nil { + return x.AppCode + } + return "" +} + +func (x *RegistrationRewardConfig) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *RegistrationRewardConfig) GetRewardType() string { + if x != nil { + return x.RewardType + } + return "" +} + +func (x *RegistrationRewardConfig) GetCoinAmount() int64 { + if x != nil { + return x.CoinAmount + } + return 0 +} + +func (x *RegistrationRewardConfig) GetResourceGroupId() int64 { + if x != nil { + return x.ResourceGroupId + } + return 0 +} + +func (x *RegistrationRewardConfig) GetDailyLimit() int64 { + if x != nil { + return x.DailyLimit + } + return 0 +} + +func (x *RegistrationRewardConfig) GetUpdatedByAdminId() int64 { + if x != nil { + return x.UpdatedByAdminId + } + return 0 +} + +func (x *RegistrationRewardConfig) GetCreatedAtMs() int64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *RegistrationRewardConfig) GetUpdatedAtMs() int64 { + if x != nil { + return x.UpdatedAtMs + } + return 0 +} + +// RegistrationRewardClaim 是每个用户注册奖励的领取事实;user_id 唯一保证“没有领过”。 +type RegistrationRewardClaim struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClaimId string `protobuf:"bytes,1,opt,name=claim_id,json=claimId,proto3" json:"claim_id,omitempty"` + CommandId string `protobuf:"bytes,2,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + RewardDay string `protobuf:"bytes,4,opt,name=reward_day,json=rewardDay,proto3" json:"reward_day,omitempty"` + RewardType string `protobuf:"bytes,5,opt,name=reward_type,json=rewardType,proto3" json:"reward_type,omitempty"` + CoinAmount int64 `protobuf:"varint,6,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` + ResourceGroupId int64 `protobuf:"varint,7,opt,name=resource_group_id,json=resourceGroupId,proto3" json:"resource_group_id,omitempty"` + Status string `protobuf:"bytes,8,opt,name=status,proto3" json:"status,omitempty"` + WalletCommandId string `protobuf:"bytes,9,opt,name=wallet_command_id,json=walletCommandId,proto3" json:"wallet_command_id,omitempty"` + WalletTransactionId string `protobuf:"bytes,10,opt,name=wallet_transaction_id,json=walletTransactionId,proto3" json:"wallet_transaction_id,omitempty"` + ResourceGrantId string `protobuf:"bytes,11,opt,name=resource_grant_id,json=resourceGrantId,proto3" json:"resource_grant_id,omitempty"` + FailureReason string `protobuf:"bytes,12,opt,name=failure_reason,json=failureReason,proto3" json:"failure_reason,omitempty"` + ClaimedAtMs int64 `protobuf:"varint,13,opt,name=claimed_at_ms,json=claimedAtMs,proto3" json:"claimed_at_ms,omitempty"` + CreatedAtMs int64 `protobuf:"varint,14,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,15,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` +} + +func (x *RegistrationRewardClaim) Reset() { + *x = RegistrationRewardClaim{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegistrationRewardClaim) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegistrationRewardClaim) ProtoMessage() {} + +func (x *RegistrationRewardClaim) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[50] + 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 RegistrationRewardClaim.ProtoReflect.Descriptor instead. +func (*RegistrationRewardClaim) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{50} +} + +func (x *RegistrationRewardClaim) GetClaimId() string { + if x != nil { + return x.ClaimId + } + return "" +} + +func (x *RegistrationRewardClaim) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +func (x *RegistrationRewardClaim) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *RegistrationRewardClaim) GetRewardDay() string { + if x != nil { + return x.RewardDay + } + return "" +} + +func (x *RegistrationRewardClaim) GetRewardType() string { + if x != nil { + return x.RewardType + } + return "" +} + +func (x *RegistrationRewardClaim) GetCoinAmount() int64 { + if x != nil { + return x.CoinAmount + } + return 0 +} + +func (x *RegistrationRewardClaim) GetResourceGroupId() int64 { + if x != nil { + return x.ResourceGroupId + } + return 0 +} + +func (x *RegistrationRewardClaim) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *RegistrationRewardClaim) GetWalletCommandId() string { + if x != nil { + return x.WalletCommandId + } + return "" +} + +func (x *RegistrationRewardClaim) GetWalletTransactionId() string { + if x != nil { + return x.WalletTransactionId + } + return "" +} + +func (x *RegistrationRewardClaim) GetResourceGrantId() string { + if x != nil { + return x.ResourceGrantId + } + return "" +} + +func (x *RegistrationRewardClaim) GetFailureReason() string { + if x != nil { + return x.FailureReason + } + return "" +} + +func (x *RegistrationRewardClaim) GetClaimedAtMs() int64 { + if x != nil { + return x.ClaimedAtMs + } + return 0 +} + +func (x *RegistrationRewardClaim) GetCreatedAtMs() int64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *RegistrationRewardClaim) GetUpdatedAtMs() int64 { + if x != nil { + return x.UpdatedAtMs + } + return 0 +} + +// RegistrationRewardEligibility 返回 App 可直接展示的资格判断;每日份数按 UTC reward_day 统计。 +type RegistrationRewardEligibility struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CanReceive bool `protobuf:"varint,1,opt,name=can_receive,json=canReceive,proto3" json:"can_receive,omitempty"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` + Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` + RewardType string `protobuf:"bytes,4,opt,name=reward_type,json=rewardType,proto3" json:"reward_type,omitempty"` + CoinAmount int64 `protobuf:"varint,5,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` + ResourceGroupId int64 `protobuf:"varint,6,opt,name=resource_group_id,json=resourceGroupId,proto3" json:"resource_group_id,omitempty"` + DailyLimit int64 `protobuf:"varint,7,opt,name=daily_limit,json=dailyLimit,proto3" json:"daily_limit,omitempty"` + DailyUsed int64 `protobuf:"varint,8,opt,name=daily_used,json=dailyUsed,proto3" json:"daily_used,omitempty"` + DailyRemaining int64 `protobuf:"varint,9,opt,name=daily_remaining,json=dailyRemaining,proto3" json:"daily_remaining,omitempty"` + RewardDay string `protobuf:"bytes,10,opt,name=reward_day,json=rewardDay,proto3" json:"reward_day,omitempty"` + ServerTimeMs int64 `protobuf:"varint,11,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"` +} + +func (x *RegistrationRewardEligibility) Reset() { + *x = RegistrationRewardEligibility{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegistrationRewardEligibility) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegistrationRewardEligibility) ProtoMessage() {} + +func (x *RegistrationRewardEligibility) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[51] + 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 RegistrationRewardEligibility.ProtoReflect.Descriptor instead. +func (*RegistrationRewardEligibility) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{51} +} + +func (x *RegistrationRewardEligibility) GetCanReceive() bool { + if x != nil { + return x.CanReceive + } + return false +} + +func (x *RegistrationRewardEligibility) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *RegistrationRewardEligibility) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *RegistrationRewardEligibility) GetRewardType() string { + if x != nil { + return x.RewardType + } + return "" +} + +func (x *RegistrationRewardEligibility) GetCoinAmount() int64 { + if x != nil { + return x.CoinAmount + } + return 0 +} + +func (x *RegistrationRewardEligibility) GetResourceGroupId() int64 { + if x != nil { + return x.ResourceGroupId + } + return 0 +} + +func (x *RegistrationRewardEligibility) GetDailyLimit() int64 { + if x != nil { + return x.DailyLimit + } + return 0 +} + +func (x *RegistrationRewardEligibility) GetDailyUsed() int64 { + if x != nil { + return x.DailyUsed + } + return 0 +} + +func (x *RegistrationRewardEligibility) GetDailyRemaining() int64 { + if x != nil { + return x.DailyRemaining + } + return 0 +} + +func (x *RegistrationRewardEligibility) GetRewardDay() string { + if x != nil { + return x.RewardDay + } + return "" +} + +func (x *RegistrationRewardEligibility) GetServerTimeMs() int64 { + if x != nil { + return x.ServerTimeMs + } + return 0 +} + +// GetRegistrationRewardEligibilityRequest 给 App 查询当前用户是否还有注册奖励资格。 +type GetRegistrationRewardEligibilityRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` +} + +func (x *GetRegistrationRewardEligibilityRequest) Reset() { + *x = GetRegistrationRewardEligibilityRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRegistrationRewardEligibilityRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRegistrationRewardEligibilityRequest) ProtoMessage() {} + +func (x *GetRegistrationRewardEligibilityRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[52] + 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 GetRegistrationRewardEligibilityRequest.ProtoReflect.Descriptor instead. +func (*GetRegistrationRewardEligibilityRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{52} +} + +func (x *GetRegistrationRewardEligibilityRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *GetRegistrationRewardEligibilityRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +type GetRegistrationRewardEligibilityResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Eligibility *RegistrationRewardEligibility `protobuf:"bytes,1,opt,name=eligibility,proto3" json:"eligibility,omitempty"` +} + +func (x *GetRegistrationRewardEligibilityResponse) Reset() { + *x = GetRegistrationRewardEligibilityResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRegistrationRewardEligibilityResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRegistrationRewardEligibilityResponse) ProtoMessage() {} + +func (x *GetRegistrationRewardEligibilityResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[53] + 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 GetRegistrationRewardEligibilityResponse.ProtoReflect.Descriptor instead. +func (*GetRegistrationRewardEligibilityResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{53} +} + +func (x *GetRegistrationRewardEligibilityResponse) GetEligibility() *RegistrationRewardEligibility { + if x != nil { + return x.Eligibility + } + return nil +} + +// IssueRegistrationRewardRequest 是 user-service 注册成功后调用的幂等发放命令。 +type IssueRegistrationRewardRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + CommandId string `protobuf:"bytes,3,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` +} + +func (x *IssueRegistrationRewardRequest) Reset() { + *x = IssueRegistrationRewardRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IssueRegistrationRewardRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IssueRegistrationRewardRequest) ProtoMessage() {} + +func (x *IssueRegistrationRewardRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[54] + 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 IssueRegistrationRewardRequest.ProtoReflect.Descriptor instead. +func (*IssueRegistrationRewardRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{54} +} + +func (x *IssueRegistrationRewardRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *IssueRegistrationRewardRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *IssueRegistrationRewardRequest) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +type IssueRegistrationRewardResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Claim *RegistrationRewardClaim `protobuf:"bytes,1,opt,name=claim,proto3" json:"claim,omitempty"` + Eligibility *RegistrationRewardEligibility `protobuf:"bytes,2,opt,name=eligibility,proto3" json:"eligibility,omitempty"` + Issued bool `protobuf:"varint,3,opt,name=issued,proto3" json:"issued,omitempty"` +} + +func (x *IssueRegistrationRewardResponse) Reset() { + *x = IssueRegistrationRewardResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IssueRegistrationRewardResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IssueRegistrationRewardResponse) ProtoMessage() {} + +func (x *IssueRegistrationRewardResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[55] + 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 IssueRegistrationRewardResponse.ProtoReflect.Descriptor instead. +func (*IssueRegistrationRewardResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{55} +} + +func (x *IssueRegistrationRewardResponse) GetClaim() *RegistrationRewardClaim { + if x != nil { + return x.Claim + } + return nil +} + +func (x *IssueRegistrationRewardResponse) GetEligibility() *RegistrationRewardEligibility { + if x != nil { + return x.Eligibility + } + return nil +} + +func (x *IssueRegistrationRewardResponse) GetIssued() bool { + if x != nil { + return x.Issued + } + return false +} + +// GetRegistrationRewardConfigRequest 返回后台注册奖励配置;未配置时服务端返回默认 disabled 配置。 +type GetRegistrationRewardConfigRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` +} + +func (x *GetRegistrationRewardConfigRequest) Reset() { + *x = GetRegistrationRewardConfigRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRegistrationRewardConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRegistrationRewardConfigRequest) ProtoMessage() {} + +func (x *GetRegistrationRewardConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[56] + 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 GetRegistrationRewardConfigRequest.ProtoReflect.Descriptor instead. +func (*GetRegistrationRewardConfigRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{56} +} + +func (x *GetRegistrationRewardConfigRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +type GetRegistrationRewardConfigResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *RegistrationRewardConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` +} + +func (x *GetRegistrationRewardConfigResponse) Reset() { + *x = GetRegistrationRewardConfigResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRegistrationRewardConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRegistrationRewardConfigResponse) ProtoMessage() {} + +func (x *GetRegistrationRewardConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[57] + 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 GetRegistrationRewardConfigResponse.ProtoReflect.Descriptor instead. +func (*GetRegistrationRewardConfigResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{57} +} + +func (x *GetRegistrationRewardConfigResponse) GetConfig() *RegistrationRewardConfig { + if x != nil { + return x.Config + } + return nil +} + +// UpdateRegistrationRewardConfigRequest 更新注册奖励开关、奖励内容和每日限制。 +type UpdateRegistrationRewardConfigRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + Enabled bool `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled,omitempty"` + RewardType string `protobuf:"bytes,3,opt,name=reward_type,json=rewardType,proto3" json:"reward_type,omitempty"` + CoinAmount int64 `protobuf:"varint,4,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` + ResourceGroupId int64 `protobuf:"varint,5,opt,name=resource_group_id,json=resourceGroupId,proto3" json:"resource_group_id,omitempty"` + DailyLimit int64 `protobuf:"varint,6,opt,name=daily_limit,json=dailyLimit,proto3" json:"daily_limit,omitempty"` + OperatorAdminId int64 `protobuf:"varint,7,opt,name=operator_admin_id,json=operatorAdminId,proto3" json:"operator_admin_id,omitempty"` +} + +func (x *UpdateRegistrationRewardConfigRequest) Reset() { + *x = UpdateRegistrationRewardConfigRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateRegistrationRewardConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRegistrationRewardConfigRequest) ProtoMessage() {} + +func (x *UpdateRegistrationRewardConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[58] + 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 UpdateRegistrationRewardConfigRequest.ProtoReflect.Descriptor instead. +func (*UpdateRegistrationRewardConfigRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{58} +} + +func (x *UpdateRegistrationRewardConfigRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *UpdateRegistrationRewardConfigRequest) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *UpdateRegistrationRewardConfigRequest) GetRewardType() string { + if x != nil { + return x.RewardType + } + return "" +} + +func (x *UpdateRegistrationRewardConfigRequest) GetCoinAmount() int64 { + if x != nil { + return x.CoinAmount + } + return 0 +} + +func (x *UpdateRegistrationRewardConfigRequest) GetResourceGroupId() int64 { + if x != nil { + return x.ResourceGroupId + } + return 0 +} + +func (x *UpdateRegistrationRewardConfigRequest) GetDailyLimit() int64 { + if x != nil { + return x.DailyLimit + } + return 0 +} + +func (x *UpdateRegistrationRewardConfigRequest) GetOperatorAdminId() int64 { + if x != nil { + return x.OperatorAdminId + } + return 0 +} + +type UpdateRegistrationRewardConfigResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *RegistrationRewardConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` +} + +func (x *UpdateRegistrationRewardConfigResponse) Reset() { + *x = UpdateRegistrationRewardConfigResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateRegistrationRewardConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRegistrationRewardConfigResponse) ProtoMessage() {} + +func (x *UpdateRegistrationRewardConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[59] + 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 UpdateRegistrationRewardConfigResponse.ProtoReflect.Descriptor instead. +func (*UpdateRegistrationRewardConfigResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{59} +} + +func (x *UpdateRegistrationRewardConfigResponse) GetConfig() *RegistrationRewardConfig { + if x != nil { + return x.Config + } + return nil +} + +// ListRegistrationRewardClaimsRequest 是后台领取记录分页筛选;keyword 由 admin-server 结合用户库扩展。 +type ListRegistrationRewardClaimsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Page int32 `protobuf:"varint,4,opt,name=page,proto3" json:"page,omitempty"` + PageSize int32 `protobuf:"varint,5,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` +} + +func (x *ListRegistrationRewardClaimsRequest) Reset() { + *x = ListRegistrationRewardClaimsRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListRegistrationRewardClaimsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListRegistrationRewardClaimsRequest) ProtoMessage() {} + +func (x *ListRegistrationRewardClaimsRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[60] + 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 ListRegistrationRewardClaimsRequest.ProtoReflect.Descriptor instead. +func (*ListRegistrationRewardClaimsRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{60} +} + +func (x *ListRegistrationRewardClaimsRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *ListRegistrationRewardClaimsRequest) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *ListRegistrationRewardClaimsRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *ListRegistrationRewardClaimsRequest) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *ListRegistrationRewardClaimsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +type ListRegistrationRewardClaimsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Claims []*RegistrationRewardClaim `protobuf:"bytes,1,rep,name=claims,proto3" json:"claims,omitempty"` + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` +} + +func (x *ListRegistrationRewardClaimsResponse) Reset() { + *x = ListRegistrationRewardClaimsResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListRegistrationRewardClaimsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListRegistrationRewardClaimsResponse) ProtoMessage() {} + +func (x *ListRegistrationRewardClaimsResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[61] + 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 ListRegistrationRewardClaimsResponse.ProtoReflect.Descriptor instead. +func (*ListRegistrationRewardClaimsResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{61} +} + +func (x *ListRegistrationRewardClaimsResponse) GetClaims() []*RegistrationRewardClaim { + if x != nil { + return x.Claims + } + return nil +} + +func (x *ListRegistrationRewardClaimsResponse) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + var File_proto_activity_v1_activity_proto protoreflect.FileDescriptor var file_proto_activity_v1_activity_proto_rawDesc = []byte{ @@ -4323,178 +5300,406 @@ var file_proto_activity_v1_activity_proto_rawDesc = []byte{ 0x35, 0x0a, 0x04, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x04, 0x74, 0x61, 0x73, 0x6b, 0x32, 0xe2, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, - 0x69, 0x74, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x0c, 0x50, 0x69, - 0x6e, 0x67, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x69, 0x6e, 0x67, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, - 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x41, 0x63, 0x74, 0x69, 0x76, - 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x11, 0x47, - 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x04, 0x74, 0x61, 0x73, 0x6b, 0x22, 0xd5, 0x02, 0x0a, 0x18, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 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, 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, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, + 0x65, 0x77, 0x61, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x69, + 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x61, 0x69, + 0x6c, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2d, 0x0a, 0x13, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xb0, + 0x04, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6c, + 0x61, 0x69, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, + 0x61, 0x69, 0x6d, 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, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x64, 0x61, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x44, 0x61, 0x79, 0x12, 0x1f, 0x0a, 0x0b, + 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, + 0x0b, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, + 0x0a, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 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, 0x12, 0x2a, 0x0a, 0x11, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x32, + 0x0a, 0x15, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, + 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x25, + 0x0a, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x6c, + 0x61, 0x69, 0x6d, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, + 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, + 0x73, 0x22, 0x8e, 0x03, 0x0a, 0x1d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x45, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x63, + 0x65, 0x69, 0x76, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 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, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x69, 0x6e, 0x5f, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, + 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x75, + 0x73, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, + 0x55, 0x73, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x72, 0x65, + 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x64, + 0x61, 0x69, 0x6c, 0x79, 0x52, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x64, 0x61, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x44, 0x61, 0x79, 0x12, 0x24, 0x0a, 0x0e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, + 0x4d, 0x73, 0x22, 0x76, 0x0a, 0x27, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x45, 0x6c, 0x69, 0x67, 0x69, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 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, 0x22, 0x7e, 0x0a, 0x28, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x45, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0b, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x45, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0b, 0x65, + 0x6c, 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x22, 0x8c, 0x01, 0x0a, 0x1e, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 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, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x22, 0xcf, 0x01, 0x0a, 0x1f, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, + 0x05, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x12, + 0x52, 0x0a, 0x0b, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x45, 0x6c, 0x69, 0x67, 0x69, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0b, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x22, 0x58, 0x0a, 0x22, 0x47, + 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x32, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x6a, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x22, 0xb0, 0x02, 0x0a, 0x25, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x04, 0x6d, + 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, + 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x69, 0x6c, 0x79, + 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x61, + 0x69, 0x6c, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x49, 0x64, 0x22, 0x6d, 0x0a, 0x26, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, + 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x22, 0xbb, 0x01, 0x0a, 0x23, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6c, + 0x61, 0x69, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x04, 0x6d, + 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, + 0x65, 0x22, 0x80, 0x01, 0x0a, 0x24, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6c, 0x61, 0x69, + 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x63, 0x6c, + 0x61, 0x69, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, + 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x52, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x32, 0xe2, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, + 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, + 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x11, 0x47, 0x65, 0x74, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2b, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb1, 0x06, 0x0a, 0x13, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x68, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x61, 0x62, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x61, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x61, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x11, 0x4c, + 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, - 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, + 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb1, 0x06, 0x0a, 0x13, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x68, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x54, 0x61, 0x62, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, - 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x61, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, - 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x54, 0x61, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, - 0x11, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, - 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, - 0x14, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x61, 0x64, 0x12, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, - 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, - 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x14, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, - 0x62, 0x6f, 0x78, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x64, 0x12, 0x2e, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x53, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x53, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x71, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x14, 0x4d, + 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x61, 0x64, 0x12, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x14, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x64, 0x12, 0x2e, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, + 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, - 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x71, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x62, 0x6f, - 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, + 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, + 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x71, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, - 0x61, 0x6e, 0x6f, 0x75, 0x74, 0x4a, 0x6f, 0x62, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x46, 0x61, 0x6e, 0x6f, 0x75, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, - 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, - 0x6e, 0x6f, 0x75, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, - 0x7d, 0x0a, 0x13, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x43, 0x72, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x66, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x46, 0x61, 0x6e, 0x6f, 0x75, 0x74, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, - 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, - 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc8, - 0x02, 0x0a, 0x0b, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, - 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, - 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0f, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x52, - 0x65, 0x77, 0x61, 0x72, 0x64, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, - 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, - 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, - 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x10, - 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, - 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x54, 0x61, 0x73, 0x6b, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8b, 0x05, 0x0a, 0x10, 0x42, 0x72, - 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7a, - 0x0a, 0x15, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, - 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x73, 0x75, - 0x72, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x73, - 0x75, 0x72, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x16, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, 0x61, 0x64, - 0x63, 0x61, 0x73, 0x74, 0x12, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, - 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, - 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x73, 0x68, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x16, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x47, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x30, 0x2e, + 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x6e, + 0x6f, 0x75, 0x74, 0x4a, 0x6f, 0x62, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x46, 0x61, 0x6e, 0x6f, 0x75, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, + 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x6e, 0x6f, + 0x75, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x7d, 0x0a, + 0x13, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x43, 0x72, 0x6f, 0x6e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x66, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x46, 0x61, 0x6e, 0x6f, 0x75, 0x74, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, + 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc8, 0x02, 0x0a, + 0x0b, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x0d, + 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x42, - 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x42, 0x72, 0x6f, 0x61, 0x64, - 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8c, 0x01, 0x0a, - 0x1b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, - 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x35, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, - 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, - 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x1b, 0x50, - 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4f, - 0x75, 0x74, 0x62, 0x6f, 0x78, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x68, 0x0a, 0x0f, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, + 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x10, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2a, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x36, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x72, 0x6f, 0x61, 0x64, - 0x63, 0x61, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x78, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x87, 0x01, 0x0a, 0x18, 0x52, 0x6f, 0x6f, 0x6d, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x6b, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, - 0x6f, 0x6f, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, - 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8b, 0x05, 0x0a, 0x10, 0x42, 0x72, 0x6f, 0x61, + 0x64, 0x63, 0x61, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7a, 0x0a, 0x15, + 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, + 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x73, 0x75, 0x72, + 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x16, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, + 0x73, 0x74, 0x12, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, - 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, - 0x52, 0x6f, 0x6f, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x32, 0x84, 0x03, 0x0a, 0x10, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x74, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, - 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x2e, + 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x77, 0x0a, 0x16, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x30, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x42, 0x72, 0x6f, + 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x14, - 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, - 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x54, - 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, - 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x54, - 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x54, 0x61, 0x73, - 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x31, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, - 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, - 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, - 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2e, 0x5a, 0x2c, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8c, 0x01, 0x0a, 0x1b, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, 0x61, 0x64, + 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x35, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x6f, 0x61, 0x64, + 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, + 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x1b, 0x50, 0x72, 0x6f, + 0x63, 0x65, 0x73, 0x73, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4f, 0x75, 0x74, + 0x62, 0x6f, 0x78, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, + 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, + 0x73, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x78, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x87, 0x01, 0x0a, 0x18, 0x52, 0x6f, 0x6f, 0x6d, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x6b, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6f, + 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, + 0x6f, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, + 0x84, 0x03, 0x0a, 0x10, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x74, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, + 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x14, 0x55, 0x70, + 0x73, 0x65, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x54, 0x61, 0x73, + 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x54, 0x61, 0x73, + 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x31, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xbc, 0x02, 0x0a, 0x19, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x9b, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x45, 0x6c, + 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x3a, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x45, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x45, + 0x6c, 0x69, 0x67, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x17, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x12, 0x31, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, + 0x76, 0x31, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x32, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, + 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xd9, 0x03, 0x0a, 0x1e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, + 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x8c, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x36, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x95, 0x01, 0x0a, 0x1e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, + 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x8f, 0x01, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, + 0x12, 0x36, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, + 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x2e, 0x5a, 0x2c, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x69, 0x74, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x76, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4509,58 +5714,71 @@ func file_proto_activity_v1_activity_proto_rawDescGZIP() []byte { return file_proto_activity_v1_activity_proto_rawDescData } -var file_proto_activity_v1_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 49) +var file_proto_activity_v1_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 62) var file_proto_activity_v1_activity_proto_goTypes = []any{ - (*RequestMeta)(nil), // 0: hyapp.activity.v1.RequestMeta - (*PingActivityRequest)(nil), // 1: hyapp.activity.v1.PingActivityRequest - (*PingActivityResponse)(nil), // 2: hyapp.activity.v1.PingActivityResponse - (*GetActivityStatusRequest)(nil), // 3: hyapp.activity.v1.GetActivityStatusRequest - (*GetActivityStatusResponse)(nil), // 4: hyapp.activity.v1.GetActivityStatusResponse - (*MessageTabSection)(nil), // 5: hyapp.activity.v1.MessageTabSection - (*ListMessageTabsRequest)(nil), // 6: hyapp.activity.v1.ListMessageTabsRequest - (*ListMessageTabsResponse)(nil), // 7: hyapp.activity.v1.ListMessageTabsResponse - (*InboxMessage)(nil), // 8: hyapp.activity.v1.InboxMessage - (*ListInboxMessagesRequest)(nil), // 9: hyapp.activity.v1.ListInboxMessagesRequest - (*ListInboxMessagesResponse)(nil), // 10: hyapp.activity.v1.ListInboxMessagesResponse - (*MarkInboxMessageReadRequest)(nil), // 11: hyapp.activity.v1.MarkInboxMessageReadRequest - (*MarkInboxMessageReadResponse)(nil), // 12: hyapp.activity.v1.MarkInboxMessageReadResponse - (*MarkInboxSectionReadRequest)(nil), // 13: hyapp.activity.v1.MarkInboxSectionReadRequest - (*MarkInboxSectionReadResponse)(nil), // 14: hyapp.activity.v1.MarkInboxSectionReadResponse - (*DeleteInboxMessageRequest)(nil), // 15: hyapp.activity.v1.DeleteInboxMessageRequest - (*DeleteInboxMessageResponse)(nil), // 16: hyapp.activity.v1.DeleteInboxMessageResponse - (*CreateInboxMessageRequest)(nil), // 17: hyapp.activity.v1.CreateInboxMessageRequest - (*CreateInboxMessageResponse)(nil), // 18: hyapp.activity.v1.CreateInboxMessageResponse - (*CreateFanoutJobRequest)(nil), // 19: hyapp.activity.v1.CreateFanoutJobRequest - (*CreateFanoutJobResponse)(nil), // 20: hyapp.activity.v1.CreateFanoutJobResponse - (*CronBatchRequest)(nil), // 21: hyapp.activity.v1.CronBatchRequest - (*CronBatchResponse)(nil), // 22: hyapp.activity.v1.CronBatchResponse - (*TaskItem)(nil), // 23: hyapp.activity.v1.TaskItem - (*TaskSection)(nil), // 24: hyapp.activity.v1.TaskSection - (*ListUserTasksRequest)(nil), // 25: hyapp.activity.v1.ListUserTasksRequest - (*ListUserTasksResponse)(nil), // 26: hyapp.activity.v1.ListUserTasksResponse - (*ClaimTaskRewardRequest)(nil), // 27: hyapp.activity.v1.ClaimTaskRewardRequest - (*ClaimTaskRewardResponse)(nil), // 28: hyapp.activity.v1.ClaimTaskRewardResponse - (*ConsumeTaskEventRequest)(nil), // 29: hyapp.activity.v1.ConsumeTaskEventRequest - (*ConsumeTaskEventResponse)(nil), // 30: hyapp.activity.v1.ConsumeTaskEventResponse - (*BroadcastJoinGroup)(nil), // 31: hyapp.activity.v1.BroadcastJoinGroup - (*EnsureBroadcastGroupsRequest)(nil), // 32: hyapp.activity.v1.EnsureBroadcastGroupsRequest - (*EnsureBroadcastGroupsResponse)(nil), // 33: hyapp.activity.v1.EnsureBroadcastGroupsResponse - (*PublishRegionBroadcastRequest)(nil), // 34: hyapp.activity.v1.PublishRegionBroadcastRequest - (*PublishGlobalBroadcastRequest)(nil), // 35: hyapp.activity.v1.PublishGlobalBroadcastRequest - (*PublishBroadcastResponse)(nil), // 36: hyapp.activity.v1.PublishBroadcastResponse - (*RemoveRegionBroadcastMemberRequest)(nil), // 37: hyapp.activity.v1.RemoveRegionBroadcastMemberRequest - (*RemoveRegionBroadcastMemberResponse)(nil), // 38: hyapp.activity.v1.RemoveRegionBroadcastMemberResponse - (*ProcessBroadcastOutboxBatchResponse)(nil), // 39: hyapp.activity.v1.ProcessBroadcastOutboxBatchResponse - (*ConsumeRoomEventRequest)(nil), // 40: hyapp.activity.v1.ConsumeRoomEventRequest - (*ConsumeRoomEventResponse)(nil), // 41: hyapp.activity.v1.ConsumeRoomEventResponse - (*TaskDefinition)(nil), // 42: hyapp.activity.v1.TaskDefinition - (*ListTaskDefinitionsRequest)(nil), // 43: hyapp.activity.v1.ListTaskDefinitionsRequest - (*ListTaskDefinitionsResponse)(nil), // 44: hyapp.activity.v1.ListTaskDefinitionsResponse - (*UpsertTaskDefinitionRequest)(nil), // 45: hyapp.activity.v1.UpsertTaskDefinitionRequest - (*UpsertTaskDefinitionResponse)(nil), // 46: hyapp.activity.v1.UpsertTaskDefinitionResponse - (*SetTaskDefinitionStatusRequest)(nil), // 47: hyapp.activity.v1.SetTaskDefinitionStatusRequest - (*SetTaskDefinitionStatusResponse)(nil), // 48: hyapp.activity.v1.SetTaskDefinitionStatusResponse - (*v1.EventEnvelope)(nil), // 49: hyapp.events.room.v1.EventEnvelope + (*RequestMeta)(nil), // 0: hyapp.activity.v1.RequestMeta + (*PingActivityRequest)(nil), // 1: hyapp.activity.v1.PingActivityRequest + (*PingActivityResponse)(nil), // 2: hyapp.activity.v1.PingActivityResponse + (*GetActivityStatusRequest)(nil), // 3: hyapp.activity.v1.GetActivityStatusRequest + (*GetActivityStatusResponse)(nil), // 4: hyapp.activity.v1.GetActivityStatusResponse + (*MessageTabSection)(nil), // 5: hyapp.activity.v1.MessageTabSection + (*ListMessageTabsRequest)(nil), // 6: hyapp.activity.v1.ListMessageTabsRequest + (*ListMessageTabsResponse)(nil), // 7: hyapp.activity.v1.ListMessageTabsResponse + (*InboxMessage)(nil), // 8: hyapp.activity.v1.InboxMessage + (*ListInboxMessagesRequest)(nil), // 9: hyapp.activity.v1.ListInboxMessagesRequest + (*ListInboxMessagesResponse)(nil), // 10: hyapp.activity.v1.ListInboxMessagesResponse + (*MarkInboxMessageReadRequest)(nil), // 11: hyapp.activity.v1.MarkInboxMessageReadRequest + (*MarkInboxMessageReadResponse)(nil), // 12: hyapp.activity.v1.MarkInboxMessageReadResponse + (*MarkInboxSectionReadRequest)(nil), // 13: hyapp.activity.v1.MarkInboxSectionReadRequest + (*MarkInboxSectionReadResponse)(nil), // 14: hyapp.activity.v1.MarkInboxSectionReadResponse + (*DeleteInboxMessageRequest)(nil), // 15: hyapp.activity.v1.DeleteInboxMessageRequest + (*DeleteInboxMessageResponse)(nil), // 16: hyapp.activity.v1.DeleteInboxMessageResponse + (*CreateInboxMessageRequest)(nil), // 17: hyapp.activity.v1.CreateInboxMessageRequest + (*CreateInboxMessageResponse)(nil), // 18: hyapp.activity.v1.CreateInboxMessageResponse + (*CreateFanoutJobRequest)(nil), // 19: hyapp.activity.v1.CreateFanoutJobRequest + (*CreateFanoutJobResponse)(nil), // 20: hyapp.activity.v1.CreateFanoutJobResponse + (*CronBatchRequest)(nil), // 21: hyapp.activity.v1.CronBatchRequest + (*CronBatchResponse)(nil), // 22: hyapp.activity.v1.CronBatchResponse + (*TaskItem)(nil), // 23: hyapp.activity.v1.TaskItem + (*TaskSection)(nil), // 24: hyapp.activity.v1.TaskSection + (*ListUserTasksRequest)(nil), // 25: hyapp.activity.v1.ListUserTasksRequest + (*ListUserTasksResponse)(nil), // 26: hyapp.activity.v1.ListUserTasksResponse + (*ClaimTaskRewardRequest)(nil), // 27: hyapp.activity.v1.ClaimTaskRewardRequest + (*ClaimTaskRewardResponse)(nil), // 28: hyapp.activity.v1.ClaimTaskRewardResponse + (*ConsumeTaskEventRequest)(nil), // 29: hyapp.activity.v1.ConsumeTaskEventRequest + (*ConsumeTaskEventResponse)(nil), // 30: hyapp.activity.v1.ConsumeTaskEventResponse + (*BroadcastJoinGroup)(nil), // 31: hyapp.activity.v1.BroadcastJoinGroup + (*EnsureBroadcastGroupsRequest)(nil), // 32: hyapp.activity.v1.EnsureBroadcastGroupsRequest + (*EnsureBroadcastGroupsResponse)(nil), // 33: hyapp.activity.v1.EnsureBroadcastGroupsResponse + (*PublishRegionBroadcastRequest)(nil), // 34: hyapp.activity.v1.PublishRegionBroadcastRequest + (*PublishGlobalBroadcastRequest)(nil), // 35: hyapp.activity.v1.PublishGlobalBroadcastRequest + (*PublishBroadcastResponse)(nil), // 36: hyapp.activity.v1.PublishBroadcastResponse + (*RemoveRegionBroadcastMemberRequest)(nil), // 37: hyapp.activity.v1.RemoveRegionBroadcastMemberRequest + (*RemoveRegionBroadcastMemberResponse)(nil), // 38: hyapp.activity.v1.RemoveRegionBroadcastMemberResponse + (*ProcessBroadcastOutboxBatchResponse)(nil), // 39: hyapp.activity.v1.ProcessBroadcastOutboxBatchResponse + (*ConsumeRoomEventRequest)(nil), // 40: hyapp.activity.v1.ConsumeRoomEventRequest + (*ConsumeRoomEventResponse)(nil), // 41: hyapp.activity.v1.ConsumeRoomEventResponse + (*TaskDefinition)(nil), // 42: hyapp.activity.v1.TaskDefinition + (*ListTaskDefinitionsRequest)(nil), // 43: hyapp.activity.v1.ListTaskDefinitionsRequest + (*ListTaskDefinitionsResponse)(nil), // 44: hyapp.activity.v1.ListTaskDefinitionsResponse + (*UpsertTaskDefinitionRequest)(nil), // 45: hyapp.activity.v1.UpsertTaskDefinitionRequest + (*UpsertTaskDefinitionResponse)(nil), // 46: hyapp.activity.v1.UpsertTaskDefinitionResponse + (*SetTaskDefinitionStatusRequest)(nil), // 47: hyapp.activity.v1.SetTaskDefinitionStatusRequest + (*SetTaskDefinitionStatusResponse)(nil), // 48: hyapp.activity.v1.SetTaskDefinitionStatusResponse + (*RegistrationRewardConfig)(nil), // 49: hyapp.activity.v1.RegistrationRewardConfig + (*RegistrationRewardClaim)(nil), // 50: hyapp.activity.v1.RegistrationRewardClaim + (*RegistrationRewardEligibility)(nil), // 51: hyapp.activity.v1.RegistrationRewardEligibility + (*GetRegistrationRewardEligibilityRequest)(nil), // 52: hyapp.activity.v1.GetRegistrationRewardEligibilityRequest + (*GetRegistrationRewardEligibilityResponse)(nil), // 53: hyapp.activity.v1.GetRegistrationRewardEligibilityResponse + (*IssueRegistrationRewardRequest)(nil), // 54: hyapp.activity.v1.IssueRegistrationRewardRequest + (*IssueRegistrationRewardResponse)(nil), // 55: hyapp.activity.v1.IssueRegistrationRewardResponse + (*GetRegistrationRewardConfigRequest)(nil), // 56: hyapp.activity.v1.GetRegistrationRewardConfigRequest + (*GetRegistrationRewardConfigResponse)(nil), // 57: hyapp.activity.v1.GetRegistrationRewardConfigResponse + (*UpdateRegistrationRewardConfigRequest)(nil), // 58: hyapp.activity.v1.UpdateRegistrationRewardConfigRequest + (*UpdateRegistrationRewardConfigResponse)(nil), // 59: hyapp.activity.v1.UpdateRegistrationRewardConfigResponse + (*ListRegistrationRewardClaimsRequest)(nil), // 60: hyapp.activity.v1.ListRegistrationRewardClaimsRequest + (*ListRegistrationRewardClaimsResponse)(nil), // 61: hyapp.activity.v1.ListRegistrationRewardClaimsResponse + (*v1.EventEnvelope)(nil), // 62: hyapp.events.room.v1.EventEnvelope } var file_proto_activity_v1_activity_proto_depIdxs = []int32{ 0, // 0: hyapp.activity.v1.PingActivityRequest.meta:type_name -> hyapp.activity.v1.RequestMeta @@ -4585,62 +5803,83 @@ var file_proto_activity_v1_activity_proto_depIdxs = []int32{ 0, // 19: hyapp.activity.v1.PublishGlobalBroadcastRequest.meta:type_name -> hyapp.activity.v1.RequestMeta 0, // 20: hyapp.activity.v1.RemoveRegionBroadcastMemberRequest.meta:type_name -> hyapp.activity.v1.RequestMeta 0, // 21: hyapp.activity.v1.ConsumeRoomEventRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 49, // 22: hyapp.activity.v1.ConsumeRoomEventRequest.envelope:type_name -> hyapp.events.room.v1.EventEnvelope + 62, // 22: hyapp.activity.v1.ConsumeRoomEventRequest.envelope:type_name -> hyapp.events.room.v1.EventEnvelope 0, // 23: hyapp.activity.v1.ListTaskDefinitionsRequest.meta:type_name -> hyapp.activity.v1.RequestMeta 42, // 24: hyapp.activity.v1.ListTaskDefinitionsResponse.tasks:type_name -> hyapp.activity.v1.TaskDefinition 0, // 25: hyapp.activity.v1.UpsertTaskDefinitionRequest.meta:type_name -> hyapp.activity.v1.RequestMeta 42, // 26: hyapp.activity.v1.UpsertTaskDefinitionResponse.task:type_name -> hyapp.activity.v1.TaskDefinition 0, // 27: hyapp.activity.v1.SetTaskDefinitionStatusRequest.meta:type_name -> hyapp.activity.v1.RequestMeta 42, // 28: hyapp.activity.v1.SetTaskDefinitionStatusResponse.task:type_name -> hyapp.activity.v1.TaskDefinition - 1, // 29: hyapp.activity.v1.ActivityService.PingActivity:input_type -> hyapp.activity.v1.PingActivityRequest - 3, // 30: hyapp.activity.v1.ActivityService.GetActivityStatus:input_type -> hyapp.activity.v1.GetActivityStatusRequest - 6, // 31: hyapp.activity.v1.MessageInboxService.ListMessageTabs:input_type -> hyapp.activity.v1.ListMessageTabsRequest - 9, // 32: hyapp.activity.v1.MessageInboxService.ListInboxMessages:input_type -> hyapp.activity.v1.ListInboxMessagesRequest - 11, // 33: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:input_type -> hyapp.activity.v1.MarkInboxMessageReadRequest - 13, // 34: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:input_type -> hyapp.activity.v1.MarkInboxSectionReadRequest - 15, // 35: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:input_type -> hyapp.activity.v1.DeleteInboxMessageRequest - 17, // 36: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:input_type -> hyapp.activity.v1.CreateInboxMessageRequest - 19, // 37: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:input_type -> hyapp.activity.v1.CreateFanoutJobRequest - 21, // 38: hyapp.activity.v1.ActivityCronService.ProcessMessageFanoutBatch:input_type -> hyapp.activity.v1.CronBatchRequest - 25, // 39: hyapp.activity.v1.TaskService.ListUserTasks:input_type -> hyapp.activity.v1.ListUserTasksRequest - 27, // 40: hyapp.activity.v1.TaskService.ClaimTaskReward:input_type -> hyapp.activity.v1.ClaimTaskRewardRequest - 29, // 41: hyapp.activity.v1.TaskService.ConsumeTaskEvent:input_type -> hyapp.activity.v1.ConsumeTaskEventRequest - 32, // 42: hyapp.activity.v1.BroadcastService.EnsureBroadcastGroups:input_type -> hyapp.activity.v1.EnsureBroadcastGroupsRequest - 34, // 43: hyapp.activity.v1.BroadcastService.PublishRegionBroadcast:input_type -> hyapp.activity.v1.PublishRegionBroadcastRequest - 35, // 44: hyapp.activity.v1.BroadcastService.PublishGlobalBroadcast:input_type -> hyapp.activity.v1.PublishGlobalBroadcastRequest - 37, // 45: hyapp.activity.v1.BroadcastService.RemoveRegionBroadcastMember:input_type -> hyapp.activity.v1.RemoveRegionBroadcastMemberRequest - 21, // 46: hyapp.activity.v1.BroadcastService.ProcessBroadcastOutboxBatch:input_type -> hyapp.activity.v1.CronBatchRequest - 40, // 47: hyapp.activity.v1.RoomEventConsumerService.ConsumeRoomEvent:input_type -> hyapp.activity.v1.ConsumeRoomEventRequest - 43, // 48: hyapp.activity.v1.AdminTaskService.ListTaskDefinitions:input_type -> hyapp.activity.v1.ListTaskDefinitionsRequest - 45, // 49: hyapp.activity.v1.AdminTaskService.UpsertTaskDefinition:input_type -> hyapp.activity.v1.UpsertTaskDefinitionRequest - 47, // 50: hyapp.activity.v1.AdminTaskService.SetTaskDefinitionStatus:input_type -> hyapp.activity.v1.SetTaskDefinitionStatusRequest - 2, // 51: hyapp.activity.v1.ActivityService.PingActivity:output_type -> hyapp.activity.v1.PingActivityResponse - 4, // 52: hyapp.activity.v1.ActivityService.GetActivityStatus:output_type -> hyapp.activity.v1.GetActivityStatusResponse - 7, // 53: hyapp.activity.v1.MessageInboxService.ListMessageTabs:output_type -> hyapp.activity.v1.ListMessageTabsResponse - 10, // 54: hyapp.activity.v1.MessageInboxService.ListInboxMessages:output_type -> hyapp.activity.v1.ListInboxMessagesResponse - 12, // 55: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:output_type -> hyapp.activity.v1.MarkInboxMessageReadResponse - 14, // 56: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:output_type -> hyapp.activity.v1.MarkInboxSectionReadResponse - 16, // 57: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:output_type -> hyapp.activity.v1.DeleteInboxMessageResponse - 18, // 58: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:output_type -> hyapp.activity.v1.CreateInboxMessageResponse - 20, // 59: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:output_type -> hyapp.activity.v1.CreateFanoutJobResponse - 22, // 60: hyapp.activity.v1.ActivityCronService.ProcessMessageFanoutBatch:output_type -> hyapp.activity.v1.CronBatchResponse - 26, // 61: hyapp.activity.v1.TaskService.ListUserTasks:output_type -> hyapp.activity.v1.ListUserTasksResponse - 28, // 62: hyapp.activity.v1.TaskService.ClaimTaskReward:output_type -> hyapp.activity.v1.ClaimTaskRewardResponse - 30, // 63: hyapp.activity.v1.TaskService.ConsumeTaskEvent:output_type -> hyapp.activity.v1.ConsumeTaskEventResponse - 33, // 64: hyapp.activity.v1.BroadcastService.EnsureBroadcastGroups:output_type -> hyapp.activity.v1.EnsureBroadcastGroupsResponse - 36, // 65: hyapp.activity.v1.BroadcastService.PublishRegionBroadcast:output_type -> hyapp.activity.v1.PublishBroadcastResponse - 36, // 66: hyapp.activity.v1.BroadcastService.PublishGlobalBroadcast:output_type -> hyapp.activity.v1.PublishBroadcastResponse - 38, // 67: hyapp.activity.v1.BroadcastService.RemoveRegionBroadcastMember:output_type -> hyapp.activity.v1.RemoveRegionBroadcastMemberResponse - 39, // 68: hyapp.activity.v1.BroadcastService.ProcessBroadcastOutboxBatch:output_type -> hyapp.activity.v1.ProcessBroadcastOutboxBatchResponse - 41, // 69: hyapp.activity.v1.RoomEventConsumerService.ConsumeRoomEvent:output_type -> hyapp.activity.v1.ConsumeRoomEventResponse - 44, // 70: hyapp.activity.v1.AdminTaskService.ListTaskDefinitions:output_type -> hyapp.activity.v1.ListTaskDefinitionsResponse - 46, // 71: hyapp.activity.v1.AdminTaskService.UpsertTaskDefinition:output_type -> hyapp.activity.v1.UpsertTaskDefinitionResponse - 48, // 72: hyapp.activity.v1.AdminTaskService.SetTaskDefinitionStatus:output_type -> hyapp.activity.v1.SetTaskDefinitionStatusResponse - 51, // [51:73] is the sub-list for method output_type - 29, // [29:51] is the sub-list for method input_type - 29, // [29:29] is the sub-list for extension type_name - 29, // [29:29] is the sub-list for extension extendee - 0, // [0:29] is the sub-list for field type_name + 0, // 29: hyapp.activity.v1.GetRegistrationRewardEligibilityRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 51, // 30: hyapp.activity.v1.GetRegistrationRewardEligibilityResponse.eligibility:type_name -> hyapp.activity.v1.RegistrationRewardEligibility + 0, // 31: hyapp.activity.v1.IssueRegistrationRewardRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 50, // 32: hyapp.activity.v1.IssueRegistrationRewardResponse.claim:type_name -> hyapp.activity.v1.RegistrationRewardClaim + 51, // 33: hyapp.activity.v1.IssueRegistrationRewardResponse.eligibility:type_name -> hyapp.activity.v1.RegistrationRewardEligibility + 0, // 34: hyapp.activity.v1.GetRegistrationRewardConfigRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 49, // 35: hyapp.activity.v1.GetRegistrationRewardConfigResponse.config:type_name -> hyapp.activity.v1.RegistrationRewardConfig + 0, // 36: hyapp.activity.v1.UpdateRegistrationRewardConfigRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 49, // 37: hyapp.activity.v1.UpdateRegistrationRewardConfigResponse.config:type_name -> hyapp.activity.v1.RegistrationRewardConfig + 0, // 38: hyapp.activity.v1.ListRegistrationRewardClaimsRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 50, // 39: hyapp.activity.v1.ListRegistrationRewardClaimsResponse.claims:type_name -> hyapp.activity.v1.RegistrationRewardClaim + 1, // 40: hyapp.activity.v1.ActivityService.PingActivity:input_type -> hyapp.activity.v1.PingActivityRequest + 3, // 41: hyapp.activity.v1.ActivityService.GetActivityStatus:input_type -> hyapp.activity.v1.GetActivityStatusRequest + 6, // 42: hyapp.activity.v1.MessageInboxService.ListMessageTabs:input_type -> hyapp.activity.v1.ListMessageTabsRequest + 9, // 43: hyapp.activity.v1.MessageInboxService.ListInboxMessages:input_type -> hyapp.activity.v1.ListInboxMessagesRequest + 11, // 44: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:input_type -> hyapp.activity.v1.MarkInboxMessageReadRequest + 13, // 45: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:input_type -> hyapp.activity.v1.MarkInboxSectionReadRequest + 15, // 46: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:input_type -> hyapp.activity.v1.DeleteInboxMessageRequest + 17, // 47: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:input_type -> hyapp.activity.v1.CreateInboxMessageRequest + 19, // 48: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:input_type -> hyapp.activity.v1.CreateFanoutJobRequest + 21, // 49: hyapp.activity.v1.ActivityCronService.ProcessMessageFanoutBatch:input_type -> hyapp.activity.v1.CronBatchRequest + 25, // 50: hyapp.activity.v1.TaskService.ListUserTasks:input_type -> hyapp.activity.v1.ListUserTasksRequest + 27, // 51: hyapp.activity.v1.TaskService.ClaimTaskReward:input_type -> hyapp.activity.v1.ClaimTaskRewardRequest + 29, // 52: hyapp.activity.v1.TaskService.ConsumeTaskEvent:input_type -> hyapp.activity.v1.ConsumeTaskEventRequest + 32, // 53: hyapp.activity.v1.BroadcastService.EnsureBroadcastGroups:input_type -> hyapp.activity.v1.EnsureBroadcastGroupsRequest + 34, // 54: hyapp.activity.v1.BroadcastService.PublishRegionBroadcast:input_type -> hyapp.activity.v1.PublishRegionBroadcastRequest + 35, // 55: hyapp.activity.v1.BroadcastService.PublishGlobalBroadcast:input_type -> hyapp.activity.v1.PublishGlobalBroadcastRequest + 37, // 56: hyapp.activity.v1.BroadcastService.RemoveRegionBroadcastMember:input_type -> hyapp.activity.v1.RemoveRegionBroadcastMemberRequest + 21, // 57: hyapp.activity.v1.BroadcastService.ProcessBroadcastOutboxBatch:input_type -> hyapp.activity.v1.CronBatchRequest + 40, // 58: hyapp.activity.v1.RoomEventConsumerService.ConsumeRoomEvent:input_type -> hyapp.activity.v1.ConsumeRoomEventRequest + 43, // 59: hyapp.activity.v1.AdminTaskService.ListTaskDefinitions:input_type -> hyapp.activity.v1.ListTaskDefinitionsRequest + 45, // 60: hyapp.activity.v1.AdminTaskService.UpsertTaskDefinition:input_type -> hyapp.activity.v1.UpsertTaskDefinitionRequest + 47, // 61: hyapp.activity.v1.AdminTaskService.SetTaskDefinitionStatus:input_type -> hyapp.activity.v1.SetTaskDefinitionStatusRequest + 52, // 62: hyapp.activity.v1.RegistrationRewardService.GetRegistrationRewardEligibility:input_type -> hyapp.activity.v1.GetRegistrationRewardEligibilityRequest + 54, // 63: hyapp.activity.v1.RegistrationRewardService.IssueRegistrationReward:input_type -> hyapp.activity.v1.IssueRegistrationRewardRequest + 56, // 64: hyapp.activity.v1.AdminRegistrationRewardService.GetRegistrationRewardConfig:input_type -> hyapp.activity.v1.GetRegistrationRewardConfigRequest + 58, // 65: hyapp.activity.v1.AdminRegistrationRewardService.UpdateRegistrationRewardConfig:input_type -> hyapp.activity.v1.UpdateRegistrationRewardConfigRequest + 60, // 66: hyapp.activity.v1.AdminRegistrationRewardService.ListRegistrationRewardClaims:input_type -> hyapp.activity.v1.ListRegistrationRewardClaimsRequest + 2, // 67: hyapp.activity.v1.ActivityService.PingActivity:output_type -> hyapp.activity.v1.PingActivityResponse + 4, // 68: hyapp.activity.v1.ActivityService.GetActivityStatus:output_type -> hyapp.activity.v1.GetActivityStatusResponse + 7, // 69: hyapp.activity.v1.MessageInboxService.ListMessageTabs:output_type -> hyapp.activity.v1.ListMessageTabsResponse + 10, // 70: hyapp.activity.v1.MessageInboxService.ListInboxMessages:output_type -> hyapp.activity.v1.ListInboxMessagesResponse + 12, // 71: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:output_type -> hyapp.activity.v1.MarkInboxMessageReadResponse + 14, // 72: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:output_type -> hyapp.activity.v1.MarkInboxSectionReadResponse + 16, // 73: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:output_type -> hyapp.activity.v1.DeleteInboxMessageResponse + 18, // 74: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:output_type -> hyapp.activity.v1.CreateInboxMessageResponse + 20, // 75: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:output_type -> hyapp.activity.v1.CreateFanoutJobResponse + 22, // 76: hyapp.activity.v1.ActivityCronService.ProcessMessageFanoutBatch:output_type -> hyapp.activity.v1.CronBatchResponse + 26, // 77: hyapp.activity.v1.TaskService.ListUserTasks:output_type -> hyapp.activity.v1.ListUserTasksResponse + 28, // 78: hyapp.activity.v1.TaskService.ClaimTaskReward:output_type -> hyapp.activity.v1.ClaimTaskRewardResponse + 30, // 79: hyapp.activity.v1.TaskService.ConsumeTaskEvent:output_type -> hyapp.activity.v1.ConsumeTaskEventResponse + 33, // 80: hyapp.activity.v1.BroadcastService.EnsureBroadcastGroups:output_type -> hyapp.activity.v1.EnsureBroadcastGroupsResponse + 36, // 81: hyapp.activity.v1.BroadcastService.PublishRegionBroadcast:output_type -> hyapp.activity.v1.PublishBroadcastResponse + 36, // 82: hyapp.activity.v1.BroadcastService.PublishGlobalBroadcast:output_type -> hyapp.activity.v1.PublishBroadcastResponse + 38, // 83: hyapp.activity.v1.BroadcastService.RemoveRegionBroadcastMember:output_type -> hyapp.activity.v1.RemoveRegionBroadcastMemberResponse + 39, // 84: hyapp.activity.v1.BroadcastService.ProcessBroadcastOutboxBatch:output_type -> hyapp.activity.v1.ProcessBroadcastOutboxBatchResponse + 41, // 85: hyapp.activity.v1.RoomEventConsumerService.ConsumeRoomEvent:output_type -> hyapp.activity.v1.ConsumeRoomEventResponse + 44, // 86: hyapp.activity.v1.AdminTaskService.ListTaskDefinitions:output_type -> hyapp.activity.v1.ListTaskDefinitionsResponse + 46, // 87: hyapp.activity.v1.AdminTaskService.UpsertTaskDefinition:output_type -> hyapp.activity.v1.UpsertTaskDefinitionResponse + 48, // 88: hyapp.activity.v1.AdminTaskService.SetTaskDefinitionStatus:output_type -> hyapp.activity.v1.SetTaskDefinitionStatusResponse + 53, // 89: hyapp.activity.v1.RegistrationRewardService.GetRegistrationRewardEligibility:output_type -> hyapp.activity.v1.GetRegistrationRewardEligibilityResponse + 55, // 90: hyapp.activity.v1.RegistrationRewardService.IssueRegistrationReward:output_type -> hyapp.activity.v1.IssueRegistrationRewardResponse + 57, // 91: hyapp.activity.v1.AdminRegistrationRewardService.GetRegistrationRewardConfig:output_type -> hyapp.activity.v1.GetRegistrationRewardConfigResponse + 59, // 92: hyapp.activity.v1.AdminRegistrationRewardService.UpdateRegistrationRewardConfig:output_type -> hyapp.activity.v1.UpdateRegistrationRewardConfigResponse + 61, // 93: hyapp.activity.v1.AdminRegistrationRewardService.ListRegistrationRewardClaims:output_type -> hyapp.activity.v1.ListRegistrationRewardClaimsResponse + 67, // [67:94] is the sub-list for method output_type + 40, // [40:67] is the sub-list for method input_type + 40, // [40:40] is the sub-list for extension type_name + 40, // [40:40] is the sub-list for extension extendee + 0, // [0:40] is the sub-list for field type_name } func init() { file_proto_activity_v1_activity_proto_init() } @@ -4654,9 +5893,9 @@ func file_proto_activity_v1_activity_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_activity_v1_activity_proto_rawDesc, NumEnums: 0, - NumMessages: 49, + NumMessages: 62, NumExtensions: 0, - NumServices: 7, + NumServices: 9, }, GoTypes: file_proto_activity_v1_activity_proto_goTypes, DependencyIndexes: file_proto_activity_v1_activity_proto_depIdxs, diff --git a/api/proto/activity/v1/activity.proto b/api/proto/activity/v1/activity.proto index 150668fc..4b7054d3 100644 --- a/api/proto/activity/v1/activity.proto +++ b/api/proto/activity/v1/activity.proto @@ -423,6 +423,114 @@ message SetTaskDefinitionStatusResponse { TaskDefinition task = 1; } +// RegistrationRewardConfig 是注册奖励的当前配置;enabled=false 时保留配置但不自动发放。 +message RegistrationRewardConfig { + string app_code = 1; + bool enabled = 2; + string reward_type = 3; + int64 coin_amount = 4; + int64 resource_group_id = 5; + int64 daily_limit = 6; + int64 updated_by_admin_id = 7; + int64 created_at_ms = 8; + int64 updated_at_ms = 9; +} + +// RegistrationRewardClaim 是每个用户注册奖励的领取事实;user_id 唯一保证“没有领过”。 +message RegistrationRewardClaim { + string claim_id = 1; + string command_id = 2; + int64 user_id = 3; + string reward_day = 4; + string reward_type = 5; + int64 coin_amount = 6; + int64 resource_group_id = 7; + string status = 8; + string wallet_command_id = 9; + string wallet_transaction_id = 10; + string resource_grant_id = 11; + string failure_reason = 12; + int64 claimed_at_ms = 13; + int64 created_at_ms = 14; + int64 updated_at_ms = 15; +} + +// RegistrationRewardEligibility 返回 App 可直接展示的资格判断;每日份数按 UTC reward_day 统计。 +message RegistrationRewardEligibility { + bool can_receive = 1; + string reason = 2; + bool enabled = 3; + string reward_type = 4; + int64 coin_amount = 5; + int64 resource_group_id = 6; + int64 daily_limit = 7; + int64 daily_used = 8; + int64 daily_remaining = 9; + string reward_day = 10; + int64 server_time_ms = 11; +} + +// GetRegistrationRewardEligibilityRequest 给 App 查询当前用户是否还有注册奖励资格。 +message GetRegistrationRewardEligibilityRequest { + RequestMeta meta = 1; + int64 user_id = 2; +} + +message GetRegistrationRewardEligibilityResponse { + RegistrationRewardEligibility eligibility = 1; +} + +// IssueRegistrationRewardRequest 是 user-service 注册成功后调用的幂等发放命令。 +message IssueRegistrationRewardRequest { + RequestMeta meta = 1; + int64 user_id = 2; + string command_id = 3; +} + +message IssueRegistrationRewardResponse { + RegistrationRewardClaim claim = 1; + RegistrationRewardEligibility eligibility = 2; + bool issued = 3; +} + +// GetRegistrationRewardConfigRequest 返回后台注册奖励配置;未配置时服务端返回默认 disabled 配置。 +message GetRegistrationRewardConfigRequest { + RequestMeta meta = 1; +} + +message GetRegistrationRewardConfigResponse { + RegistrationRewardConfig config = 1; +} + +// UpdateRegistrationRewardConfigRequest 更新注册奖励开关、奖励内容和每日限制。 +message UpdateRegistrationRewardConfigRequest { + RequestMeta meta = 1; + bool enabled = 2; + string reward_type = 3; + int64 coin_amount = 4; + int64 resource_group_id = 5; + int64 daily_limit = 6; + int64 operator_admin_id = 7; +} + +message UpdateRegistrationRewardConfigResponse { + RegistrationRewardConfig config = 1; +} + +// ListRegistrationRewardClaimsRequest 是后台领取记录分页筛选;keyword 由 admin-server 结合用户库扩展。 +message ListRegistrationRewardClaimsRequest { + RequestMeta meta = 1; + string status = 2; + int64 user_id = 3; + int32 page = 4; + int32 page_size = 5; +} + +message ListRegistrationRewardClaimsResponse { + repeated RegistrationRewardClaim claims = 1; + int64 total = 2; +} + // ActivityService 只暴露同步查询,不把事件消费伪装成 RPC。 service ActivityService { rpc PingActivity(PingActivityRequest) returns (PingActivityResponse); @@ -472,3 +580,16 @@ service AdminTaskService { rpc UpsertTaskDefinition(UpsertTaskDefinitionRequest) returns (UpsertTaskDefinitionResponse); rpc SetTaskDefinitionStatus(SetTaskDefinitionStatusRequest) returns (SetTaskDefinitionStatusResponse); } + +// RegistrationRewardService 拥有 App 查询和注册完成发放入口。 +service RegistrationRewardService { + rpc GetRegistrationRewardEligibility(GetRegistrationRewardEligibilityRequest) returns (GetRegistrationRewardEligibilityResponse); + rpc IssueRegistrationReward(IssueRegistrationRewardRequest) returns (IssueRegistrationRewardResponse); +} + +// AdminRegistrationRewardService 是后台活动管理访问注册奖励配置和领取记录的唯一入口。 +service AdminRegistrationRewardService { + rpc GetRegistrationRewardConfig(GetRegistrationRewardConfigRequest) returns (GetRegistrationRewardConfigResponse); + rpc UpdateRegistrationRewardConfig(UpdateRegistrationRewardConfigRequest) returns (UpdateRegistrationRewardConfigResponse); + rpc ListRegistrationRewardClaims(ListRegistrationRewardClaimsRequest) returns (ListRegistrationRewardClaimsResponse); +} diff --git a/api/proto/activity/v1/activity_grpc.pb.go b/api/proto/activity/v1/activity_grpc.pb.go index dd9868a8..0fd0022a 100644 --- a/api/proto/activity/v1/activity_grpc.pb.go +++ b/api/proto/activity/v1/activity_grpc.pb.go @@ -1330,3 +1330,331 @@ var AdminTaskService_ServiceDesc = grpc.ServiceDesc{ Streams: []grpc.StreamDesc{}, Metadata: "proto/activity/v1/activity.proto", } + +const ( + RegistrationRewardService_GetRegistrationRewardEligibility_FullMethodName = "/hyapp.activity.v1.RegistrationRewardService/GetRegistrationRewardEligibility" + RegistrationRewardService_IssueRegistrationReward_FullMethodName = "/hyapp.activity.v1.RegistrationRewardService/IssueRegistrationReward" +) + +// RegistrationRewardServiceClient is the client API for RegistrationRewardService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// RegistrationRewardService 拥有 App 查询和注册完成发放入口。 +type RegistrationRewardServiceClient interface { + GetRegistrationRewardEligibility(ctx context.Context, in *GetRegistrationRewardEligibilityRequest, opts ...grpc.CallOption) (*GetRegistrationRewardEligibilityResponse, error) + IssueRegistrationReward(ctx context.Context, in *IssueRegistrationRewardRequest, opts ...grpc.CallOption) (*IssueRegistrationRewardResponse, error) +} + +type registrationRewardServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewRegistrationRewardServiceClient(cc grpc.ClientConnInterface) RegistrationRewardServiceClient { + return ®istrationRewardServiceClient{cc} +} + +func (c *registrationRewardServiceClient) GetRegistrationRewardEligibility(ctx context.Context, in *GetRegistrationRewardEligibilityRequest, opts ...grpc.CallOption) (*GetRegistrationRewardEligibilityResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetRegistrationRewardEligibilityResponse) + err := c.cc.Invoke(ctx, RegistrationRewardService_GetRegistrationRewardEligibility_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *registrationRewardServiceClient) IssueRegistrationReward(ctx context.Context, in *IssueRegistrationRewardRequest, opts ...grpc.CallOption) (*IssueRegistrationRewardResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(IssueRegistrationRewardResponse) + err := c.cc.Invoke(ctx, RegistrationRewardService_IssueRegistrationReward_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RegistrationRewardServiceServer is the server API for RegistrationRewardService service. +// All implementations must embed UnimplementedRegistrationRewardServiceServer +// for forward compatibility. +// +// RegistrationRewardService 拥有 App 查询和注册完成发放入口。 +type RegistrationRewardServiceServer interface { + GetRegistrationRewardEligibility(context.Context, *GetRegistrationRewardEligibilityRequest) (*GetRegistrationRewardEligibilityResponse, error) + IssueRegistrationReward(context.Context, *IssueRegistrationRewardRequest) (*IssueRegistrationRewardResponse, error) + mustEmbedUnimplementedRegistrationRewardServiceServer() +} + +// UnimplementedRegistrationRewardServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedRegistrationRewardServiceServer struct{} + +func (UnimplementedRegistrationRewardServiceServer) GetRegistrationRewardEligibility(context.Context, *GetRegistrationRewardEligibilityRequest) (*GetRegistrationRewardEligibilityResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRegistrationRewardEligibility not implemented") +} +func (UnimplementedRegistrationRewardServiceServer) IssueRegistrationReward(context.Context, *IssueRegistrationRewardRequest) (*IssueRegistrationRewardResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IssueRegistrationReward not implemented") +} +func (UnimplementedRegistrationRewardServiceServer) mustEmbedUnimplementedRegistrationRewardServiceServer() { +} +func (UnimplementedRegistrationRewardServiceServer) testEmbeddedByValue() {} + +// UnsafeRegistrationRewardServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to RegistrationRewardServiceServer will +// result in compilation errors. +type UnsafeRegistrationRewardServiceServer interface { + mustEmbedUnimplementedRegistrationRewardServiceServer() +} + +func RegisterRegistrationRewardServiceServer(s grpc.ServiceRegistrar, srv RegistrationRewardServiceServer) { + // If the following call pancis, it indicates UnimplementedRegistrationRewardServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&RegistrationRewardService_ServiceDesc, srv) +} + +func _RegistrationRewardService_GetRegistrationRewardEligibility_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRegistrationRewardEligibilityRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RegistrationRewardServiceServer).GetRegistrationRewardEligibility(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RegistrationRewardService_GetRegistrationRewardEligibility_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RegistrationRewardServiceServer).GetRegistrationRewardEligibility(ctx, req.(*GetRegistrationRewardEligibilityRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RegistrationRewardService_IssueRegistrationReward_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(IssueRegistrationRewardRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RegistrationRewardServiceServer).IssueRegistrationReward(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RegistrationRewardService_IssueRegistrationReward_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RegistrationRewardServiceServer).IssueRegistrationReward(ctx, req.(*IssueRegistrationRewardRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// RegistrationRewardService_ServiceDesc is the grpc.ServiceDesc for RegistrationRewardService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var RegistrationRewardService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "hyapp.activity.v1.RegistrationRewardService", + HandlerType: (*RegistrationRewardServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetRegistrationRewardEligibility", + Handler: _RegistrationRewardService_GetRegistrationRewardEligibility_Handler, + }, + { + MethodName: "IssueRegistrationReward", + Handler: _RegistrationRewardService_IssueRegistrationReward_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto/activity/v1/activity.proto", +} + +const ( + AdminRegistrationRewardService_GetRegistrationRewardConfig_FullMethodName = "/hyapp.activity.v1.AdminRegistrationRewardService/GetRegistrationRewardConfig" + AdminRegistrationRewardService_UpdateRegistrationRewardConfig_FullMethodName = "/hyapp.activity.v1.AdminRegistrationRewardService/UpdateRegistrationRewardConfig" + AdminRegistrationRewardService_ListRegistrationRewardClaims_FullMethodName = "/hyapp.activity.v1.AdminRegistrationRewardService/ListRegistrationRewardClaims" +) + +// AdminRegistrationRewardServiceClient is the client API for AdminRegistrationRewardService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// AdminRegistrationRewardService 是后台活动管理访问注册奖励配置和领取记录的唯一入口。 +type AdminRegistrationRewardServiceClient interface { + GetRegistrationRewardConfig(ctx context.Context, in *GetRegistrationRewardConfigRequest, opts ...grpc.CallOption) (*GetRegistrationRewardConfigResponse, error) + UpdateRegistrationRewardConfig(ctx context.Context, in *UpdateRegistrationRewardConfigRequest, opts ...grpc.CallOption) (*UpdateRegistrationRewardConfigResponse, error) + ListRegistrationRewardClaims(ctx context.Context, in *ListRegistrationRewardClaimsRequest, opts ...grpc.CallOption) (*ListRegistrationRewardClaimsResponse, error) +} + +type adminRegistrationRewardServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAdminRegistrationRewardServiceClient(cc grpc.ClientConnInterface) AdminRegistrationRewardServiceClient { + return &adminRegistrationRewardServiceClient{cc} +} + +func (c *adminRegistrationRewardServiceClient) GetRegistrationRewardConfig(ctx context.Context, in *GetRegistrationRewardConfigRequest, opts ...grpc.CallOption) (*GetRegistrationRewardConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetRegistrationRewardConfigResponse) + err := c.cc.Invoke(ctx, AdminRegistrationRewardService_GetRegistrationRewardConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminRegistrationRewardServiceClient) UpdateRegistrationRewardConfig(ctx context.Context, in *UpdateRegistrationRewardConfigRequest, opts ...grpc.CallOption) (*UpdateRegistrationRewardConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateRegistrationRewardConfigResponse) + err := c.cc.Invoke(ctx, AdminRegistrationRewardService_UpdateRegistrationRewardConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminRegistrationRewardServiceClient) ListRegistrationRewardClaims(ctx context.Context, in *ListRegistrationRewardClaimsRequest, opts ...grpc.CallOption) (*ListRegistrationRewardClaimsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListRegistrationRewardClaimsResponse) + err := c.cc.Invoke(ctx, AdminRegistrationRewardService_ListRegistrationRewardClaims_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdminRegistrationRewardServiceServer is the server API for AdminRegistrationRewardService service. +// All implementations must embed UnimplementedAdminRegistrationRewardServiceServer +// for forward compatibility. +// +// AdminRegistrationRewardService 是后台活动管理访问注册奖励配置和领取记录的唯一入口。 +type AdminRegistrationRewardServiceServer interface { + GetRegistrationRewardConfig(context.Context, *GetRegistrationRewardConfigRequest) (*GetRegistrationRewardConfigResponse, error) + UpdateRegistrationRewardConfig(context.Context, *UpdateRegistrationRewardConfigRequest) (*UpdateRegistrationRewardConfigResponse, error) + ListRegistrationRewardClaims(context.Context, *ListRegistrationRewardClaimsRequest) (*ListRegistrationRewardClaimsResponse, error) + mustEmbedUnimplementedAdminRegistrationRewardServiceServer() +} + +// UnimplementedAdminRegistrationRewardServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedAdminRegistrationRewardServiceServer struct{} + +func (UnimplementedAdminRegistrationRewardServiceServer) GetRegistrationRewardConfig(context.Context, *GetRegistrationRewardConfigRequest) (*GetRegistrationRewardConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRegistrationRewardConfig not implemented") +} +func (UnimplementedAdminRegistrationRewardServiceServer) UpdateRegistrationRewardConfig(context.Context, *UpdateRegistrationRewardConfigRequest) (*UpdateRegistrationRewardConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateRegistrationRewardConfig not implemented") +} +func (UnimplementedAdminRegistrationRewardServiceServer) ListRegistrationRewardClaims(context.Context, *ListRegistrationRewardClaimsRequest) (*ListRegistrationRewardClaimsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListRegistrationRewardClaims not implemented") +} +func (UnimplementedAdminRegistrationRewardServiceServer) mustEmbedUnimplementedAdminRegistrationRewardServiceServer() { +} +func (UnimplementedAdminRegistrationRewardServiceServer) testEmbeddedByValue() {} + +// UnsafeAdminRegistrationRewardServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AdminRegistrationRewardServiceServer will +// result in compilation errors. +type UnsafeAdminRegistrationRewardServiceServer interface { + mustEmbedUnimplementedAdminRegistrationRewardServiceServer() +} + +func RegisterAdminRegistrationRewardServiceServer(s grpc.ServiceRegistrar, srv AdminRegistrationRewardServiceServer) { + // If the following call pancis, it indicates UnimplementedAdminRegistrationRewardServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&AdminRegistrationRewardService_ServiceDesc, srv) +} + +func _AdminRegistrationRewardService_GetRegistrationRewardConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRegistrationRewardConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminRegistrationRewardServiceServer).GetRegistrationRewardConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminRegistrationRewardService_GetRegistrationRewardConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminRegistrationRewardServiceServer).GetRegistrationRewardConfig(ctx, req.(*GetRegistrationRewardConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminRegistrationRewardService_UpdateRegistrationRewardConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateRegistrationRewardConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminRegistrationRewardServiceServer).UpdateRegistrationRewardConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminRegistrationRewardService_UpdateRegistrationRewardConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminRegistrationRewardServiceServer).UpdateRegistrationRewardConfig(ctx, req.(*UpdateRegistrationRewardConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminRegistrationRewardService_ListRegistrationRewardClaims_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListRegistrationRewardClaimsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminRegistrationRewardServiceServer).ListRegistrationRewardClaims(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminRegistrationRewardService_ListRegistrationRewardClaims_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminRegistrationRewardServiceServer).ListRegistrationRewardClaims(ctx, req.(*ListRegistrationRewardClaimsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// AdminRegistrationRewardService_ServiceDesc is the grpc.ServiceDesc for AdminRegistrationRewardService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AdminRegistrationRewardService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "hyapp.activity.v1.AdminRegistrationRewardService", + HandlerType: (*AdminRegistrationRewardServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetRegistrationRewardConfig", + Handler: _AdminRegistrationRewardService_GetRegistrationRewardConfig_Handler, + }, + { + MethodName: "UpdateRegistrationRewardConfig", + Handler: _AdminRegistrationRewardService_UpdateRegistrationRewardConfig_Handler, + }, + { + MethodName: "ListRegistrationRewardClaims", + Handler: _AdminRegistrationRewardService_ListRegistrationRewardClaims_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto/activity/v1/activity.proto", +} diff --git a/api/proto/events/room/v1/events.pb.go b/api/proto/events/room/v1/events.pb.go index ad3fb7ee..cf28a605 100644 --- a/api/proto/events/room/v1/events.pb.go +++ b/api/proto/events/room/v1/events.pb.go @@ -122,7 +122,6 @@ type RoomCreated struct { unknownFields protoimpl.UnknownFields OwnerUserId int64 `protobuf:"varint,1,opt,name=owner_user_id,json=ownerUserId,proto3" json:"owner_user_id,omitempty"` - HostUserId int64 `protobuf:"varint,2,opt,name=host_user_id,json=hostUserId,proto3" json:"host_user_id,omitempty"` SeatCount int32 `protobuf:"varint,3,opt,name=seat_count,json=seatCount,proto3" json:"seat_count,omitempty"` Mode string `protobuf:"bytes,4,opt,name=mode,proto3" json:"mode,omitempty"` // room_name/room_avatar/room_description 是创建时确定的展示资料快照,消费者不需要反查 room-service。 @@ -168,13 +167,6 @@ func (x *RoomCreated) GetOwnerUserId() int64 { return 0 } -func (x *RoomCreated) GetHostUserId() int64 { - if x != nil { - return x.HostUserId - } - return 0 -} - func (x *RoomCreated) GetSeatCount() int32 { if x != nil { return x.SeatCount @@ -749,68 +741,6 @@ func (x *RoomAdminChanged) GetEnabled() bool { return false } -// RoomHostTransferred 表达主持人身份转移。 -type RoomHostTransferred struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ActorUserId int64 `protobuf:"varint,1,opt,name=actor_user_id,json=actorUserId,proto3" json:"actor_user_id,omitempty"` - OldHostUserId int64 `protobuf:"varint,2,opt,name=old_host_user_id,json=oldHostUserId,proto3" json:"old_host_user_id,omitempty"` - NewHostUserId int64 `protobuf:"varint,3,opt,name=new_host_user_id,json=newHostUserId,proto3" json:"new_host_user_id,omitempty"` -} - -func (x *RoomHostTransferred) Reset() { - *x = RoomHostTransferred{} - mi := &file_proto_events_room_v1_events_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *RoomHostTransferred) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RoomHostTransferred) ProtoMessage() {} - -func (x *RoomHostTransferred) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[10] - 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 RoomHostTransferred.ProtoReflect.Descriptor instead. -func (*RoomHostTransferred) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{10} -} - -func (x *RoomHostTransferred) GetActorUserId() int64 { - if x != nil { - return x.ActorUserId - } - return 0 -} - -func (x *RoomHostTransferred) GetOldHostUserId() int64 { - if x != nil { - return x.OldHostUserId - } - return 0 -} - -func (x *RoomHostTransferred) GetNewHostUserId() int64 { - if x != nil { - return x.NewHostUserId - } - return 0 -} - // RoomUserMuted 表达禁言状态变更。 type RoomUserMuted struct { state protoimpl.MessageState @@ -824,7 +754,7 @@ type RoomUserMuted struct { func (x *RoomUserMuted) Reset() { *x = RoomUserMuted{} - mi := &file_proto_events_room_v1_events_proto_msgTypes[11] + mi := &file_proto_events_room_v1_events_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -836,7 +766,7 @@ func (x *RoomUserMuted) String() string { func (*RoomUserMuted) ProtoMessage() {} func (x *RoomUserMuted) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[11] + mi := &file_proto_events_room_v1_events_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -849,7 +779,7 @@ func (x *RoomUserMuted) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomUserMuted.ProtoReflect.Descriptor instead. func (*RoomUserMuted) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{11} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{10} } func (x *RoomUserMuted) GetActorUserId() int64 { @@ -885,7 +815,7 @@ type RoomUserKicked struct { func (x *RoomUserKicked) Reset() { *x = RoomUserKicked{} - mi := &file_proto_events_room_v1_events_proto_msgTypes[12] + mi := &file_proto_events_room_v1_events_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -897,7 +827,7 @@ func (x *RoomUserKicked) String() string { func (*RoomUserKicked) ProtoMessage() {} func (x *RoomUserKicked) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[12] + mi := &file_proto_events_room_v1_events_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -910,7 +840,7 @@ func (x *RoomUserKicked) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomUserKicked.ProtoReflect.Descriptor instead. func (*RoomUserKicked) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{12} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{11} } func (x *RoomUserKicked) GetActorUserId() int64 { @@ -939,7 +869,7 @@ type RoomUserUnbanned struct { func (x *RoomUserUnbanned) Reset() { *x = RoomUserUnbanned{} - mi := &file_proto_events_room_v1_events_proto_msgTypes[13] + mi := &file_proto_events_room_v1_events_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -951,7 +881,7 @@ func (x *RoomUserUnbanned) String() string { func (*RoomUserUnbanned) ProtoMessage() {} func (x *RoomUserUnbanned) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[13] + mi := &file_proto_events_room_v1_events_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -964,7 +894,7 @@ func (x *RoomUserUnbanned) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomUserUnbanned.ProtoReflect.Descriptor instead. func (*RoomUserUnbanned) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{13} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{12} } func (x *RoomUserUnbanned) GetActorUserId() int64 { @@ -999,7 +929,7 @@ type RoomGiftSent struct { func (x *RoomGiftSent) Reset() { *x = RoomGiftSent{} - mi := &file_proto_events_room_v1_events_proto_msgTypes[14] + mi := &file_proto_events_room_v1_events_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1011,7 +941,7 @@ func (x *RoomGiftSent) String() string { func (*RoomGiftSent) ProtoMessage() {} func (x *RoomGiftSent) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[14] + mi := &file_proto_events_room_v1_events_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1024,7 +954,7 @@ func (x *RoomGiftSent) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomGiftSent.ProtoReflect.Descriptor instead. func (*RoomGiftSent) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{14} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{13} } func (x *RoomGiftSent) GetSenderUserId() int64 { @@ -1095,7 +1025,7 @@ type RoomHeatChanged struct { func (x *RoomHeatChanged) Reset() { *x = RoomHeatChanged{} - mi := &file_proto_events_room_v1_events_proto_msgTypes[15] + mi := &file_proto_events_room_v1_events_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1107,7 +1037,7 @@ func (x *RoomHeatChanged) String() string { func (*RoomHeatChanged) ProtoMessage() {} func (x *RoomHeatChanged) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[15] + mi := &file_proto_events_room_v1_events_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1120,7 +1050,7 @@ func (x *RoomHeatChanged) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomHeatChanged.ProtoReflect.Descriptor instead. func (*RoomHeatChanged) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{15} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{14} } func (x *RoomHeatChanged) GetDelta() int64 { @@ -1150,7 +1080,7 @@ type RoomRankChanged struct { func (x *RoomRankChanged) Reset() { *x = RoomRankChanged{} - mi := &file_proto_events_room_v1_events_proto_msgTypes[16] + mi := &file_proto_events_room_v1_events_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1162,7 +1092,7 @@ func (x *RoomRankChanged) String() string { func (*RoomRankChanged) ProtoMessage() {} func (x *RoomRankChanged) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[16] + mi := &file_proto_events_room_v1_events_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1175,7 +1105,7 @@ func (x *RoomRankChanged) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomRankChanged.ProtoReflect.Descriptor instead. func (*RoomRankChanged) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{16} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{15} } func (x *RoomRankChanged) GetUserId() int64 { @@ -1219,99 +1149,88 @@ var file_proto_events_room_v1_events_proto_rawDesc = []byte{ 0x72, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, - 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0xef, 0x01, 0x0a, 0x0b, 0x52, 0x6f, 0x6f, 0x6d, 0x43, + 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0xcd, 0x01, 0x0a, 0x0b, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6f, - 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x68, 0x6f, - 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, - 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x09, 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, - 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, - 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x29, 0x0a, - 0x10, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x6f, 0x6f, 0x6d, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc0, 0x01, 0x0a, 0x12, 0x52, 0x6f, 0x6f, - 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, 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, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x6f, 0x6f, - 0x6d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, - 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x09, 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3d, 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, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 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, 0x8b, 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, 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, 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, 0x8b, 0x01, 0x0a, 0x13, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, - 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x12, 0x22, 0x0a, + 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, + 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, + 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, + 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, + 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x72, + 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x6f, 0x6f, 0x6d, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc0, 0x01, 0x0a, 0x12, 0x52, 0x6f, 0x6f, 0x6d, 0x50, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x64, 0x61, 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, 0x27, 0x0a, 0x10, 0x6f, 0x6c, 0x64, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6f, 0x6c, 0x64, - 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x10, 0x6e, 0x65, - 0x77, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x65, 0x77, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x22, 0x6f, 0x0a, 0x0d, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4d, + 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, + 0x29, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x6f, 0x6f, 0x6d, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, + 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, + 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3d, 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, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 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, 0x8b, 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, 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, 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, @@ -1378,7 +1297,7 @@ func file_proto_events_room_v1_events_proto_rawDescGZIP() []byte { return file_proto_events_room_v1_events_proto_rawDescData } -var file_proto_events_room_v1_events_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_proto_events_room_v1_events_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_proto_events_room_v1_events_proto_goTypes = []any{ (*EventEnvelope)(nil), // 0: hyapp.events.room.v1.EventEnvelope (*RoomCreated)(nil), // 1: hyapp.events.room.v1.RoomCreated @@ -1390,13 +1309,12 @@ var file_proto_events_room_v1_events_proto_goTypes = []any{ (*RoomMicSeatLocked)(nil), // 7: hyapp.events.room.v1.RoomMicSeatLocked (*RoomChatEnabledChanged)(nil), // 8: hyapp.events.room.v1.RoomChatEnabledChanged (*RoomAdminChanged)(nil), // 9: hyapp.events.room.v1.RoomAdminChanged - (*RoomHostTransferred)(nil), // 10: hyapp.events.room.v1.RoomHostTransferred - (*RoomUserMuted)(nil), // 11: hyapp.events.room.v1.RoomUserMuted - (*RoomUserKicked)(nil), // 12: hyapp.events.room.v1.RoomUserKicked - (*RoomUserUnbanned)(nil), // 13: hyapp.events.room.v1.RoomUserUnbanned - (*RoomGiftSent)(nil), // 14: hyapp.events.room.v1.RoomGiftSent - (*RoomHeatChanged)(nil), // 15: hyapp.events.room.v1.RoomHeatChanged - (*RoomRankChanged)(nil), // 16: hyapp.events.room.v1.RoomRankChanged + (*RoomUserMuted)(nil), // 10: hyapp.events.room.v1.RoomUserMuted + (*RoomUserKicked)(nil), // 11: hyapp.events.room.v1.RoomUserKicked + (*RoomUserUnbanned)(nil), // 12: hyapp.events.room.v1.RoomUserUnbanned + (*RoomGiftSent)(nil), // 13: hyapp.events.room.v1.RoomGiftSent + (*RoomHeatChanged)(nil), // 14: hyapp.events.room.v1.RoomHeatChanged + (*RoomRankChanged)(nil), // 15: hyapp.events.room.v1.RoomRankChanged } var file_proto_events_room_v1_events_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type @@ -1417,7 +1335,7 @@ func file_proto_events_room_v1_events_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_events_room_v1_events_proto_rawDesc, NumEnums: 0, - NumMessages: 17, + NumMessages: 16, NumExtensions: 0, NumServices: 0, }, diff --git a/api/proto/events/room/v1/events.proto b/api/proto/events/room/v1/events.proto index 3d6c3c73..a04da523 100644 --- a/api/proto/events/room/v1/events.proto +++ b/api/proto/events/room/v1/events.proto @@ -19,7 +19,6 @@ message EventEnvelope { // RoomCreated 表达房间第一次建立成功。 message RoomCreated { int64 owner_user_id = 1; - int64 host_user_id = 2; int32 seat_count = 3; string mode = 4; // room_name/room_avatar/room_description 是创建时确定的展示资料快照,消费者不需要反查 room-service。 @@ -92,13 +91,6 @@ message RoomAdminChanged { bool enabled = 3; } -// RoomHostTransferred 表达主持人身份转移。 -message RoomHostTransferred { - int64 actor_user_id = 1; - int64 old_host_user_id = 2; - int64 new_host_user_id = 3; -} - // RoomUserMuted 表达禁言状态变更。 message RoomUserMuted { int64 actor_user_id = 1; diff --git a/api/proto/room/v1/room.pb.go b/api/proto/room/v1/room.pb.go index 1fed6c64..b9ddd2fd 100644 --- a/api/proto/room/v1/room.pb.go +++ b/api/proto/room/v1/room.pb.go @@ -451,7 +451,6 @@ type RoomSnapshot struct { RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` OwnerUserId int64 `protobuf:"varint,2,opt,name=owner_user_id,json=ownerUserId,proto3" json:"owner_user_id,omitempty"` - HostUserId int64 `protobuf:"varint,3,opt,name=host_user_id,json=hostUserId,proto3" json:"host_user_id,omitempty"` Mode string `protobuf:"bytes,4,opt,name=mode,proto3" json:"mode,omitempty"` Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` ChatEnabled bool `protobuf:"varint,6,opt,name=chat_enabled,json=chatEnabled,proto3" json:"chat_enabled,omitempty"` @@ -513,13 +512,6 @@ func (x *RoomSnapshot) GetOwnerUserId() int64 { return 0 } -func (x *RoomSnapshot) GetHostUserId() int64 { - if x != nil { - return x.HostUserId - } - return 0 -} - func (x *RoomSnapshot) GetMode() string { if x != nil { return x.Mode @@ -2501,114 +2493,6 @@ func (x *SetRoomAdminResponse) GetRoom() *RoomSnapshot { return nil } -// TransferRoomHostRequest 把主持人身份转移给房间内用户。 -type TransferRoomHostRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` - TargetUserId int64 `protobuf:"varint,2,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` -} - -func (x *TransferRoomHostRequest) Reset() { - *x = TransferRoomHostRequest{} - mi := &file_proto_room_v1_room_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *TransferRoomHostRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransferRoomHostRequest) ProtoMessage() {} - -func (x *TransferRoomHostRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[36] - 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 TransferRoomHostRequest.ProtoReflect.Descriptor instead. -func (*TransferRoomHostRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{36} -} - -func (x *TransferRoomHostRequest) GetMeta() *RequestMeta { - if x != nil { - return x.Meta - } - return nil -} - -func (x *TransferRoomHostRequest) GetTargetUserId() int64 { - if x != nil { - return x.TargetUserId - } - return 0 -} - -// TransferRoomHostResponse 返回主持人转移后的最新房间快照。 -type TransferRoomHostResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Result *CommandResult `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` - Room *RoomSnapshot `protobuf:"bytes,2,opt,name=room,proto3" json:"room,omitempty"` -} - -func (x *TransferRoomHostResponse) Reset() { - *x = TransferRoomHostResponse{} - mi := &file_proto_room_v1_room_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *TransferRoomHostResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransferRoomHostResponse) ProtoMessage() {} - -func (x *TransferRoomHostResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[37] - 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 TransferRoomHostResponse.ProtoReflect.Descriptor instead. -func (*TransferRoomHostResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{37} -} - -func (x *TransferRoomHostResponse) GetResult() *CommandResult { - if x != nil { - return x.Result - } - return nil -} - -func (x *TransferRoomHostResponse) GetRoom() *RoomSnapshot { - if x != nil { - return x.Room - } - return nil -} - // MuteUserRequest 修改房间内禁言态。 type MuteUserRequest struct { state protoimpl.MessageState @@ -2622,7 +2506,7 @@ type MuteUserRequest struct { func (x *MuteUserRequest) Reset() { *x = MuteUserRequest{} - mi := &file_proto_room_v1_room_proto_msgTypes[38] + mi := &file_proto_room_v1_room_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2634,7 +2518,7 @@ func (x *MuteUserRequest) String() string { func (*MuteUserRequest) ProtoMessage() {} func (x *MuteUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[38] + mi := &file_proto_room_v1_room_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2647,7 +2531,7 @@ func (x *MuteUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MuteUserRequest.ProtoReflect.Descriptor instead. func (*MuteUserRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{38} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{36} } func (x *MuteUserRequest) GetMeta() *RequestMeta { @@ -2683,7 +2567,7 @@ type MuteUserResponse struct { func (x *MuteUserResponse) Reset() { *x = MuteUserResponse{} - mi := &file_proto_room_v1_room_proto_msgTypes[39] + mi := &file_proto_room_v1_room_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2695,7 +2579,7 @@ func (x *MuteUserResponse) String() string { func (*MuteUserResponse) ProtoMessage() {} func (x *MuteUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[39] + mi := &file_proto_room_v1_room_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2708,7 +2592,7 @@ func (x *MuteUserResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MuteUserResponse.ProtoReflect.Descriptor instead. func (*MuteUserResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{39} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{37} } func (x *MuteUserResponse) GetResult() *CommandResult { @@ -2737,7 +2621,7 @@ type KickUserRequest struct { func (x *KickUserRequest) Reset() { *x = KickUserRequest{} - mi := &file_proto_room_v1_room_proto_msgTypes[40] + mi := &file_proto_room_v1_room_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2749,7 +2633,7 @@ func (x *KickUserRequest) String() string { func (*KickUserRequest) ProtoMessage() {} func (x *KickUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[40] + mi := &file_proto_room_v1_room_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2762,7 +2646,7 @@ func (x *KickUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use KickUserRequest.ProtoReflect.Descriptor instead. func (*KickUserRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{40} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{38} } func (x *KickUserRequest) GetMeta() *RequestMeta { @@ -2791,7 +2675,7 @@ type KickUserResponse struct { func (x *KickUserResponse) Reset() { *x = KickUserResponse{} - mi := &file_proto_room_v1_room_proto_msgTypes[41] + mi := &file_proto_room_v1_room_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2803,7 +2687,7 @@ func (x *KickUserResponse) String() string { func (*KickUserResponse) ProtoMessage() {} func (x *KickUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[41] + mi := &file_proto_room_v1_room_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2816,7 +2700,7 @@ func (x *KickUserResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use KickUserResponse.ProtoReflect.Descriptor instead. func (*KickUserResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{41} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{39} } func (x *KickUserResponse) GetResult() *CommandResult { @@ -2845,7 +2729,7 @@ type UnbanUserRequest struct { func (x *UnbanUserRequest) Reset() { *x = UnbanUserRequest{} - mi := &file_proto_room_v1_room_proto_msgTypes[42] + mi := &file_proto_room_v1_room_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2857,7 +2741,7 @@ func (x *UnbanUserRequest) String() string { func (*UnbanUserRequest) ProtoMessage() {} func (x *UnbanUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[42] + mi := &file_proto_room_v1_room_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2870,7 +2754,7 @@ func (x *UnbanUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbanUserRequest.ProtoReflect.Descriptor instead. func (*UnbanUserRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{42} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{40} } func (x *UnbanUserRequest) GetMeta() *RequestMeta { @@ -2899,7 +2783,7 @@ type UnbanUserResponse struct { func (x *UnbanUserResponse) Reset() { *x = UnbanUserResponse{} - mi := &file_proto_room_v1_room_proto_msgTypes[43] + mi := &file_proto_room_v1_room_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2911,7 +2795,7 @@ func (x *UnbanUserResponse) String() string { func (*UnbanUserResponse) ProtoMessage() {} func (x *UnbanUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[43] + mi := &file_proto_room_v1_room_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2924,7 +2808,7 @@ func (x *UnbanUserResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbanUserResponse.ProtoReflect.Descriptor instead. func (*UnbanUserResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{43} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{41} } func (x *UnbanUserResponse) GetResult() *CommandResult { @@ -2941,6 +2825,172 @@ func (x *UnbanUserResponse) GetRoom() *RoomSnapshot { return nil } +// SystemEvictUserRequest 是平台级封禁、风控或后台治理触发的系统驱逐入口。 +// 该命令仍由 Room Cell 修改房间状态;调用方不能直接写房间 presence 或麦位。 +type SystemEvictUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + TargetUserId int64 `protobuf:"varint,2,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + OperatorUserId int64 `protobuf:"varint,3,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` + // ban_from_room 为 true 时把用户加入当前房间 ban 集合,防止同一房间恢复入口重新进入。 + BanFromRoom bool `protobuf:"varint,5,opt,name=ban_from_room,json=banFromRoom,proto3" json:"ban_from_room,omitempty"` +} + +func (x *SystemEvictUserRequest) Reset() { + *x = SystemEvictUserRequest{} + mi := &file_proto_room_v1_room_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SystemEvictUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SystemEvictUserRequest) ProtoMessage() {} + +func (x *SystemEvictUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_proto_msgTypes[42] + 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 SystemEvictUserRequest.ProtoReflect.Descriptor instead. +func (*SystemEvictUserRequest) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{42} +} + +func (x *SystemEvictUserRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *SystemEvictUserRequest) GetTargetUserId() int64 { + if x != nil { + return x.TargetUserId + } + return 0 +} + +func (x *SystemEvictUserRequest) GetOperatorUserId() int64 { + if x != nil { + return x.OperatorUserId + } + return 0 +} + +func (x *SystemEvictUserRequest) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *SystemEvictUserRequest) GetBanFromRoom() bool { + if x != nil { + return x.BanFromRoom + } + return false +} + +// SystemEvictUserResponse 返回系统驱逐的房间状态和外部 RTC 副作用结果。 +type SystemEvictUserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HadCurrentRoom bool `protobuf:"varint,1,opt,name=had_current_room,json=hadCurrentRoom,proto3" json:"had_current_room,omitempty"` + Result *CommandResult `protobuf:"bytes,2,opt,name=result,proto3" json:"result,omitempty"` + Room *RoomSnapshot `protobuf:"bytes,3,opt,name=room,proto3" json:"room,omitempty"` + RoomId string `protobuf:"bytes,4,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + RtcKicked bool `protobuf:"varint,5,opt,name=rtc_kicked,json=rtcKicked,proto3" json:"rtc_kicked,omitempty"` + RtcKickError string `protobuf:"bytes,6,opt,name=rtc_kick_error,json=rtcKickError,proto3" json:"rtc_kick_error,omitempty"` +} + +func (x *SystemEvictUserResponse) Reset() { + *x = SystemEvictUserResponse{} + mi := &file_proto_room_v1_room_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SystemEvictUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SystemEvictUserResponse) ProtoMessage() {} + +func (x *SystemEvictUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_proto_msgTypes[43] + 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 SystemEvictUserResponse.ProtoReflect.Descriptor instead. +func (*SystemEvictUserResponse) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{43} +} + +func (x *SystemEvictUserResponse) GetHadCurrentRoom() bool { + if x != nil { + return x.HadCurrentRoom + } + return false +} + +func (x *SystemEvictUserResponse) GetResult() *CommandResult { + if x != nil { + return x.Result + } + return nil +} + +func (x *SystemEvictUserResponse) GetRoom() *RoomSnapshot { + if x != nil { + return x.Room + } + return nil +} + +func (x *SystemEvictUserResponse) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *SystemEvictUserResponse) GetRtcKicked() bool { + if x != nil { + return x.RtcKicked + } + return false +} + +func (x *SystemEvictUserResponse) GetRtcKickError() string { + if x != nil { + return x.RtcKickError + } + return "" +} + // SendGiftRequest 是首版房间内最重要的变现命令。 type SendGiftRequest struct { state protoimpl.MessageState @@ -3632,7 +3682,6 @@ type RoomListItem struct { RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` OwnerUserId int64 `protobuf:"varint,2,opt,name=owner_user_id,json=ownerUserId,proto3" json:"owner_user_id,omitempty"` - HostUserId int64 `protobuf:"varint,3,opt,name=host_user_id,json=hostUserId,proto3" json:"host_user_id,omitempty"` Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"` CoverUrl string `protobuf:"bytes,5,opt,name=cover_url,json=coverUrl,proto3" json:"cover_url,omitempty"` Mode string `protobuf:"bytes,6,opt,name=mode,proto3" json:"mode,omitempty"` @@ -3690,13 +3739,6 @@ func (x *RoomListItem) GetOwnerUserId() int64 { return 0 } -func (x *RoomListItem) GetHostUserId() int64 { - if x != nil { - return x.HostUserId - } - return 0 -} - func (x *RoomListItem) GetTitle() string { if x != nil { return x.Title @@ -4451,778 +4493,788 @@ var file_proto_room_v1_room_proto_rawDesc = []byte{ 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, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xeb, + 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xc9, 0x05, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, - 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, - 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, - 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, - 0x61, 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0b, 0x63, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x35, 0x0a, - 0x09, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x61, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x08, 0x6d, 0x69, 0x63, 0x53, - 0x65, 0x61, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x0c, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x75, - 0x73, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x0b, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x62, 0x61, 0x6e, 0x5f, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0a, 0x62, 0x61, - 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x75, 0x74, 0x65, - 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x03, 0x52, - 0x0b, 0x6d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x34, 0x0a, 0x09, - 0x67, 0x69, 0x66, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x61, 0x6e, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x67, 0x69, 0x66, 0x74, 0x52, 0x61, - 0x6e, 0x6b, 0x12, 0x43, 0x0a, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x65, 0x78, 0x74, 0x18, 0x0d, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, - 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x45, 0x78, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, - 0x72, 0x6f, 0x6f, 0x6d, 0x45, 0x78, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x74, 0x18, - 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x68, 0x65, 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, - 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, - 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, - 0x72, 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, 0x12, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x1a, 0x3a, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x45, 0x78, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xaf, 0x02, 0x0a, - 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, - 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, - 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, - 0x29, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x6f, 0x6f, 0x6d, 0x44, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x6f, - 0x6f, 0x6d, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x49, 0x64, 0x22, 0x7b, - 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0xa8, 0x02, 0x0a, 0x18, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 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, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x20, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x72, - 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x6f, - 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x01, 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x88, 0x01, 0x01, - 0x12, 0x2e, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x0f, 0x72, 0x6f, - 0x6f, 0x6d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, - 0x12, 0x22, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x05, 0x48, 0x03, 0x52, 0x09, 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, - 0x61, 0x72, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x65, 0x61, 0x74, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x82, 0x01, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x55, 0x0a, 0x0f, 0x4a, - 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x12, - 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, - 0x6c, 0x65, 0x22, 0xa6, 0x01, 0x0a, 0x10, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2b, 0x0a, - 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, - 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x46, 0x0a, 0x14, 0x52, - 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, - 0x65, 0x74, 0x61, 0x22, 0xab, 0x01, 0x0a, 0x15, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, - 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, - 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, - 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x74, + 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, + 0x63, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x35, 0x0a, 0x09, 0x6d, + 0x69, 0x63, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x65, 0x61, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x08, 0x6d, 0x69, 0x63, 0x53, 0x65, 0x61, + 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x0c, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x0b, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x24, + 0x0a, 0x0e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x09, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x62, 0x61, 0x6e, 0x5f, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0a, 0x62, 0x61, 0x6e, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x75, 0x74, 0x65, 0x5f, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0b, 0x6d, + 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x34, 0x0a, 0x09, 0x67, 0x69, + 0x66, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, + 0x6e, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x67, 0x69, 0x66, 0x74, 0x52, 0x61, 0x6e, 0x6b, + 0x12, 0x43, 0x0a, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x65, 0x78, 0x74, 0x18, 0x0d, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2e, + 0x52, 0x6f, 0x6f, 0x6d, 0x45, 0x78, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x6f, + 0x6f, 0x6d, 0x45, 0x78, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x74, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x04, 0x68, 0x65, 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, + 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, 0x72, 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, 0x12, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76, + 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x1a, 0x3a, + 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x45, 0x78, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xaf, 0x02, 0x0a, 0x11, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x22, 0x42, 0x0a, 0x10, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, - 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x11, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, - 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x22, 0x5a, 0x0a, 0x10, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, - 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x7a, 0x0a, - 0x11, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, + 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, + 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, + 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, + 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x29, 0x0a, + 0x10, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x6f, 0x6f, 0x6d, 0x44, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x6d, + 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x12, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x57, 0x0a, 0x0c, 0x4d, 0x69, 0x63, - 0x55, 0x70, 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, - 0x72, 0x6f, 0x6f, 0x6d, 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, 0x73, 0x65, 0x61, - 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, - 0x4e, 0x6f, 0x22, 0xe5, 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 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, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, - 0x72, 0x6f, 0x6f, 0x6d, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, - 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x75, - 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6d, - 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x4d, 0x73, 0x22, 0x7e, 0x0a, 0x0e, 0x4d, 0x69, - 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, + 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0xa8, 0x02, 0x0a, 0x18, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 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, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x20, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x72, 0x6f, 0x6f, + 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, + 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, + 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2e, + 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x0f, 0x72, 0x6f, 0x6f, 0x6d, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x22, + 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x05, 0x48, 0x03, 0x52, 0x09, 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x88, + 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, + 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x82, 0x01, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x55, 0x0a, 0x0f, 0x4a, 0x6f, 0x69, + 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, - 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, - 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 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, 0x2f, 0x0a, - 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x85, - 0x01, 0x0a, 0x14, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 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, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, - 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, - 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x22, 0x7e, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0xf8, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 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, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, - 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x24, 0x0a, 0x0e, - 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x1c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, - 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 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, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x22, 0x7f, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x4d, 0x75, 0x74, 0x65, - 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, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, - 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x94, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x4d, 0x75, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 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, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x8b, 0x02, 0x0a, 0x14, 0x41, - 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, + 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, + 0x22, 0xa6, 0x01, 0x0a, 0x10, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x75, + 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x46, 0x0a, 0x14, 0x52, 0x6f, 0x6f, + 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, + 0x61, 0x22, 0xab, 0x01, 0x0a, 0x15, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, + 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x2f, + 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, + 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, + 0x42, 0x0a, 0x10, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, - 0x65, 0x74, 0x61, 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, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x16, 0x0a, 0x06, - 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, - 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x11, - 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x70, 0x70, - 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 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, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x22, 0x78, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, - 0x4c, 0x6f, 0x63, 0x6b, 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, 0x72, 0x6f, 0x6f, 0x6d, 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, 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, 0x7f, 0x0a, 0x16, - 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, - 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x61, 0x0a, - 0x15, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 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, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, - 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x7f, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x22, 0x85, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, - 0x69, 0x6e, 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, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x7d, 0x0a, 0x14, 0x53, 0x65, 0x74, - 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x6f, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x11, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, + 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, + 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, + 0x5a, 0x0a, 0x10, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, - 0x65, 0x74, 0x61, 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, 0x81, 0x01, 0x0a, 0x18, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, - 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x7d, 0x0a, - 0x0f, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, - 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, 0x79, 0x0a, 0x10, - 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x65, 0x74, 0x61, 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, 0x7a, 0x0a, 0x11, 0x43, + 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, - 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x67, 0x0a, 0x0f, 0x4b, 0x69, 0x63, 0x6b, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, + 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x57, 0x0a, 0x0c, 0x4d, 0x69, 0x63, 0x55, 0x70, + 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, 0x72, 0x6f, + 0x6f, 0x6d, 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, 0x73, 0x65, 0x61, 0x74, 0x5f, + 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, + 0x22, 0xe5, 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 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, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, + 0x6f, 0x6d, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x5f, 0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6d, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x44, 0x65, + 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x4d, 0x73, 0x22, 0x7e, 0x0a, 0x0e, 0x4d, 0x69, 0x63, 0x44, + 0x6f, 0x77, 0x6e, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x79, 0x0a, 0x10, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x63, + 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 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, 0x2f, 0x0a, 0x04, 0x72, + 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x85, 0x01, 0x0a, + 0x14, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 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, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, + 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x73, + 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, + 0x61, 0x74, 0x4e, 0x6f, 0x22, 0x7e, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, + 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, + 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0xf8, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, + 0x6d, 0x65, 0x74, 0x61, 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, 0x24, 0x0a, 0x0e, 0x6d, 0x69, + 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, + 0x9e, 0x01, 0x0a, 0x1c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 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, + 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, + 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x22, 0x7f, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x4d, 0x75, 0x74, 0x65, 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, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, + 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x94, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x4d, 0x75, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 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, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x8b, 0x02, 0x0a, 0x14, 0x41, 0x70, 0x70, + 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, + 0x61, 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, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, + 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x79, + 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 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, + 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, + 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x22, 0x78, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, + 0x63, 0x6b, 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, + 0x72, 0x6f, 0x6f, 0x6d, 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, 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, 0x7f, 0x0a, 0x16, 0x53, 0x65, + 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x68, 0x0a, 0x10, 0x55, - 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x7a, 0x0a, 0x11, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x22, 0xe8, 0x01, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, + 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x61, 0x0a, 0x15, 0x53, + 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, + 0x6d, 0x65, 0x74, 0x61, 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, 0x7f, + 0x0a, 0x16, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, + 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, + 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, + 0x85, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 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, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, + 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x7d, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x52, 0x6f, + 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x7d, 0x0a, 0x0f, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 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, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x79, 0x0a, 0x10, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, + 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, + 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x22, 0x67, 0x0a, 0x0f, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, + 0x65, 0x74, 0x61, 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, 0x79, 0x0a, 0x10, 0x4b, 0x69, 0x63, + 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, + 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x68, 0x0a, 0x10, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, + 0x72, 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, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x7a, + 0x0a, 0x11, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, + 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0xd4, 0x01, 0x0a, 0x16, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x45, 0x76, 0x69, 0x63, 0x74, 0x55, 0x73, 0x65, 0x72, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 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, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0d, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x22, 0xfa, 0x01, 0x0a, - 0x10, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, - 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, 0x65, - 0x69, 0x70, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x68, 0x65, - 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x48, 0x65, - 0x61, 0x74, 0x12, 0x34, 0x0a, 0x09, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, - 0x67, 0x69, 0x66, 0x74, 0x52, 0x61, 0x6e, 0x6b, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x6a, 0x0a, 0x1b, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, - 0x64, 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, 0x19, 0x0a, 0x08, 0x61, 0x70, - 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, - 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x73, 0x0a, 0x1c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, - 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 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, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, - 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xa6, 0x01, 0x0a, 0x19, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, - 0x64, 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, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, - 0x63, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, - 0x6f, 0x64, 0x65, 0x22, 0x71, 0x0a, 0x1a, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, - 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, - 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xea, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x6f, 0x6f, 0x6d, 0x73, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x76, - 0x69, 0x65, 0x77, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, - 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, 0x12, 0x10, 0x0a, - 0x03, 0x74, 0x61, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x62, 0x12, - 0x16, 0x0a, 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, - 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x22, 0xb7, 0x02, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, - 0x46, 0x65, 0x65, 0x64, 0x73, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, - 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, - 0x49, 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, 0x12, 0x10, - 0x0a, 0x03, 0x74, 0x61, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x62, - 0x12, 0x16, 0x0a, 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, - 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x12, 0x47, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x79, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x22, 0x0a, + 0x0d, 0x62, 0x61, 0x6e, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x62, 0x61, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x52, 0x6f, 0x6f, + 0x6d, 0x22, 0x88, 0x02, 0x0a, 0x17, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x45, 0x76, 0x69, 0x63, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, + 0x10, 0x68, 0x61, 0x64, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x6f, 0x6f, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x68, 0x61, 0x64, 0x43, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, + 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, - 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x22, 0x63, 0x0a, - 0x13, 0x52, 0x6f, 0x6f, 0x6d, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, - 0x55, 0x73, 0x65, 0x72, 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, 0x33, 0x0a, - 0x16, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x4d, 0x73, 0x22, 0xbd, 0x03, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, - 0x74, 0x65, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, - 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x20, 0x0a, 0x0c, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x76, 0x65, - 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x04, 0x68, 0x65, 0x61, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6e, 0x6c, - 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x74, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x65, - 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x63, 0x63, 0x75, 0x70, - 0x69, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x63, 0x63, 0x75, 0x70, 0x69, 0x65, 0x64, 0x53, 0x65, - 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, - 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0c, 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, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, - 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, 0x72, 0x74, - 0x49, 0x64, 0x22, 0x67, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, - 0x74, 0x65, 0x6d, 0x52, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x65, - 0x78, 0x74, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x22, 0x66, 0x0a, 0x10, 0x47, - 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, - 0x22, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x22, 0x85, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, - 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x61, 0x73, - 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, 0x61, 0x73, - 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, - 0x04, 0x72, 0x6f, 0x6f, 0x6d, 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, 0x22, 0x60, 0x0a, 0x15, 0x47, - 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 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, 0x22, 0xd6, 0x02, - 0x0a, 0x16, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x68, 0x61, 0x73, 0x5f, - 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, - 0x6f, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, - 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, - 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, - 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 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, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, - 0x12, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x69, 0x6d, 0x5f, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6e, 0x65, 0x65, 0x64, 0x4a, - 0x6f, 0x69, 0x6e, 0x49, 0x6d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x65, - 0x65, 0x64, 0x5f, 0x72, 0x74, 0x63, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0c, 0x6e, 0x65, 0x65, 0x64, 0x52, 0x74, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x52, 0x6f, - 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 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, 0x72, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x76, 0x69, - 0x65, 0x77, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x22, 0x70, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x72, - 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x12, 0x24, 0x0a, 0x0e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, - 0x4d, 0x73, 0x22, 0xbc, 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x4f, - 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 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, 0x72, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x76, 0x69, - 0x65, 0x77, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, - 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, - 0x65, 0x22, 0xb9, 0x01, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x4f, 0x6e, - 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x12, 0x17, + 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x74, 0x63, 0x5f, 0x6b, + 0x69, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x74, 0x63, + 0x4b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x74, 0x63, 0x5f, 0x6b, 0x69, + 0x63, 0x6b, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x72, 0x74, 0x63, 0x4b, 0x69, 0x63, 0x6b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xe8, 0x01, 0x0a, + 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, + 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, 0x1f, + 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x26, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, + 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, + 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x49, 0x64, + 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x68, 0x65, 0x61, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x74, 0x12, 0x34, 0x0a, + 0x09, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, - 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x32, 0xd5, 0x0d, - 0x0a, 0x12, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, - 0x6f, 0x6d, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x4b, 0x0a, 0x08, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1e, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, - 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, - 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, - 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x23, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, - 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x4c, 0x65, 0x61, 0x76, - 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x43, 0x6c, 0x6f, 0x73, - 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x05, 0x4d, 0x69, 0x63, 0x55, - 0x70, 0x12, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x4d, 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, - 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x07, - 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, - 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, - 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, - 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x4d, 0x75, 0x74, - 0x65, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x4d, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x4d, 0x75, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, - 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, - 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, - 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, - 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, - 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x57, 0x0a, 0x0c, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, - 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x26, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, - 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, - 0x0a, 0x08, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, 0x65, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, 0x65, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x4b, - 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x55, 0x6e, 0x62, 0x61, - 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, - 0x47, 0x69, 0x66, 0x74, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xee, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x47, 0x75, - 0x61, 0x72, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, - 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb9, 0x04, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, - 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, - 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x0d, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x46, 0x65, 0x65, 0x64, 0x73, 0x12, 0x23, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x46, 0x65, 0x65, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, 0x6d, - 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x67, 0x69, 0x66, 0x74, 0x52, + 0x61, 0x6e, 0x6b, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, + 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x6a, 0x0a, 0x1b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, + 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 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, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, + 0x22, 0x73, 0x0a, 0x1c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 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, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xa6, 0x01, 0x0a, 0x19, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 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, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x71, + 0x0a, 0x1a, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, + 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0xea, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 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, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, + 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, + 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 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, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x62, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x62, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x75, + 0x72, 0x73, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x75, 0x72, 0x73, + 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xb7, + 0x02, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x46, 0x65, 0x65, 0x64, 0x73, + 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, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, + 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x76, 0x69, 0x65, 0x77, 0x65, + 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0c, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 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, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x62, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x62, 0x12, 0x16, 0x0a, 0x06, 0x63, + 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x75, 0x72, + 0x73, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, + 0x47, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x73, + 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x46, 0x65, 0x65, 0x64, 0x52, + 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x0c, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x22, 0x63, 0x0a, 0x13, 0x52, 0x6f, 0x6f, 0x6d, + 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 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, 0x33, 0x0a, 0x16, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, + 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0x9b, 0x03, + 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x17, + 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, + 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x12, + 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, + 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, + 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x68, 0x65, 0x61, 0x74, 0x12, 0x21, + 0x0a, 0x0c, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x63, 0x63, 0x75, 0x70, 0x69, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x61, + 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, + 0x63, 0x63, 0x75, 0x70, 0x69, 0x65, 0x64, 0x53, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0c, 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, + 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, + 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x49, 0x64, 0x22, 0x67, 0x0a, 0x11, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x31, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x72, 0x6f, + 0x6f, 0x6d, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x63, 0x75, 0x72, 0x73, + 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x43, 0x75, + 0x72, 0x73, 0x6f, 0x72, 0x22, 0x66, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, + 0x6d, 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, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, + 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x85, 0x01, 0x0a, + 0x11, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x61, 0x73, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, 0x61, 0x73, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x2f, 0x0a, + 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, + 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 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, 0x22, 0x60, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, 0x6f, 0x6d, 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, 0x22, 0xd6, 0x02, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x28, 0x0a, 0x10, 0x68, 0x61, 0x73, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x68, 0x61, 0x73, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x72, + 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, + 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6d, + 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 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, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x12, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x6a, + 0x6f, 0x69, 0x6e, 0x5f, 0x69, 0x6d, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0f, 0x6e, 0x65, 0x65, 0x64, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6d, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x72, 0x74, 0x63, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6e, 0x65, 0x65, + 0x64, 0x52, 0x74, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x22, + 0x87, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 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, 0x72, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, + 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, + 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x76, 0x69, 0x65, + 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x70, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, - 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x6f, 0x6f, 0x6d, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x4f, - 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 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, 0x72, 0x6f, 0x6f, 0x6d, - 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x6f, 0x6f, 0x6d, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, + 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x22, 0xbc, 0x01, 0x0a, 0x1a, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x73, 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, 0x72, 0x6f, 0x6f, 0x6d, 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, 0x72, 0x6f, + 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, + 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x76, 0x69, 0x65, + 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, + 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0xb9, 0x01, 0x0a, 0x1b, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, + 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, + 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, + 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x32, 0xd2, 0x0d, 0x0a, 0x12, 0x52, 0x6f, 0x6f, 0x6d, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, + 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x20, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x66, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, + 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x4a, 0x6f, 0x69, 0x6e, + 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, + 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, + 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, + 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1f, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1f, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x42, 0x0a, 0x05, 0x4d, 0x69, 0x63, 0x55, 0x70, 0x12, 0x1b, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x63, 0x55, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x07, 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, + 0x12, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x5a, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, + 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, + 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x69, 0x6e, 0x67, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0a, + 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x4d, 0x75, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, + 0x63, 0x4d, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, + 0x4d, 0x69, 0x63, 0x4d, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x5a, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x53, + 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x24, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x53, 0x65, + 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x24, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, + 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x53, 0x65, 0x74, + 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, + 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4b, 0x0a, 0x08, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, + 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x45, 0x76, 0x69, 0x63, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x45, 0x76, 0x69, 0x63, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x45, 0x76, 0x69, + 0x63, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, + 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x47, + 0x69, 0x66, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x47, + 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xee, 0x01, 0x0a, 0x10, + 0x52, 0x6f, 0x6f, 0x6d, 0x47, 0x75, 0x61, 0x72, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x6f, 0x0a, 0x14, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, + 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x69, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, + 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb9, 0x04, 0x0a, + 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x12, 0x1f, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x56, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x46, 0x65, 0x65, + 0x64, 0x73, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x46, 0x65, 0x65, 0x64, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x47, 0x65, 0x74, + 0x4d, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x52, 0x6f, 0x6f, + 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x24, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, 0x6d, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, + 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x25, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, + 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, + 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, 0x72, 0x6f, 0x6f, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x6f, 0x6f, 0x6d, 0x76, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -5275,14 +5327,14 @@ var file_proto_room_v1_room_proto_goTypes = []any{ (*SetChatEnabledResponse)(nil), // 33: hyapp.room.v1.SetChatEnabledResponse (*SetRoomAdminRequest)(nil), // 34: hyapp.room.v1.SetRoomAdminRequest (*SetRoomAdminResponse)(nil), // 35: hyapp.room.v1.SetRoomAdminResponse - (*TransferRoomHostRequest)(nil), // 36: hyapp.room.v1.TransferRoomHostRequest - (*TransferRoomHostResponse)(nil), // 37: hyapp.room.v1.TransferRoomHostResponse - (*MuteUserRequest)(nil), // 38: hyapp.room.v1.MuteUserRequest - (*MuteUserResponse)(nil), // 39: hyapp.room.v1.MuteUserResponse - (*KickUserRequest)(nil), // 40: hyapp.room.v1.KickUserRequest - (*KickUserResponse)(nil), // 41: hyapp.room.v1.KickUserResponse - (*UnbanUserRequest)(nil), // 42: hyapp.room.v1.UnbanUserRequest - (*UnbanUserResponse)(nil), // 43: hyapp.room.v1.UnbanUserResponse + (*MuteUserRequest)(nil), // 36: hyapp.room.v1.MuteUserRequest + (*MuteUserResponse)(nil), // 37: hyapp.room.v1.MuteUserResponse + (*KickUserRequest)(nil), // 38: hyapp.room.v1.KickUserRequest + (*KickUserResponse)(nil), // 39: hyapp.room.v1.KickUserResponse + (*UnbanUserRequest)(nil), // 40: hyapp.room.v1.UnbanUserRequest + (*UnbanUserResponse)(nil), // 41: hyapp.room.v1.UnbanUserResponse + (*SystemEvictUserRequest)(nil), // 42: hyapp.room.v1.SystemEvictUserRequest + (*SystemEvictUserResponse)(nil), // 43: hyapp.room.v1.SystemEvictUserResponse (*SendGiftRequest)(nil), // 44: hyapp.room.v1.SendGiftRequest (*SendGiftResponse)(nil), // 45: hyapp.room.v1.SendGiftResponse (*CheckSpeakPermissionRequest)(nil), // 46: hyapp.room.v1.CheckSpeakPermissionRequest @@ -5356,18 +5408,18 @@ var file_proto_room_v1_room_proto_depIdxs = []int32{ 0, // 48: hyapp.room.v1.SetRoomAdminRequest.meta:type_name -> hyapp.room.v1.RequestMeta 1, // 49: hyapp.room.v1.SetRoomAdminResponse.result:type_name -> hyapp.room.v1.CommandResult 5, // 50: hyapp.room.v1.SetRoomAdminResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 51: hyapp.room.v1.TransferRoomHostRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 52: hyapp.room.v1.TransferRoomHostResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 53: hyapp.room.v1.TransferRoomHostResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 54: hyapp.room.v1.MuteUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 55: hyapp.room.v1.MuteUserResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 56: hyapp.room.v1.MuteUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 57: hyapp.room.v1.KickUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 58: hyapp.room.v1.KickUserResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 59: hyapp.room.v1.KickUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 60: hyapp.room.v1.UnbanUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 61: hyapp.room.v1.UnbanUserResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 62: hyapp.room.v1.UnbanUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 51: hyapp.room.v1.MuteUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 52: hyapp.room.v1.MuteUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 53: hyapp.room.v1.MuteUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 54: hyapp.room.v1.KickUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 55: hyapp.room.v1.KickUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 56: hyapp.room.v1.KickUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 57: hyapp.room.v1.UnbanUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 58: hyapp.room.v1.UnbanUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 59: hyapp.room.v1.UnbanUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 60: hyapp.room.v1.SystemEvictUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 61: hyapp.room.v1.SystemEvictUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 62: hyapp.room.v1.SystemEvictUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot 0, // 63: hyapp.room.v1.SendGiftRequest.meta:type_name -> hyapp.room.v1.RequestMeta 1, // 64: hyapp.room.v1.SendGiftResponse.result:type_name -> hyapp.room.v1.CommandResult 4, // 65: hyapp.room.v1.SendGiftResponse.gift_rank:type_name -> hyapp.room.v1.RankItem @@ -5398,10 +5450,10 @@ var file_proto_room_v1_room_proto_depIdxs = []int32{ 30, // 90: hyapp.room.v1.RoomCommandService.SetMicSeatLock:input_type -> hyapp.room.v1.SetMicSeatLockRequest 32, // 91: hyapp.room.v1.RoomCommandService.SetChatEnabled:input_type -> hyapp.room.v1.SetChatEnabledRequest 34, // 92: hyapp.room.v1.RoomCommandService.SetRoomAdmin:input_type -> hyapp.room.v1.SetRoomAdminRequest - 36, // 93: hyapp.room.v1.RoomCommandService.TransferRoomHost:input_type -> hyapp.room.v1.TransferRoomHostRequest - 38, // 94: hyapp.room.v1.RoomCommandService.MuteUser:input_type -> hyapp.room.v1.MuteUserRequest - 40, // 95: hyapp.room.v1.RoomCommandService.KickUser:input_type -> hyapp.room.v1.KickUserRequest - 42, // 96: hyapp.room.v1.RoomCommandService.UnbanUser:input_type -> hyapp.room.v1.UnbanUserRequest + 36, // 93: hyapp.room.v1.RoomCommandService.MuteUser:input_type -> hyapp.room.v1.MuteUserRequest + 38, // 94: hyapp.room.v1.RoomCommandService.KickUser:input_type -> hyapp.room.v1.KickUserRequest + 40, // 95: hyapp.room.v1.RoomCommandService.UnbanUser:input_type -> hyapp.room.v1.UnbanUserRequest + 42, // 96: hyapp.room.v1.RoomCommandService.SystemEvictUser:input_type -> hyapp.room.v1.SystemEvictUserRequest 44, // 97: hyapp.room.v1.RoomCommandService.SendGift:input_type -> hyapp.room.v1.SendGiftRequest 46, // 98: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:input_type -> hyapp.room.v1.CheckSpeakPermissionRequest 48, // 99: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:input_type -> hyapp.room.v1.VerifyRoomPresenceRequest @@ -5426,10 +5478,10 @@ var file_proto_room_v1_room_proto_depIdxs = []int32{ 31, // 118: hyapp.room.v1.RoomCommandService.SetMicSeatLock:output_type -> hyapp.room.v1.SetMicSeatLockResponse 33, // 119: hyapp.room.v1.RoomCommandService.SetChatEnabled:output_type -> hyapp.room.v1.SetChatEnabledResponse 35, // 120: hyapp.room.v1.RoomCommandService.SetRoomAdmin:output_type -> hyapp.room.v1.SetRoomAdminResponse - 37, // 121: hyapp.room.v1.RoomCommandService.TransferRoomHost:output_type -> hyapp.room.v1.TransferRoomHostResponse - 39, // 122: hyapp.room.v1.RoomCommandService.MuteUser:output_type -> hyapp.room.v1.MuteUserResponse - 41, // 123: hyapp.room.v1.RoomCommandService.KickUser:output_type -> hyapp.room.v1.KickUserResponse - 43, // 124: hyapp.room.v1.RoomCommandService.UnbanUser:output_type -> hyapp.room.v1.UnbanUserResponse + 37, // 121: hyapp.room.v1.RoomCommandService.MuteUser:output_type -> hyapp.room.v1.MuteUserResponse + 39, // 122: hyapp.room.v1.RoomCommandService.KickUser:output_type -> hyapp.room.v1.KickUserResponse + 41, // 123: hyapp.room.v1.RoomCommandService.UnbanUser:output_type -> hyapp.room.v1.UnbanUserResponse + 43, // 124: hyapp.room.v1.RoomCommandService.SystemEvictUser:output_type -> hyapp.room.v1.SystemEvictUserResponse 45, // 125: hyapp.room.v1.RoomCommandService.SendGift:output_type -> hyapp.room.v1.SendGiftResponse 47, // 126: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:output_type -> hyapp.room.v1.CheckSpeakPermissionResponse 49, // 127: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:output_type -> hyapp.room.v1.VerifyRoomPresenceResponse diff --git a/api/proto/room/v1/room.proto b/api/proto/room/v1/room.proto index 986c08b3..b83ead88 100644 --- a/api/proto/room/v1/room.proto +++ b/api/proto/room/v1/room.proto @@ -65,7 +65,6 @@ message RankItem { message RoomSnapshot { string room_id = 1; int64 owner_user_id = 2; - int64 host_user_id = 3; string mode = 4; string status = 5; bool chat_enabled = 6; @@ -309,18 +308,6 @@ message SetRoomAdminResponse { RoomSnapshot room = 2; } -// TransferRoomHostRequest 把主持人身份转移给房间内用户。 -message TransferRoomHostRequest { - RequestMeta meta = 1; - int64 target_user_id = 2; -} - -// TransferRoomHostResponse 返回主持人转移后的最新房间快照。 -message TransferRoomHostResponse { - CommandResult result = 1; - RoomSnapshot room = 2; -} - // MuteUserRequest 修改房间内禁言态。 message MuteUserRequest { RequestMeta meta = 1; @@ -358,6 +345,27 @@ message UnbanUserResponse { RoomSnapshot room = 2; } +// SystemEvictUserRequest 是平台级封禁、风控或后台治理触发的系统驱逐入口。 +// 该命令仍由 Room Cell 修改房间状态;调用方不能直接写房间 presence 或麦位。 +message SystemEvictUserRequest { + RequestMeta meta = 1; + int64 target_user_id = 2; + int64 operator_user_id = 3; + string reason = 4; + // ban_from_room 为 true 时把用户加入当前房间 ban 集合,防止同一房间恢复入口重新进入。 + bool ban_from_room = 5; +} + +// SystemEvictUserResponse 返回系统驱逐的房间状态和外部 RTC 副作用结果。 +message SystemEvictUserResponse { + bool had_current_room = 1; + CommandResult result = 2; + RoomSnapshot room = 3; + string room_id = 4; + bool rtc_kicked = 5; + string rtc_kick_error = 6; +} + // SendGiftRequest 是首版房间内最重要的变现命令。 message SendGiftRequest { RequestMeta meta = 1; @@ -445,7 +453,6 @@ message RoomFeedRelatedUser { message RoomListItem { string room_id = 1; int64 owner_user_id = 2; - int64 host_user_id = 3; string title = 4; string cover_url = 5; string mode = 6; @@ -549,10 +556,10 @@ service RoomCommandService { rpc SetMicSeatLock(SetMicSeatLockRequest) returns (SetMicSeatLockResponse); rpc SetChatEnabled(SetChatEnabledRequest) returns (SetChatEnabledResponse); rpc SetRoomAdmin(SetRoomAdminRequest) returns (SetRoomAdminResponse); - rpc TransferRoomHost(TransferRoomHostRequest) returns (TransferRoomHostResponse); rpc MuteUser(MuteUserRequest) returns (MuteUserResponse); rpc KickUser(KickUserRequest) returns (KickUserResponse); rpc UnbanUser(UnbanUserRequest) returns (UnbanUserResponse); + rpc SystemEvictUser(SystemEvictUserRequest) returns (SystemEvictUserResponse); rpc SendGift(SendGiftRequest) returns (SendGiftResponse); } diff --git a/api/proto/room/v1/room_grpc.pb.go b/api/proto/room/v1/room_grpc.pb.go index e019a996..b7af8dd2 100644 --- a/api/proto/room/v1/room_grpc.pb.go +++ b/api/proto/room/v1/room_grpc.pb.go @@ -34,10 +34,10 @@ const ( RoomCommandService_SetMicSeatLock_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetMicSeatLock" RoomCommandService_SetChatEnabled_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetChatEnabled" RoomCommandService_SetRoomAdmin_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetRoomAdmin" - RoomCommandService_TransferRoomHost_FullMethodName = "/hyapp.room.v1.RoomCommandService/TransferRoomHost" RoomCommandService_MuteUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/MuteUser" RoomCommandService_KickUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/KickUser" RoomCommandService_UnbanUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/UnbanUser" + RoomCommandService_SystemEvictUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/SystemEvictUser" RoomCommandService_SendGift_FullMethodName = "/hyapp.room.v1.RoomCommandService/SendGift" ) @@ -62,10 +62,10 @@ type RoomCommandServiceClient interface { SetMicSeatLock(ctx context.Context, in *SetMicSeatLockRequest, opts ...grpc.CallOption) (*SetMicSeatLockResponse, error) SetChatEnabled(ctx context.Context, in *SetChatEnabledRequest, opts ...grpc.CallOption) (*SetChatEnabledResponse, error) SetRoomAdmin(ctx context.Context, in *SetRoomAdminRequest, opts ...grpc.CallOption) (*SetRoomAdminResponse, error) - TransferRoomHost(ctx context.Context, in *TransferRoomHostRequest, opts ...grpc.CallOption) (*TransferRoomHostResponse, error) MuteUser(ctx context.Context, in *MuteUserRequest, opts ...grpc.CallOption) (*MuteUserResponse, error) KickUser(ctx context.Context, in *KickUserRequest, opts ...grpc.CallOption) (*KickUserResponse, error) UnbanUser(ctx context.Context, in *UnbanUserRequest, opts ...grpc.CallOption) (*UnbanUserResponse, error) + SystemEvictUser(ctx context.Context, in *SystemEvictUserRequest, opts ...grpc.CallOption) (*SystemEvictUserResponse, error) SendGift(ctx context.Context, in *SendGiftRequest, opts ...grpc.CallOption) (*SendGiftResponse, error) } @@ -227,16 +227,6 @@ func (c *roomCommandServiceClient) SetRoomAdmin(ctx context.Context, in *SetRoom return out, nil } -func (c *roomCommandServiceClient) TransferRoomHost(ctx context.Context, in *TransferRoomHostRequest, opts ...grpc.CallOption) (*TransferRoomHostResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(TransferRoomHostResponse) - err := c.cc.Invoke(ctx, RoomCommandService_TransferRoomHost_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *roomCommandServiceClient) MuteUser(ctx context.Context, in *MuteUserRequest, opts ...grpc.CallOption) (*MuteUserResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(MuteUserResponse) @@ -267,6 +257,16 @@ func (c *roomCommandServiceClient) UnbanUser(ctx context.Context, in *UnbanUserR return out, nil } +func (c *roomCommandServiceClient) SystemEvictUser(ctx context.Context, in *SystemEvictUserRequest, opts ...grpc.CallOption) (*SystemEvictUserResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SystemEvictUserResponse) + err := c.cc.Invoke(ctx, RoomCommandService_SystemEvictUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *roomCommandServiceClient) SendGift(ctx context.Context, in *SendGiftRequest, opts ...grpc.CallOption) (*SendGiftResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(SendGiftResponse) @@ -298,10 +298,10 @@ type RoomCommandServiceServer interface { SetMicSeatLock(context.Context, *SetMicSeatLockRequest) (*SetMicSeatLockResponse, error) SetChatEnabled(context.Context, *SetChatEnabledRequest) (*SetChatEnabledResponse, error) SetRoomAdmin(context.Context, *SetRoomAdminRequest) (*SetRoomAdminResponse, error) - TransferRoomHost(context.Context, *TransferRoomHostRequest) (*TransferRoomHostResponse, error) MuteUser(context.Context, *MuteUserRequest) (*MuteUserResponse, error) KickUser(context.Context, *KickUserRequest) (*KickUserResponse, error) UnbanUser(context.Context, *UnbanUserRequest) (*UnbanUserResponse, error) + SystemEvictUser(context.Context, *SystemEvictUserRequest) (*SystemEvictUserResponse, error) SendGift(context.Context, *SendGiftRequest) (*SendGiftResponse, error) mustEmbedUnimplementedRoomCommandServiceServer() } @@ -358,9 +358,6 @@ func (UnimplementedRoomCommandServiceServer) SetChatEnabled(context.Context, *Se func (UnimplementedRoomCommandServiceServer) SetRoomAdmin(context.Context, *SetRoomAdminRequest) (*SetRoomAdminResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SetRoomAdmin not implemented") } -func (UnimplementedRoomCommandServiceServer) TransferRoomHost(context.Context, *TransferRoomHostRequest) (*TransferRoomHostResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TransferRoomHost not implemented") -} func (UnimplementedRoomCommandServiceServer) MuteUser(context.Context, *MuteUserRequest) (*MuteUserResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method MuteUser not implemented") } @@ -370,6 +367,9 @@ func (UnimplementedRoomCommandServiceServer) KickUser(context.Context, *KickUser func (UnimplementedRoomCommandServiceServer) UnbanUser(context.Context, *UnbanUserRequest) (*UnbanUserResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UnbanUser not implemented") } +func (UnimplementedRoomCommandServiceServer) SystemEvictUser(context.Context, *SystemEvictUserRequest) (*SystemEvictUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SystemEvictUser not implemented") +} func (UnimplementedRoomCommandServiceServer) SendGift(context.Context, *SendGiftRequest) (*SendGiftResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SendGift not implemented") } @@ -664,24 +664,6 @@ func _RoomCommandService_SetRoomAdmin_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } -func _RoomCommandService_TransferRoomHost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TransferRoomHostRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(RoomCommandServiceServer).TransferRoomHost(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: RoomCommandService_TransferRoomHost_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RoomCommandServiceServer).TransferRoomHost(ctx, req.(*TransferRoomHostRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _RoomCommandService_MuteUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MuteUserRequest) if err := dec(in); err != nil { @@ -736,6 +718,24 @@ func _RoomCommandService_UnbanUser_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _RoomCommandService_SystemEvictUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SystemEvictUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoomCommandServiceServer).SystemEvictUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RoomCommandService_SystemEvictUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoomCommandServiceServer).SystemEvictUser(ctx, req.(*SystemEvictUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _RoomCommandService_SendGift_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SendGiftRequest) if err := dec(in); err != nil { @@ -821,10 +821,6 @@ var RoomCommandService_ServiceDesc = grpc.ServiceDesc{ MethodName: "SetRoomAdmin", Handler: _RoomCommandService_SetRoomAdmin_Handler, }, - { - MethodName: "TransferRoomHost", - Handler: _RoomCommandService_TransferRoomHost_Handler, - }, { MethodName: "MuteUser", Handler: _RoomCommandService_MuteUser_Handler, @@ -837,6 +833,10 @@ var RoomCommandService_ServiceDesc = grpc.ServiceDesc{ MethodName: "UnbanUser", Handler: _RoomCommandService_UnbanUser_Handler, }, + { + MethodName: "SystemEvictUser", + Handler: _RoomCommandService_SystemEvictUser_Handler, + }, { MethodName: "SendGift", Handler: _RoomCommandService_SendGift_Handler, diff --git a/api/proto/user/v1/user.pb.go b/api/proto/user/v1/user.pb.go index 08e9140e..babcf7b9 100644 --- a/api/proto/user/v1/user.pb.go +++ b/api/proto/user/v1/user.pb.go @@ -3843,6 +3843,221 @@ func (x *ChangeUserCountryResponse) GetRegionChanged() bool { return false } +// SetUserStatusRequest 是封禁、停用和恢复用户的通用内部入口。 +// 非 active 状态会同步吊销 refresh session,并把仍在有效期内的 access session 写入 gateway denylist。 +type SetUserStatusRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + TargetUserId int64 `protobuf:"varint,2,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + Status UserStatus `protobuf:"varint,3,opt,name=status,proto3,enum=hyapp.user.v1.UserStatus" json:"status,omitempty"` + OperatorUserId int64 `protobuf:"varint,4,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` + Reason string `protobuf:"bytes,5,opt,name=reason,proto3" json:"reason,omitempty"` + // operator_type 区分 admin、app_user、system,避免不同身份体系共用一个整数 ID 后无法追溯。 + OperatorType string `protobuf:"bytes,6,opt,name=operator_type,json=operatorType,proto3" json:"operator_type,omitempty"` +} + +func (x *SetUserStatusRequest) Reset() { + *x = SetUserStatusRequest{} + mi := &file_proto_user_v1_user_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetUserStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetUserStatusRequest) ProtoMessage() {} + +func (x *SetUserStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_v1_user_proto_msgTypes[53] + 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 SetUserStatusRequest.ProtoReflect.Descriptor instead. +func (*SetUserStatusRequest) Descriptor() ([]byte, []int) { + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{53} +} + +func (x *SetUserStatusRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *SetUserStatusRequest) GetTargetUserId() int64 { + if x != nil { + return x.TargetUserId + } + return 0 +} + +func (x *SetUserStatusRequest) GetStatus() UserStatus { + if x != nil { + return x.Status + } + return UserStatus_USER_STATUS_UNSPECIFIED +} + +func (x *SetUserStatusRequest) GetOperatorUserId() int64 { + if x != nil { + return x.OperatorUserId + } + return 0 +} + +func (x *SetUserStatusRequest) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *SetUserStatusRequest) GetOperatorType() string { + if x != nil { + return x.OperatorType + } + return "" +} + +// SetUserStatusResponse 返回用户当前状态和封禁相关副作用结果。 +// 外部副作用字段用于后台或 App 管理入口判断是否需要重试补偿。 +type SetUserStatusResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + RevokedSessionCount int64 `protobuf:"varint,2,opt,name=revoked_session_count,json=revokedSessionCount,proto3" json:"revoked_session_count,omitempty"` + ImKicked bool `protobuf:"varint,3,opt,name=im_kicked,json=imKicked,proto3" json:"im_kicked,omitempty"` + ImKickError string `protobuf:"bytes,4,opt,name=im_kick_error,json=imKickError,proto3" json:"im_kick_error,omitempty"` + RoomEvicted bool `protobuf:"varint,5,opt,name=room_evicted,json=roomEvicted,proto3" json:"room_evicted,omitempty"` + RoomId string `protobuf:"bytes,6,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + RtcKicked bool `protobuf:"varint,7,opt,name=rtc_kicked,json=rtcKicked,proto3" json:"rtc_kicked,omitempty"` + RoomEvictError string `protobuf:"bytes,8,opt,name=room_evict_error,json=roomEvictError,proto3" json:"room_evict_error,omitempty"` + RtcKickError string `protobuf:"bytes,9,opt,name=rtc_kick_error,json=rtcKickError,proto3" json:"rtc_kick_error,omitempty"` + AccessTokenRevoked bool `protobuf:"varint,10,opt,name=access_token_revoked,json=accessTokenRevoked,proto3" json:"access_token_revoked,omitempty"` + AccessTokenRevokeError string `protobuf:"bytes,11,opt,name=access_token_revoke_error,json=accessTokenRevokeError,proto3" json:"access_token_revoke_error,omitempty"` +} + +func (x *SetUserStatusResponse) Reset() { + *x = SetUserStatusResponse{} + mi := &file_proto_user_v1_user_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetUserStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetUserStatusResponse) ProtoMessage() {} + +func (x *SetUserStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_v1_user_proto_msgTypes[54] + 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 SetUserStatusResponse.ProtoReflect.Descriptor instead. +func (*SetUserStatusResponse) Descriptor() ([]byte, []int) { + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{54} +} + +func (x *SetUserStatusResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +func (x *SetUserStatusResponse) GetRevokedSessionCount() int64 { + if x != nil { + return x.RevokedSessionCount + } + return 0 +} + +func (x *SetUserStatusResponse) GetImKicked() bool { + if x != nil { + return x.ImKicked + } + return false +} + +func (x *SetUserStatusResponse) GetImKickError() string { + if x != nil { + return x.ImKickError + } + return "" +} + +func (x *SetUserStatusResponse) GetRoomEvicted() bool { + if x != nil { + return x.RoomEvicted + } + return false +} + +func (x *SetUserStatusResponse) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *SetUserStatusResponse) GetRtcKicked() bool { + if x != nil { + return x.RtcKicked + } + return false +} + +func (x *SetUserStatusResponse) GetRoomEvictError() string { + if x != nil { + return x.RoomEvictError + } + return "" +} + +func (x *SetUserStatusResponse) GetRtcKickError() string { + if x != nil { + return x.RtcKickError + } + return "" +} + +func (x *SetUserStatusResponse) GetAccessTokenRevoked() bool { + if x != nil { + return x.AccessTokenRevoked + } + return false +} + +func (x *SetUserStatusResponse) GetAccessTokenRevokeError() string { + if x != nil { + return x.AccessTokenRevokeError + } + return "" +} + // CompleteOnboardingRequest 是注册页唯一资料提交入口。 type CompleteOnboardingRequest struct { state protoimpl.MessageState @@ -3860,7 +4075,7 @@ type CompleteOnboardingRequest struct { func (x *CompleteOnboardingRequest) Reset() { *x = CompleteOnboardingRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[53] + mi := &file_proto_user_v1_user_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3872,7 +4087,7 @@ func (x *CompleteOnboardingRequest) String() string { func (*CompleteOnboardingRequest) ProtoMessage() {} func (x *CompleteOnboardingRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[53] + mi := &file_proto_user_v1_user_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3885,7 +4100,7 @@ func (x *CompleteOnboardingRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CompleteOnboardingRequest.ProtoReflect.Descriptor instead. func (*CompleteOnboardingRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{53} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{55} } func (x *CompleteOnboardingRequest) GetMeta() *RequestMeta { @@ -3953,7 +4168,7 @@ type CompleteOnboardingResponse struct { func (x *CompleteOnboardingResponse) Reset() { *x = CompleteOnboardingResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[54] + mi := &file_proto_user_v1_user_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3965,7 +4180,7 @@ func (x *CompleteOnboardingResponse) String() string { func (*CompleteOnboardingResponse) ProtoMessage() {} func (x *CompleteOnboardingResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[54] + mi := &file_proto_user_v1_user_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3978,7 +4193,7 @@ func (x *CompleteOnboardingResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CompleteOnboardingResponse.ProtoReflect.Descriptor instead. func (*CompleteOnboardingResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{54} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{56} } func (x *CompleteOnboardingResponse) GetUser() *User { @@ -4043,7 +4258,7 @@ type BindPushTokenRequest struct { func (x *BindPushTokenRequest) Reset() { *x = BindPushTokenRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[55] + mi := &file_proto_user_v1_user_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4055,7 +4270,7 @@ func (x *BindPushTokenRequest) String() string { func (*BindPushTokenRequest) ProtoMessage() {} func (x *BindPushTokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[55] + mi := &file_proto_user_v1_user_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4068,7 +4283,7 @@ func (x *BindPushTokenRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BindPushTokenRequest.ProtoReflect.Descriptor instead. func (*BindPushTokenRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{55} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{57} } func (x *BindPushTokenRequest) GetMeta() *RequestMeta { @@ -4145,7 +4360,7 @@ type BindPushTokenResponse struct { func (x *BindPushTokenResponse) Reset() { *x = BindPushTokenResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[56] + mi := &file_proto_user_v1_user_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4157,7 +4372,7 @@ func (x *BindPushTokenResponse) String() string { func (*BindPushTokenResponse) ProtoMessage() {} func (x *BindPushTokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[56] + mi := &file_proto_user_v1_user_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4170,7 +4385,7 @@ func (x *BindPushTokenResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BindPushTokenResponse.ProtoReflect.Descriptor instead. func (*BindPushTokenResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{56} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{58} } func (x *BindPushTokenResponse) GetBound() bool { @@ -4202,7 +4417,7 @@ type DeletePushTokenRequest struct { func (x *DeletePushTokenRequest) Reset() { *x = DeletePushTokenRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[57] + mi := &file_proto_user_v1_user_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4214,7 +4429,7 @@ func (x *DeletePushTokenRequest) String() string { func (*DeletePushTokenRequest) ProtoMessage() {} func (x *DeletePushTokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[57] + mi := &file_proto_user_v1_user_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4227,7 +4442,7 @@ func (x *DeletePushTokenRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletePushTokenRequest.ProtoReflect.Descriptor instead. func (*DeletePushTokenRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{57} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{59} } func (x *DeletePushTokenRequest) GetMeta() *RequestMeta { @@ -4269,7 +4484,7 @@ type DeletePushTokenResponse struct { func (x *DeletePushTokenResponse) Reset() { *x = DeletePushTokenResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[58] + mi := &file_proto_user_v1_user_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4281,7 +4496,7 @@ func (x *DeletePushTokenResponse) String() string { func (*DeletePushTokenResponse) ProtoMessage() {} func (x *DeletePushTokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[58] + mi := &file_proto_user_v1_user_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4294,7 +4509,7 @@ func (x *DeletePushTokenResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletePushTokenResponse.ProtoReflect.Descriptor instead. func (*DeletePushTokenResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{58} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{60} } func (x *DeletePushTokenResponse) GetDeleted() bool { @@ -4334,7 +4549,7 @@ type Country struct { func (x *Country) Reset() { *x = Country{} - mi := &file_proto_user_v1_user_proto_msgTypes[59] + mi := &file_proto_user_v1_user_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4346,7 +4561,7 @@ func (x *Country) String() string { func (*Country) ProtoMessage() {} func (x *Country) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[59] + mi := &file_proto_user_v1_user_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4359,7 +4574,7 @@ func (x *Country) ProtoReflect() protoreflect.Message { // Deprecated: Use Country.ProtoReflect.Descriptor instead. func (*Country) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{59} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{61} } func (x *Country) GetCountryId() int64 { @@ -4472,7 +4687,7 @@ type Region struct { func (x *Region) Reset() { *x = Region{} - mi := &file_proto_user_v1_user_proto_msgTypes[60] + mi := &file_proto_user_v1_user_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4484,7 +4699,7 @@ func (x *Region) String() string { func (*Region) ProtoMessage() {} func (x *Region) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[60] + mi := &file_proto_user_v1_user_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4497,7 +4712,7 @@ func (x *Region) ProtoReflect() protoreflect.Message { // Deprecated: Use Region.ProtoReflect.Descriptor instead. func (*Region) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{60} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{62} } func (x *Region) GetRegionId() int64 { @@ -4574,7 +4789,7 @@ type ListCountriesRequest struct { func (x *ListCountriesRequest) Reset() { *x = ListCountriesRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[61] + mi := &file_proto_user_v1_user_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4586,7 +4801,7 @@ func (x *ListCountriesRequest) String() string { func (*ListCountriesRequest) ProtoMessage() {} func (x *ListCountriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[61] + mi := &file_proto_user_v1_user_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4599,7 +4814,7 @@ func (x *ListCountriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListCountriesRequest.ProtoReflect.Descriptor instead. func (*ListCountriesRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{61} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{63} } func (x *ListCountriesRequest) GetMeta() *RequestMeta { @@ -4626,7 +4841,7 @@ type ListCountriesResponse struct { func (x *ListCountriesResponse) Reset() { *x = ListCountriesResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[62] + mi := &file_proto_user_v1_user_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4638,7 +4853,7 @@ func (x *ListCountriesResponse) String() string { func (*ListCountriesResponse) ProtoMessage() {} func (x *ListCountriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[62] + mi := &file_proto_user_v1_user_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4651,7 +4866,7 @@ func (x *ListCountriesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListCountriesResponse.ProtoReflect.Descriptor instead. func (*ListCountriesResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{62} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{64} } func (x *ListCountriesResponse) GetCountries() []*Country { @@ -4681,7 +4896,7 @@ type UpdateCountryRequest struct { func (x *UpdateCountryRequest) Reset() { *x = UpdateCountryRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[63] + mi := &file_proto_user_v1_user_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4693,7 +4908,7 @@ func (x *UpdateCountryRequest) String() string { func (*UpdateCountryRequest) ProtoMessage() {} func (x *UpdateCountryRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[63] + mi := &file_proto_user_v1_user_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4706,7 +4921,7 @@ func (x *UpdateCountryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateCountryRequest.ProtoReflect.Descriptor instead. func (*UpdateCountryRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{63} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{65} } func (x *UpdateCountryRequest) GetMeta() *RequestMeta { @@ -4789,7 +5004,7 @@ type CountryResponse struct { func (x *CountryResponse) Reset() { *x = CountryResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[64] + mi := &file_proto_user_v1_user_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4801,7 +5016,7 @@ func (x *CountryResponse) String() string { func (*CountryResponse) ProtoMessage() {} func (x *CountryResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[64] + mi := &file_proto_user_v1_user_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4814,7 +5029,7 @@ func (x *CountryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CountryResponse.ProtoReflect.Descriptor instead. func (*CountryResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{64} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{66} } func (x *CountryResponse) GetCountry() *Country { @@ -4834,7 +5049,7 @@ type ListRegistrationCountriesRequest struct { func (x *ListRegistrationCountriesRequest) Reset() { *x = ListRegistrationCountriesRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[65] + mi := &file_proto_user_v1_user_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4846,7 +5061,7 @@ func (x *ListRegistrationCountriesRequest) String() string { func (*ListRegistrationCountriesRequest) ProtoMessage() {} func (x *ListRegistrationCountriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[65] + mi := &file_proto_user_v1_user_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4859,7 +5074,7 @@ func (x *ListRegistrationCountriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRegistrationCountriesRequest.ProtoReflect.Descriptor instead. func (*ListRegistrationCountriesRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{65} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{67} } func (x *ListRegistrationCountriesRequest) GetMeta() *RequestMeta { @@ -4879,7 +5094,7 @@ type ListRegistrationCountriesResponse struct { func (x *ListRegistrationCountriesResponse) Reset() { *x = ListRegistrationCountriesResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[66] + mi := &file_proto_user_v1_user_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4891,7 +5106,7 @@ func (x *ListRegistrationCountriesResponse) String() string { func (*ListRegistrationCountriesResponse) ProtoMessage() {} func (x *ListRegistrationCountriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[66] + mi := &file_proto_user_v1_user_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4904,7 +5119,7 @@ func (x *ListRegistrationCountriesResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListRegistrationCountriesResponse.ProtoReflect.Descriptor instead. func (*ListRegistrationCountriesResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{66} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{68} } func (x *ListRegistrationCountriesResponse) GetCountries() []*Country { @@ -4925,7 +5140,7 @@ type ListRegionsRequest struct { func (x *ListRegionsRequest) Reset() { *x = ListRegionsRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[67] + mi := &file_proto_user_v1_user_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4937,7 +5152,7 @@ func (x *ListRegionsRequest) String() string { func (*ListRegionsRequest) ProtoMessage() {} func (x *ListRegionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[67] + mi := &file_proto_user_v1_user_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4950,7 +5165,7 @@ func (x *ListRegionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRegionsRequest.ProtoReflect.Descriptor instead. func (*ListRegionsRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{67} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{69} } func (x *ListRegionsRequest) GetMeta() *RequestMeta { @@ -4977,7 +5192,7 @@ type ListRegionsResponse struct { func (x *ListRegionsResponse) Reset() { *x = ListRegionsResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[68] + mi := &file_proto_user_v1_user_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4989,7 +5204,7 @@ func (x *ListRegionsResponse) String() string { func (*ListRegionsResponse) ProtoMessage() {} func (x *ListRegionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[68] + mi := &file_proto_user_v1_user_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5002,7 +5217,7 @@ func (x *ListRegionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRegionsResponse.ProtoReflect.Descriptor instead. func (*ListRegionsResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{68} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{70} } func (x *ListRegionsResponse) GetRegions() []*Region { @@ -5023,7 +5238,7 @@ type GetRegionRequest struct { func (x *GetRegionRequest) Reset() { *x = GetRegionRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[69] + mi := &file_proto_user_v1_user_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5035,7 +5250,7 @@ func (x *GetRegionRequest) String() string { func (*GetRegionRequest) ProtoMessage() {} func (x *GetRegionRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[69] + mi := &file_proto_user_v1_user_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5048,7 +5263,7 @@ func (x *GetRegionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRegionRequest.ProtoReflect.Descriptor instead. func (*GetRegionRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{69} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{71} } func (x *GetRegionRequest) GetMeta() *RequestMeta { @@ -5081,7 +5296,7 @@ type UpdateRegionRequest struct { func (x *UpdateRegionRequest) Reset() { *x = UpdateRegionRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[70] + mi := &file_proto_user_v1_user_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5093,7 +5308,7 @@ func (x *UpdateRegionRequest) String() string { func (*UpdateRegionRequest) ProtoMessage() {} func (x *UpdateRegionRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[70] + mi := &file_proto_user_v1_user_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5106,7 +5321,7 @@ func (x *UpdateRegionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateRegionRequest.ProtoReflect.Descriptor instead. func (*UpdateRegionRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{70} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{72} } func (x *UpdateRegionRequest) GetMeta() *RequestMeta { @@ -5164,7 +5379,7 @@ type ReplaceRegionCountriesRequest struct { func (x *ReplaceRegionCountriesRequest) Reset() { *x = ReplaceRegionCountriesRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[71] + mi := &file_proto_user_v1_user_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5176,7 +5391,7 @@ func (x *ReplaceRegionCountriesRequest) String() string { func (*ReplaceRegionCountriesRequest) ProtoMessage() {} func (x *ReplaceRegionCountriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[71] + mi := &file_proto_user_v1_user_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5189,7 +5404,7 @@ func (x *ReplaceRegionCountriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReplaceRegionCountriesRequest.ProtoReflect.Descriptor instead. func (*ReplaceRegionCountriesRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{71} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{73} } func (x *ReplaceRegionCountriesRequest) GetMeta() *RequestMeta { @@ -5230,7 +5445,7 @@ type RegionResponse struct { func (x *RegionResponse) Reset() { *x = RegionResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[72] + mi := &file_proto_user_v1_user_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5242,7 +5457,7 @@ func (x *RegionResponse) String() string { func (*RegionResponse) ProtoMessage() {} func (x *RegionResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[72] + mi := &file_proto_user_v1_user_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5255,7 +5470,7 @@ func (x *RegionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegionResponse.ProtoReflect.Descriptor instead. func (*RegionResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{72} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{74} } func (x *RegionResponse) GetRegion() *Region { @@ -5282,7 +5497,7 @@ type UserIdentity struct { func (x *UserIdentity) Reset() { *x = UserIdentity{} - mi := &file_proto_user_v1_user_proto_msgTypes[73] + mi := &file_proto_user_v1_user_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5294,7 +5509,7 @@ func (x *UserIdentity) String() string { func (*UserIdentity) ProtoMessage() {} func (x *UserIdentity) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[73] + mi := &file_proto_user_v1_user_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5307,7 +5522,7 @@ func (x *UserIdentity) ProtoReflect() protoreflect.Message { // Deprecated: Use UserIdentity.ProtoReflect.Descriptor instead. func (*UserIdentity) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{73} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{75} } func (x *UserIdentity) GetUserId() int64 { @@ -5371,7 +5586,7 @@ type GetUserIdentityRequest struct { func (x *GetUserIdentityRequest) Reset() { *x = GetUserIdentityRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[74] + mi := &file_proto_user_v1_user_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5383,7 +5598,7 @@ func (x *GetUserIdentityRequest) String() string { func (*GetUserIdentityRequest) ProtoMessage() {} func (x *GetUserIdentityRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[74] + mi := &file_proto_user_v1_user_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5396,7 +5611,7 @@ func (x *GetUserIdentityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUserIdentityRequest.ProtoReflect.Descriptor instead. func (*GetUserIdentityRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{74} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{76} } func (x *GetUserIdentityRequest) GetMeta() *RequestMeta { @@ -5424,7 +5639,7 @@ type GetUserIdentityResponse struct { func (x *GetUserIdentityResponse) Reset() { *x = GetUserIdentityResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[75] + mi := &file_proto_user_v1_user_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5436,7 +5651,7 @@ func (x *GetUserIdentityResponse) String() string { func (*GetUserIdentityResponse) ProtoMessage() {} func (x *GetUserIdentityResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[75] + mi := &file_proto_user_v1_user_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5449,7 +5664,7 @@ func (x *GetUserIdentityResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUserIdentityResponse.ProtoReflect.Descriptor instead. func (*GetUserIdentityResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{75} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{77} } func (x *GetUserIdentityResponse) GetIdentity() *UserIdentity { @@ -5471,7 +5686,7 @@ type ResolveDisplayUserIDRequest struct { func (x *ResolveDisplayUserIDRequest) Reset() { *x = ResolveDisplayUserIDRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[76] + mi := &file_proto_user_v1_user_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5483,7 +5698,7 @@ func (x *ResolveDisplayUserIDRequest) String() string { func (*ResolveDisplayUserIDRequest) ProtoMessage() {} func (x *ResolveDisplayUserIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[76] + mi := &file_proto_user_v1_user_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5496,7 +5711,7 @@ func (x *ResolveDisplayUserIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResolveDisplayUserIDRequest.ProtoReflect.Descriptor instead. func (*ResolveDisplayUserIDRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{76} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{78} } func (x *ResolveDisplayUserIDRequest) GetMeta() *RequestMeta { @@ -5524,7 +5739,7 @@ type ResolveDisplayUserIDResponse struct { func (x *ResolveDisplayUserIDResponse) Reset() { *x = ResolveDisplayUserIDResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[77] + mi := &file_proto_user_v1_user_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5536,7 +5751,7 @@ func (x *ResolveDisplayUserIDResponse) String() string { func (*ResolveDisplayUserIDResponse) ProtoMessage() {} func (x *ResolveDisplayUserIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[77] + mi := &file_proto_user_v1_user_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5549,7 +5764,7 @@ func (x *ResolveDisplayUserIDResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ResolveDisplayUserIDResponse.ProtoReflect.Descriptor instead. func (*ResolveDisplayUserIDResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{77} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{79} } func (x *ResolveDisplayUserIDResponse) GetIdentity() *UserIdentity { @@ -5574,7 +5789,7 @@ type ChangeDisplayUserIDRequest struct { func (x *ChangeDisplayUserIDRequest) Reset() { *x = ChangeDisplayUserIDRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[78] + mi := &file_proto_user_v1_user_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5586,7 +5801,7 @@ func (x *ChangeDisplayUserIDRequest) String() string { func (*ChangeDisplayUserIDRequest) ProtoMessage() {} func (x *ChangeDisplayUserIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[78] + mi := &file_proto_user_v1_user_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5599,7 +5814,7 @@ func (x *ChangeDisplayUserIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeDisplayUserIDRequest.ProtoReflect.Descriptor instead. func (*ChangeDisplayUserIDRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{78} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{80} } func (x *ChangeDisplayUserIDRequest) GetMeta() *RequestMeta { @@ -5648,7 +5863,7 @@ type ChangeDisplayUserIDResponse struct { func (x *ChangeDisplayUserIDResponse) Reset() { *x = ChangeDisplayUserIDResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[79] + mi := &file_proto_user_v1_user_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5660,7 +5875,7 @@ func (x *ChangeDisplayUserIDResponse) String() string { func (*ChangeDisplayUserIDResponse) ProtoMessage() {} func (x *ChangeDisplayUserIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[79] + mi := &file_proto_user_v1_user_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5673,7 +5888,7 @@ func (x *ChangeDisplayUserIDResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeDisplayUserIDResponse.ProtoReflect.Descriptor instead. func (*ChangeDisplayUserIDResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{79} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{81} } func (x *ChangeDisplayUserIDResponse) GetIdentity() *UserIdentity { @@ -5698,7 +5913,7 @@ type ApplyPrettyDisplayUserIDRequest struct { func (x *ApplyPrettyDisplayUserIDRequest) Reset() { *x = ApplyPrettyDisplayUserIDRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[80] + mi := &file_proto_user_v1_user_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5710,7 +5925,7 @@ func (x *ApplyPrettyDisplayUserIDRequest) String() string { func (*ApplyPrettyDisplayUserIDRequest) ProtoMessage() {} func (x *ApplyPrettyDisplayUserIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[80] + mi := &file_proto_user_v1_user_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5723,7 +5938,7 @@ func (x *ApplyPrettyDisplayUserIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyPrettyDisplayUserIDRequest.ProtoReflect.Descriptor instead. func (*ApplyPrettyDisplayUserIDRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{80} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{82} } func (x *ApplyPrettyDisplayUserIDRequest) GetMeta() *RequestMeta { @@ -5773,7 +5988,7 @@ type ApplyPrettyDisplayUserIDResponse struct { func (x *ApplyPrettyDisplayUserIDResponse) Reset() { *x = ApplyPrettyDisplayUserIDResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[81] + mi := &file_proto_user_v1_user_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5785,7 +6000,7 @@ func (x *ApplyPrettyDisplayUserIDResponse) String() string { func (*ApplyPrettyDisplayUserIDResponse) ProtoMessage() {} func (x *ApplyPrettyDisplayUserIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[81] + mi := &file_proto_user_v1_user_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5798,7 +6013,7 @@ func (x *ApplyPrettyDisplayUserIDResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyPrettyDisplayUserIDResponse.ProtoReflect.Descriptor instead. func (*ApplyPrettyDisplayUserIDResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{81} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{83} } func (x *ApplyPrettyDisplayUserIDResponse) GetIdentity() *UserIdentity { @@ -5828,7 +6043,7 @@ type ExpirePrettyDisplayUserIDRequest struct { func (x *ExpirePrettyDisplayUserIDRequest) Reset() { *x = ExpirePrettyDisplayUserIDRequest{} - mi := &file_proto_user_v1_user_proto_msgTypes[82] + mi := &file_proto_user_v1_user_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5840,7 +6055,7 @@ func (x *ExpirePrettyDisplayUserIDRequest) String() string { func (*ExpirePrettyDisplayUserIDRequest) ProtoMessage() {} func (x *ExpirePrettyDisplayUserIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[82] + mi := &file_proto_user_v1_user_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5853,7 +6068,7 @@ func (x *ExpirePrettyDisplayUserIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpirePrettyDisplayUserIDRequest.ProtoReflect.Descriptor instead. func (*ExpirePrettyDisplayUserIDRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{82} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{84} } func (x *ExpirePrettyDisplayUserIDRequest) GetMeta() *RequestMeta { @@ -5888,7 +6103,7 @@ type ExpirePrettyDisplayUserIDResponse struct { func (x *ExpirePrettyDisplayUserIDResponse) Reset() { *x = ExpirePrettyDisplayUserIDResponse{} - mi := &file_proto_user_v1_user_proto_msgTypes[83] + mi := &file_proto_user_v1_user_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5900,7 +6115,7 @@ func (x *ExpirePrettyDisplayUserIDResponse) String() string { func (*ExpirePrettyDisplayUserIDResponse) ProtoMessage() {} func (x *ExpirePrettyDisplayUserIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[83] + mi := &file_proto_user_v1_user_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5913,7 +6128,7 @@ func (x *ExpirePrettyDisplayUserIDResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ExpirePrettyDisplayUserIDResponse.ProtoReflect.Descriptor instead. func (*ExpirePrettyDisplayUserIDResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{83} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{85} } func (x *ExpirePrettyDisplayUserIDResponse) GetIdentity() *UserIdentity { @@ -6538,577 +6753,628 @@ var file_proto_user_v1_user_proto_rawDesc = []byte{ 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x72, 0x65, 0x67, - 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x22, 0xeb, 0x01, 0x0a, 0x19, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, - 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, 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, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, - 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, - 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, - 0x76, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0xbc, 0x02, 0x0a, 0x1a, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, - 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x35, 0x0a, - 0x17, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x4d, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x10, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x2e, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 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, 0x12, 0x34, 0x0a, 0x06, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, - 0x06, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x22, 0xac, 0x02, 0x0a, 0x14, 0x42, 0x69, 0x6e, 0x64, - 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 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, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x73, 0x68, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1f, 0x0a, - 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, - 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x69, - 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, - 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x22, 0x51, 0x0a, 0x15, 0x42, 0x69, 0x6e, 0x64, 0x50, 0x75, - 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, - 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0x9d, 0x01, 0x0a, 0x16, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 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, 0x1b, 0x0a, - 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, - 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x70, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x57, 0x0a, 0x17, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x22, - 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x4d, 0x73, 0x22, 0xbe, 0x03, 0x0a, 0x07, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1d, - 0x0a, 0x0a, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x21, 0x0a, - 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, - 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x64, - 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, - 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, - 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, - 0x72, 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x1d, 0x0a, 0x0a, - 0x69, 0x73, 0x6f, 0x5f, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x33, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x69, 0x73, 0x6f, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x33, 0x12, 0x1f, 0x0a, 0x0b, 0x69, - 0x73, 0x6f, 0x5f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x69, 0x73, 0x6f, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x12, 0x2c, 0x0a, 0x12, - 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, - 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x18, 0x0d, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, - 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, - 0x6f, 0x64, 0x65, 0x22, 0x92, 0x02, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1b, - 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, - 0x72, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x19, 0x0a, - 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x71, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 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, 0x1d, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x08, 0x48, 0x00, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, - 0x0a, 0x0a, 0x08, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x4d, 0x0a, 0x15, 0x4c, - 0x69, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x85, 0x03, 0x0a, 0x14, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x22, 0x86, 0x02, 0x0a, 0x14, 0x53, + 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 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, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, - 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, - 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, - 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x44, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, - 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x6f, 0x5f, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x33, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x73, 0x6f, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x33, 0x12, - 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x6f, 0x5f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x6f, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, - 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, - 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x68, - 0x6f, 0x6e, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, - 0x61, 0x67, 0x22, 0x43, 0x0a, 0x0f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x52, 0x0a, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 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, 0x59, 0x0a, 0x21, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x34, 0x0a, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x5c, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, + 0x65, 0x74, 0x61, 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, 0x31, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x28, 0x0a, 0x10, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x23, + 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x54, + 0x79, 0x70, 0x65, 0x22, 0xcd, 0x03, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, + 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x15, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x64, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6d, + 0x5f, 0x6b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, + 0x6d, 0x4b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x6d, 0x5f, 0x6b, 0x69, + 0x63, 0x6b, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x69, 0x6d, 0x4b, 0x69, 0x63, 0x6b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x72, + 0x6f, 0x6f, 0x6d, 0x5f, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x45, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x12, 0x17, + 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x74, 0x63, 0x5f, 0x6b, + 0x69, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x74, 0x63, + 0x4b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x65, + 0x76, 0x69, 0x63, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x6d, 0x45, 0x76, 0x69, 0x63, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x74, 0x63, 0x5f, 0x6b, 0x69, 0x63, 0x6b, 0x5f, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x74, 0x63, 0x4b, 0x69, 0x63, + 0x6b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x19, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x5f, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x22, 0xeb, 0x01, 0x0a, 0x19, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 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, 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, 0x1a, 0x0a, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x18, + 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x64, + 0x65, 0x22, 0xbc, 0x02, 0x0a, 0x1a, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x27, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x35, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x2b, 0x0a, + 0x11, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2e, 0x0a, 0x05, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x05, 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, 0x12, 0x34, 0x0a, 0x06, 0x69, 0x6e, + 0x76, 0x69, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, + 0x22, 0xac, 0x02, 0x0a, 0x14, 0x42, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 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, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, + 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, + 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x22, + 0x51, 0x0a, 0x15, 0x42, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x22, + 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x73, 0x22, 0x9d, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x75, 0x73, + 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 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, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x22, 0x57, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x75, 0x73, 0x68, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xbe, 0x03, 0x0a, 0x07, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, + 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x14, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x72, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a, + 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, + 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, + 0x6d, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x6f, 0x5f, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x33, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x73, 0x6f, 0x41, 0x6c, + 0x70, 0x68, 0x61, 0x33, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x6f, 0x5f, 0x6e, 0x75, 0x6d, 0x65, + 0x72, 0x69, 0x63, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x6f, 0x4e, 0x75, + 0x6d, 0x65, 0x72, 0x69, 0x63, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x10, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x66, 0x6c, 0x61, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x61, + 0x67, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x92, 0x02, 0x0a, + 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, + 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x22, + 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x5f, 0x6d, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, + 0x65, 0x22, 0x71, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 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, 0x1d, 0x0a, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x22, 0x4d, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, + 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x22, 0x85, 0x03, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x72, 0x79, 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, 0x16, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x22, 0x46, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x72, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, - 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5f, 0x0a, 0x10, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 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, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xe0, 0x01, - 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x30, + 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x72, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, + 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x6f, + 0x5f, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x33, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, + 0x73, 0x6f, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x33, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x6f, 0x5f, + 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, + 0x73, 0x6f, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x22, 0x43, 0x0a, 0x0f, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, + 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, + 0x22, 0x52, 0x0a, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 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, 0x59, 0x0a, 0x21, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, + 0x5c, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 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, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, - 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x46, 0x0a, + 0x13, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 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, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xe0, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 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, 0x1b, + 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, + 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0xb4, 0x01, 0x0a, 0x1d, 0x52, 0x65, + 0x70, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 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, 0x1b, 0x0a, 0x09, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x22, 0xb4, 0x01, 0x0a, 0x1d, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 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, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x28, 0x0a, - 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x3f, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x72, 0x65, 0x67, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, - 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x22, 0xab, 0x02, 0x0a, 0x0c, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 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, 0x26, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x69, 0x73, - 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x69, - 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x44, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x14, 0x64, 0x69, 0x73, - 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x5f, 0x6b, 0x69, 0x6e, - 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x3f, 0x0a, 0x1d, 0x64, 0x69, - 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x5f, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x18, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x61, - 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, - 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x61, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 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, 0x22, 0x52, 0x0a, 0x17, 0x47, 0x65, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x75, 0x0a, - 0x1b, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x44, 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, 0x26, 0x0a, 0x0f, - 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x22, 0x57, 0x0a, 0x1c, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x44, - 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0xd6, 0x01, - 0x0a, 0x1a, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x44, 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, 0x2d, 0x0a, 0x13, 0x6e, 0x65, 0x77, 0x5f, 0x64, 0x69, 0x73, - 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x10, 0x6e, 0x65, 0x77, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, - 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x56, 0x0a, 0x1b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0xf9, - 0x01, 0x0a, 0x1f, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, - 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 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, 0x33, 0x0a, 0x16, 0x70, - 0x72, 0x65, 0x74, 0x74, 0x79, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x72, 0x65, - 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x12, 0x2c, 0x0a, 0x12, - 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x49, 0x64, 0x22, 0x76, 0x0a, 0x20, 0x41, 0x70, - 0x70, 0x6c, 0x79, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x22, 0x3f, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x22, 0xab, 0x02, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 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, 0x26, 0x0a, 0x0f, 0x64, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x14, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x11, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x4b, + 0x69, 0x6e, 0x64, 0x12, 0x3f, 0x0a, 0x1d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, + 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x64, 0x69, 0x73, 0x70, + 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x41, 0x74, 0x4d, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, + 0x61, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 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, 0x22, 0x52, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, + 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x75, 0x0a, 0x1b, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 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, 0x26, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x57, 0x0a, + 0x1c, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, + 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0xd6, 0x01, 0x0a, 0x1a, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 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, 0x2d, + 0x0a, 0x13, 0x6e, 0x65, 0x77, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6e, 0x65, 0x77, + 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, + 0x56, 0x0a, 0x1b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x49, 0x64, 0x22, 0x86, 0x01, 0x0a, 0x20, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, - 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, - 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, 0x19, 0x0a, 0x08, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x22, 0x5c, 0x0a, 0x21, 0x45, - 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, - 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x37, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, - 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2a, 0x73, 0x0a, 0x0a, 0x55, 0x73, 0x65, - 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x53, 0x45, 0x52, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, - 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x44, 0x49, 0x53, 0x41, - 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x42, 0x41, 0x4e, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x32, 0x91, - 0x07, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, - 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x42, 0x75, 0x73, 0x69, - 0x6e, 0x65, 0x73, 0x73, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x12, 0x28, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, - 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, - 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, - 0x73, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0xf9, 0x01, 0x0a, 0x1f, 0x41, 0x70, 0x70, 0x6c, + 0x79, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x44, 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, 0x33, 0x0a, 0x16, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x5f, 0x64, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, + 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, + 0x74, 0x49, 0x64, 0x22, 0x76, 0x0a, 0x20, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x65, 0x74, + 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x22, 0x86, 0x01, 0x0a, 0x20, + 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, + 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 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, 0x19, 0x0a, 0x08, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x49, 0x64, 0x22, 0x5c, 0x0a, 0x21, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, + 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x2a, 0x73, 0x0a, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, + 0x12, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, + 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, + 0x16, 0x0a, 0x12, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x42, + 0x41, 0x4e, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x32, 0xed, 0x07, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x69, 0x0a, 0x12, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x55, 0x73, 0x65, + 0x72, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, + 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, + 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x11, + 0x47, 0x65, 0x74, 0x4d, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x73, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x42, - 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x23, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, - 0x17, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x69, 0x63, 0x4c, 0x69, 0x66, 0x65, 0x74, - 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x4d, 0x69, 0x63, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4d, - 0x69, 0x63, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, + 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, + 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x12, + 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x4d, 0x69, 0x63, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x73, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x69, 0x63, 0x4c, 0x69, 0x66, 0x65, + 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x69, 0x63, 0x4c, 0x69, 0x66, 0x65, 0x74, + 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x66, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x66, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, + 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, - 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x32, 0xea, 0x07, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x72, 0x53, 0x6f, 0x63, 0x69, 0x61, - 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, 0x12, 0x28, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x56, 0x69, 0x73, 0x69, - 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, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x5a, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, + 0x6e, 0x67, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xea, 0x07, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x72, + 0x53, 0x6f, 0x63, 0x69, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, + 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x56, 0x69, + 0x73, 0x69, 0x74, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x56, 0x69, 0x73, 0x69, 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, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, + 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x12, + 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x73, 0x65, 0x72, 0x12, - 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x55, 0x6e, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, - 0x55, 0x73, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, - 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, - 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x12, 0x23, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x55, 0x6e, 0x66, + 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x73, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x66, 0x6f, 0x6c, 0x6c, + 0x6f, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, + 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, + 0x69, 0x6e, 0x67, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, - 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x41, 0x70, 0x70, - 0x6c, 0x79, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x46, 0x72, - 0x69, 0x65, 0x6e, 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, 0x41, 0x70, 0x70, 0x6c, - 0x79, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x78, 0x0a, 0x17, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, - 0x73, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, - 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, - 0xaf, 0x02, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x43, 0x72, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x5c, 0x0a, 0x17, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, - 0x67, 0x69, 0x6e, 0x49, 0x50, 0x52, 0x69, 0x73, 0x6b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1f, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x5e, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x67, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1f, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x5e, 0x0a, 0x19, 0x43, 0x6f, 0x6d, 0x70, 0x65, 0x6e, 0x73, 0x61, 0x74, 0x65, 0x4d, - 0x69, 0x63, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x32, 0xd1, 0x01, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x42, 0x69, 0x6e, 0x64, 0x50, - 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x73, - 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, + 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x6f, 0x6c, + 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, + 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, + 0x70, 0x6c, 0x79, 0x46, 0x72, 0x69, 0x65, 0x6e, 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, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x17, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x46, 0x72, + 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x63, 0x63, 0x65, 0x70, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, + 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x22, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x46, + 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, + 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, + 0x69, 0x65, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, + 0x16, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xaf, 0x02, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x43, 0x72, 0x6f, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5c, 0x0a, 0x17, 0x50, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x49, 0x50, 0x52, 0x69, 0x73, 0x6b, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x19, 0x43, 0x6f, 0x6d, 0x70, 0x65, 0x6e, + 0x73, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x63, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xd1, 0x01, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x72, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5a, 0x0a, 0x0d, + 0x42, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, - 0x6e, 0x64, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x75, 0x73, - 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x75, 0x73, - 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x67, 0x0a, 0x12, 0x41, 0x70, 0x70, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x52, - 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x70, 0x70, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, - 0x65, 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x6c, 0x76, 0x65, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc7, - 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x95, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x72, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x7e, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2f, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0xf1, 0x02, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x6d, 0x69, 0x6e, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, - 0x09, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0c, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x22, 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, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, + 0x6e, 0x64, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x25, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x75, 0x73, 0x68, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x67, 0x0a, 0x12, 0x41, 0x70, + 0x70, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x51, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x70, 0x70, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, - 0x16, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x52, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xd3, 0x04, 0x0a, 0x13, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x60, 0x0a, 0x0f, - 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, - 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, - 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x44, 0x69, - 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, - 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x6c, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, + 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x32, 0xc7, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x4c, + 0x69, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x95, 0x01, + 0x0a, 0x13, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 0x12, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xf1, 0x02, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x54, 0x0a, 0x0b, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, + 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x51, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, + 0x22, 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, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x65, 0x0a, 0x16, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, + 0x6c, 0x61, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xd3, 0x04, 0x0a, 0x13, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x44, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2a, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x44, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x29, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x69, 0x73, - 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, - 0x18, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, - 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, - 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x19, 0x45, 0x78, + 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x18, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x65, 0x74, 0x74, + 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2e, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x70, 0x70, 0x6c, 0x79, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x7e, 0x0a, 0x19, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2f, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, - 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, 0x72, - 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x50, - 0x72, 0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x44, 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, + 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 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 ( @@ -7124,7 +7390,7 @@ func file_proto_user_v1_user_proto_rawDescGZIP() []byte { } var file_proto_user_v1_user_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_user_v1_user_proto_msgTypes = make([]protoimpl.MessageInfo, 85) +var file_proto_user_v1_user_proto_msgTypes = make([]protoimpl.MessageInfo, 87) var file_proto_user_v1_user_proto_goTypes = []any{ (UserStatus)(0), // 0: hyapp.user.v1.UserStatus (*RequestMeta)(nil), // 1: hyapp.user.v1.RequestMeta @@ -7180,38 +7446,40 @@ var file_proto_user_v1_user_proto_goTypes = []any{ (*UpdateUserProfileResponse)(nil), // 51: hyapp.user.v1.UpdateUserProfileResponse (*ChangeUserCountryRequest)(nil), // 52: hyapp.user.v1.ChangeUserCountryRequest (*ChangeUserCountryResponse)(nil), // 53: hyapp.user.v1.ChangeUserCountryResponse - (*CompleteOnboardingRequest)(nil), // 54: hyapp.user.v1.CompleteOnboardingRequest - (*CompleteOnboardingResponse)(nil), // 55: hyapp.user.v1.CompleteOnboardingResponse - (*BindPushTokenRequest)(nil), // 56: hyapp.user.v1.BindPushTokenRequest - (*BindPushTokenResponse)(nil), // 57: hyapp.user.v1.BindPushTokenResponse - (*DeletePushTokenRequest)(nil), // 58: hyapp.user.v1.DeletePushTokenRequest - (*DeletePushTokenResponse)(nil), // 59: hyapp.user.v1.DeletePushTokenResponse - (*Country)(nil), // 60: hyapp.user.v1.Country - (*Region)(nil), // 61: hyapp.user.v1.Region - (*ListCountriesRequest)(nil), // 62: hyapp.user.v1.ListCountriesRequest - (*ListCountriesResponse)(nil), // 63: hyapp.user.v1.ListCountriesResponse - (*UpdateCountryRequest)(nil), // 64: hyapp.user.v1.UpdateCountryRequest - (*CountryResponse)(nil), // 65: hyapp.user.v1.CountryResponse - (*ListRegistrationCountriesRequest)(nil), // 66: hyapp.user.v1.ListRegistrationCountriesRequest - (*ListRegistrationCountriesResponse)(nil), // 67: hyapp.user.v1.ListRegistrationCountriesResponse - (*ListRegionsRequest)(nil), // 68: hyapp.user.v1.ListRegionsRequest - (*ListRegionsResponse)(nil), // 69: hyapp.user.v1.ListRegionsResponse - (*GetRegionRequest)(nil), // 70: hyapp.user.v1.GetRegionRequest - (*UpdateRegionRequest)(nil), // 71: hyapp.user.v1.UpdateRegionRequest - (*ReplaceRegionCountriesRequest)(nil), // 72: hyapp.user.v1.ReplaceRegionCountriesRequest - (*RegionResponse)(nil), // 73: hyapp.user.v1.RegionResponse - (*UserIdentity)(nil), // 74: hyapp.user.v1.UserIdentity - (*GetUserIdentityRequest)(nil), // 75: hyapp.user.v1.GetUserIdentityRequest - (*GetUserIdentityResponse)(nil), // 76: hyapp.user.v1.GetUserIdentityResponse - (*ResolveDisplayUserIDRequest)(nil), // 77: hyapp.user.v1.ResolveDisplayUserIDRequest - (*ResolveDisplayUserIDResponse)(nil), // 78: hyapp.user.v1.ResolveDisplayUserIDResponse - (*ChangeDisplayUserIDRequest)(nil), // 79: hyapp.user.v1.ChangeDisplayUserIDRequest - (*ChangeDisplayUserIDResponse)(nil), // 80: hyapp.user.v1.ChangeDisplayUserIDResponse - (*ApplyPrettyDisplayUserIDRequest)(nil), // 81: hyapp.user.v1.ApplyPrettyDisplayUserIDRequest - (*ApplyPrettyDisplayUserIDResponse)(nil), // 82: hyapp.user.v1.ApplyPrettyDisplayUserIDResponse - (*ExpirePrettyDisplayUserIDRequest)(nil), // 83: hyapp.user.v1.ExpirePrettyDisplayUserIDRequest - (*ExpirePrettyDisplayUserIDResponse)(nil), // 84: hyapp.user.v1.ExpirePrettyDisplayUserIDResponse - nil, // 85: hyapp.user.v1.BatchGetUsersResponse.UsersEntry + (*SetUserStatusRequest)(nil), // 54: hyapp.user.v1.SetUserStatusRequest + (*SetUserStatusResponse)(nil), // 55: hyapp.user.v1.SetUserStatusResponse + (*CompleteOnboardingRequest)(nil), // 56: hyapp.user.v1.CompleteOnboardingRequest + (*CompleteOnboardingResponse)(nil), // 57: hyapp.user.v1.CompleteOnboardingResponse + (*BindPushTokenRequest)(nil), // 58: hyapp.user.v1.BindPushTokenRequest + (*BindPushTokenResponse)(nil), // 59: hyapp.user.v1.BindPushTokenResponse + (*DeletePushTokenRequest)(nil), // 60: hyapp.user.v1.DeletePushTokenRequest + (*DeletePushTokenResponse)(nil), // 61: hyapp.user.v1.DeletePushTokenResponse + (*Country)(nil), // 62: hyapp.user.v1.Country + (*Region)(nil), // 63: hyapp.user.v1.Region + (*ListCountriesRequest)(nil), // 64: hyapp.user.v1.ListCountriesRequest + (*ListCountriesResponse)(nil), // 65: hyapp.user.v1.ListCountriesResponse + (*UpdateCountryRequest)(nil), // 66: hyapp.user.v1.UpdateCountryRequest + (*CountryResponse)(nil), // 67: hyapp.user.v1.CountryResponse + (*ListRegistrationCountriesRequest)(nil), // 68: hyapp.user.v1.ListRegistrationCountriesRequest + (*ListRegistrationCountriesResponse)(nil), // 69: hyapp.user.v1.ListRegistrationCountriesResponse + (*ListRegionsRequest)(nil), // 70: hyapp.user.v1.ListRegionsRequest + (*ListRegionsResponse)(nil), // 71: hyapp.user.v1.ListRegionsResponse + (*GetRegionRequest)(nil), // 72: hyapp.user.v1.GetRegionRequest + (*UpdateRegionRequest)(nil), // 73: hyapp.user.v1.UpdateRegionRequest + (*ReplaceRegionCountriesRequest)(nil), // 74: hyapp.user.v1.ReplaceRegionCountriesRequest + (*RegionResponse)(nil), // 75: hyapp.user.v1.RegionResponse + (*UserIdentity)(nil), // 76: hyapp.user.v1.UserIdentity + (*GetUserIdentityRequest)(nil), // 77: hyapp.user.v1.GetUserIdentityRequest + (*GetUserIdentityResponse)(nil), // 78: hyapp.user.v1.GetUserIdentityResponse + (*ResolveDisplayUserIDRequest)(nil), // 79: hyapp.user.v1.ResolveDisplayUserIDRequest + (*ResolveDisplayUserIDResponse)(nil), // 80: hyapp.user.v1.ResolveDisplayUserIDResponse + (*ChangeDisplayUserIDRequest)(nil), // 81: hyapp.user.v1.ChangeDisplayUserIDRequest + (*ChangeDisplayUserIDResponse)(nil), // 82: hyapp.user.v1.ChangeDisplayUserIDResponse + (*ApplyPrettyDisplayUserIDRequest)(nil), // 83: hyapp.user.v1.ApplyPrettyDisplayUserIDRequest + (*ApplyPrettyDisplayUserIDResponse)(nil), // 84: hyapp.user.v1.ApplyPrettyDisplayUserIDResponse + (*ExpirePrettyDisplayUserIDRequest)(nil), // 85: hyapp.user.v1.ExpirePrettyDisplayUserIDRequest + (*ExpirePrettyDisplayUserIDResponse)(nil), // 86: hyapp.user.v1.ExpirePrettyDisplayUserIDResponse + nil, // 87: hyapp.user.v1.BatchGetUsersResponse.UsersEntry } var file_proto_user_v1_user_proto_depIdxs = []int32{ 1, // 0: hyapp.user.v1.ResolveAppRequest.meta:type_name -> hyapp.user.v1.RequestMeta @@ -7248,120 +7516,125 @@ var file_proto_user_v1_user_proto_depIdxs = []int32{ 1, // 31: hyapp.user.v1.ListFriendApplicationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta 43, // 32: hyapp.user.v1.ListFriendApplicationsResponse.applications:type_name -> hyapp.user.v1.FriendApplication 1, // 33: hyapp.user.v1.BatchGetUsersRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 85, // 34: hyapp.user.v1.BatchGetUsersResponse.users:type_name -> hyapp.user.v1.BatchGetUsersResponse.UsersEntry + 87, // 34: hyapp.user.v1.BatchGetUsersResponse.users:type_name -> hyapp.user.v1.BatchGetUsersResponse.UsersEntry 1, // 35: hyapp.user.v1.ListUserIDsRequest.meta:type_name -> hyapp.user.v1.RequestMeta 1, // 36: hyapp.user.v1.UpdateUserProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta 5, // 37: hyapp.user.v1.UpdateUserProfileResponse.user:type_name -> hyapp.user.v1.User 1, // 38: hyapp.user.v1.ChangeUserCountryRequest.meta:type_name -> hyapp.user.v1.RequestMeta 5, // 39: hyapp.user.v1.ChangeUserCountryResponse.user:type_name -> hyapp.user.v1.User - 1, // 40: hyapp.user.v1.CompleteOnboardingRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 5, // 41: hyapp.user.v1.CompleteOnboardingResponse.user:type_name -> hyapp.user.v1.User - 13, // 42: hyapp.user.v1.CompleteOnboardingResponse.token:type_name -> hyapp.user.v1.AuthToken - 7, // 43: hyapp.user.v1.CompleteOnboardingResponse.invite:type_name -> hyapp.user.v1.InviteBinding - 1, // 44: hyapp.user.v1.BindPushTokenRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 1, // 45: hyapp.user.v1.DeletePushTokenRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 1, // 46: hyapp.user.v1.ListCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 60, // 47: hyapp.user.v1.ListCountriesResponse.countries:type_name -> hyapp.user.v1.Country - 1, // 48: hyapp.user.v1.UpdateCountryRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 60, // 49: hyapp.user.v1.CountryResponse.country:type_name -> hyapp.user.v1.Country - 1, // 50: hyapp.user.v1.ListRegistrationCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 60, // 51: hyapp.user.v1.ListRegistrationCountriesResponse.countries:type_name -> hyapp.user.v1.Country - 1, // 52: hyapp.user.v1.ListRegionsRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 61, // 53: hyapp.user.v1.ListRegionsResponse.regions:type_name -> hyapp.user.v1.Region - 1, // 54: hyapp.user.v1.GetRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 1, // 55: hyapp.user.v1.UpdateRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 1, // 56: hyapp.user.v1.ReplaceRegionCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 61, // 57: hyapp.user.v1.RegionResponse.region:type_name -> hyapp.user.v1.Region - 1, // 58: hyapp.user.v1.GetUserIdentityRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 74, // 59: hyapp.user.v1.GetUserIdentityResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 1, // 60: hyapp.user.v1.ResolveDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 74, // 61: hyapp.user.v1.ResolveDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 1, // 62: hyapp.user.v1.ChangeDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 74, // 63: hyapp.user.v1.ChangeDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 1, // 64: hyapp.user.v1.ApplyPrettyDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 74, // 65: hyapp.user.v1.ApplyPrettyDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 1, // 66: hyapp.user.v1.ExpirePrettyDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 74, // 67: hyapp.user.v1.ExpirePrettyDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 5, // 68: hyapp.user.v1.BatchGetUsersResponse.UsersEntry.value:type_name -> hyapp.user.v1.User - 14, // 69: hyapp.user.v1.UserService.GetUser:input_type -> hyapp.user.v1.GetUserRequest - 16, // 70: hyapp.user.v1.UserService.BusinessUserLookup:input_type -> hyapp.user.v1.BusinessUserLookupRequest - 20, // 71: hyapp.user.v1.UserService.GetMyProfileStats:input_type -> hyapp.user.v1.GetMyProfileStatsRequest - 46, // 72: hyapp.user.v1.UserService.BatchGetUsers:input_type -> hyapp.user.v1.BatchGetUsersRequest - 48, // 73: hyapp.user.v1.UserService.ListUserIDs:input_type -> hyapp.user.v1.ListUserIDsRequest - 9, // 74: hyapp.user.v1.UserService.GetUserMicLifetimeStats:input_type -> hyapp.user.v1.GetUserMicLifetimeStatsRequest - 50, // 75: hyapp.user.v1.UserService.UpdateUserProfile:input_type -> hyapp.user.v1.UpdateUserProfileRequest - 52, // 76: hyapp.user.v1.UserService.ChangeUserCountry:input_type -> hyapp.user.v1.ChangeUserCountryRequest - 54, // 77: hyapp.user.v1.UserService.CompleteOnboarding:input_type -> hyapp.user.v1.CompleteOnboardingRequest - 22, // 78: hyapp.user.v1.UserSocialService.RecordProfileVisit:input_type -> hyapp.user.v1.RecordProfileVisitRequest - 25, // 79: hyapp.user.v1.UserSocialService.ListProfileVisitors:input_type -> hyapp.user.v1.ListProfileVisitorsRequest - 27, // 80: hyapp.user.v1.UserSocialService.FollowUser:input_type -> hyapp.user.v1.FollowUserRequest - 29, // 81: hyapp.user.v1.UserSocialService.UnfollowUser:input_type -> hyapp.user.v1.UnfollowUserRequest - 32, // 82: hyapp.user.v1.UserSocialService.ListFollowing:input_type -> hyapp.user.v1.ListFollowingRequest - 34, // 83: hyapp.user.v1.UserSocialService.ApplyFriend:input_type -> hyapp.user.v1.ApplyFriendRequest - 36, // 84: hyapp.user.v1.UserSocialService.AcceptFriendApplication:input_type -> hyapp.user.v1.AcceptFriendApplicationRequest - 38, // 85: hyapp.user.v1.UserSocialService.DeleteFriend:input_type -> hyapp.user.v1.DeleteFriendRequest - 41, // 86: hyapp.user.v1.UserSocialService.ListFriends:input_type -> hyapp.user.v1.ListFriendsRequest - 44, // 87: hyapp.user.v1.UserSocialService.ListFriendApplications:input_type -> hyapp.user.v1.ListFriendApplicationsRequest - 11, // 88: hyapp.user.v1.UserCronService.ProcessLoginIPRiskBatch:input_type -> hyapp.user.v1.CronBatchRequest - 11, // 89: hyapp.user.v1.UserCronService.ProcessRegionRebuildBatch:input_type -> hyapp.user.v1.CronBatchRequest - 11, // 90: hyapp.user.v1.UserCronService.CompensateMicOpenSessions:input_type -> hyapp.user.v1.CronBatchRequest - 56, // 91: hyapp.user.v1.UserDeviceService.BindPushToken:input_type -> hyapp.user.v1.BindPushTokenRequest - 58, // 92: hyapp.user.v1.UserDeviceService.DeletePushToken:input_type -> hyapp.user.v1.DeletePushTokenRequest - 3, // 93: hyapp.user.v1.AppRegistryService.ResolveApp:input_type -> hyapp.user.v1.ResolveAppRequest - 62, // 94: hyapp.user.v1.CountryAdminService.ListCountries:input_type -> hyapp.user.v1.ListCountriesRequest - 64, // 95: hyapp.user.v1.CountryAdminService.UpdateCountry:input_type -> hyapp.user.v1.UpdateCountryRequest - 66, // 96: hyapp.user.v1.CountryQueryService.ListRegistrationCountries:input_type -> hyapp.user.v1.ListRegistrationCountriesRequest - 68, // 97: hyapp.user.v1.RegionAdminService.ListRegions:input_type -> hyapp.user.v1.ListRegionsRequest - 70, // 98: hyapp.user.v1.RegionAdminService.GetRegion:input_type -> hyapp.user.v1.GetRegionRequest - 71, // 99: hyapp.user.v1.RegionAdminService.UpdateRegion:input_type -> hyapp.user.v1.UpdateRegionRequest - 72, // 100: hyapp.user.v1.RegionAdminService.ReplaceRegionCountries:input_type -> hyapp.user.v1.ReplaceRegionCountriesRequest - 75, // 101: hyapp.user.v1.UserIdentityService.GetUserIdentity:input_type -> hyapp.user.v1.GetUserIdentityRequest - 77, // 102: hyapp.user.v1.UserIdentityService.ResolveDisplayUserID:input_type -> hyapp.user.v1.ResolveDisplayUserIDRequest - 79, // 103: hyapp.user.v1.UserIdentityService.ChangeDisplayUserID:input_type -> hyapp.user.v1.ChangeDisplayUserIDRequest - 81, // 104: hyapp.user.v1.UserIdentityService.ApplyPrettyDisplayUserID:input_type -> hyapp.user.v1.ApplyPrettyDisplayUserIDRequest - 83, // 105: hyapp.user.v1.UserIdentityService.ExpirePrettyDisplayUserID:input_type -> hyapp.user.v1.ExpirePrettyDisplayUserIDRequest - 15, // 106: hyapp.user.v1.UserService.GetUser:output_type -> hyapp.user.v1.GetUserResponse - 18, // 107: hyapp.user.v1.UserService.BusinessUserLookup:output_type -> hyapp.user.v1.BusinessUserLookupResponse - 21, // 108: hyapp.user.v1.UserService.GetMyProfileStats:output_type -> hyapp.user.v1.GetMyProfileStatsResponse - 47, // 109: hyapp.user.v1.UserService.BatchGetUsers:output_type -> hyapp.user.v1.BatchGetUsersResponse - 49, // 110: hyapp.user.v1.UserService.ListUserIDs:output_type -> hyapp.user.v1.ListUserIDsResponse - 10, // 111: hyapp.user.v1.UserService.GetUserMicLifetimeStats:output_type -> hyapp.user.v1.GetUserMicLifetimeStatsResponse - 51, // 112: hyapp.user.v1.UserService.UpdateUserProfile:output_type -> hyapp.user.v1.UpdateUserProfileResponse - 53, // 113: hyapp.user.v1.UserService.ChangeUserCountry:output_type -> hyapp.user.v1.ChangeUserCountryResponse - 55, // 114: hyapp.user.v1.UserService.CompleteOnboarding:output_type -> hyapp.user.v1.CompleteOnboardingResponse - 23, // 115: hyapp.user.v1.UserSocialService.RecordProfileVisit:output_type -> hyapp.user.v1.RecordProfileVisitResponse - 26, // 116: hyapp.user.v1.UserSocialService.ListProfileVisitors:output_type -> hyapp.user.v1.ListProfileVisitorsResponse - 28, // 117: hyapp.user.v1.UserSocialService.FollowUser:output_type -> hyapp.user.v1.FollowUserResponse - 30, // 118: hyapp.user.v1.UserSocialService.UnfollowUser:output_type -> hyapp.user.v1.UnfollowUserResponse - 33, // 119: hyapp.user.v1.UserSocialService.ListFollowing:output_type -> hyapp.user.v1.ListFollowingResponse - 35, // 120: hyapp.user.v1.UserSocialService.ApplyFriend:output_type -> hyapp.user.v1.ApplyFriendResponse - 37, // 121: hyapp.user.v1.UserSocialService.AcceptFriendApplication:output_type -> hyapp.user.v1.AcceptFriendApplicationResponse - 39, // 122: hyapp.user.v1.UserSocialService.DeleteFriend:output_type -> hyapp.user.v1.DeleteFriendResponse - 42, // 123: hyapp.user.v1.UserSocialService.ListFriends:output_type -> hyapp.user.v1.ListFriendsResponse - 45, // 124: hyapp.user.v1.UserSocialService.ListFriendApplications:output_type -> hyapp.user.v1.ListFriendApplicationsResponse - 12, // 125: hyapp.user.v1.UserCronService.ProcessLoginIPRiskBatch:output_type -> hyapp.user.v1.CronBatchResponse - 12, // 126: hyapp.user.v1.UserCronService.ProcessRegionRebuildBatch:output_type -> hyapp.user.v1.CronBatchResponse - 12, // 127: hyapp.user.v1.UserCronService.CompensateMicOpenSessions:output_type -> hyapp.user.v1.CronBatchResponse - 57, // 128: hyapp.user.v1.UserDeviceService.BindPushToken:output_type -> hyapp.user.v1.BindPushTokenResponse - 59, // 129: hyapp.user.v1.UserDeviceService.DeletePushToken:output_type -> hyapp.user.v1.DeletePushTokenResponse - 4, // 130: hyapp.user.v1.AppRegistryService.ResolveApp:output_type -> hyapp.user.v1.ResolveAppResponse - 63, // 131: hyapp.user.v1.CountryAdminService.ListCountries:output_type -> hyapp.user.v1.ListCountriesResponse - 65, // 132: hyapp.user.v1.CountryAdminService.UpdateCountry:output_type -> hyapp.user.v1.CountryResponse - 67, // 133: hyapp.user.v1.CountryQueryService.ListRegistrationCountries:output_type -> hyapp.user.v1.ListRegistrationCountriesResponse - 69, // 134: hyapp.user.v1.RegionAdminService.ListRegions:output_type -> hyapp.user.v1.ListRegionsResponse - 73, // 135: hyapp.user.v1.RegionAdminService.GetRegion:output_type -> hyapp.user.v1.RegionResponse - 73, // 136: hyapp.user.v1.RegionAdminService.UpdateRegion:output_type -> hyapp.user.v1.RegionResponse - 73, // 137: hyapp.user.v1.RegionAdminService.ReplaceRegionCountries:output_type -> hyapp.user.v1.RegionResponse - 76, // 138: hyapp.user.v1.UserIdentityService.GetUserIdentity:output_type -> hyapp.user.v1.GetUserIdentityResponse - 78, // 139: hyapp.user.v1.UserIdentityService.ResolveDisplayUserID:output_type -> hyapp.user.v1.ResolveDisplayUserIDResponse - 80, // 140: hyapp.user.v1.UserIdentityService.ChangeDisplayUserID:output_type -> hyapp.user.v1.ChangeDisplayUserIDResponse - 82, // 141: hyapp.user.v1.UserIdentityService.ApplyPrettyDisplayUserID:output_type -> hyapp.user.v1.ApplyPrettyDisplayUserIDResponse - 84, // 142: hyapp.user.v1.UserIdentityService.ExpirePrettyDisplayUserID:output_type -> hyapp.user.v1.ExpirePrettyDisplayUserIDResponse - 106, // [106:143] is the sub-list for method output_type - 69, // [69:106] is the sub-list for method input_type - 69, // [69:69] is the sub-list for extension type_name - 69, // [69:69] is the sub-list for extension extendee - 0, // [0:69] is the sub-list for field type_name + 1, // 40: hyapp.user.v1.SetUserStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 0, // 41: hyapp.user.v1.SetUserStatusRequest.status:type_name -> hyapp.user.v1.UserStatus + 5, // 42: hyapp.user.v1.SetUserStatusResponse.user:type_name -> hyapp.user.v1.User + 1, // 43: hyapp.user.v1.CompleteOnboardingRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 5, // 44: hyapp.user.v1.CompleteOnboardingResponse.user:type_name -> hyapp.user.v1.User + 13, // 45: hyapp.user.v1.CompleteOnboardingResponse.token:type_name -> hyapp.user.v1.AuthToken + 7, // 46: hyapp.user.v1.CompleteOnboardingResponse.invite:type_name -> hyapp.user.v1.InviteBinding + 1, // 47: hyapp.user.v1.BindPushTokenRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 48: hyapp.user.v1.DeletePushTokenRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 49: hyapp.user.v1.ListCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 62, // 50: hyapp.user.v1.ListCountriesResponse.countries:type_name -> hyapp.user.v1.Country + 1, // 51: hyapp.user.v1.UpdateCountryRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 62, // 52: hyapp.user.v1.CountryResponse.country:type_name -> hyapp.user.v1.Country + 1, // 53: hyapp.user.v1.ListRegistrationCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 62, // 54: hyapp.user.v1.ListRegistrationCountriesResponse.countries:type_name -> hyapp.user.v1.Country + 1, // 55: hyapp.user.v1.ListRegionsRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 63, // 56: hyapp.user.v1.ListRegionsResponse.regions:type_name -> hyapp.user.v1.Region + 1, // 57: hyapp.user.v1.GetRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 58: hyapp.user.v1.UpdateRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 59: hyapp.user.v1.ReplaceRegionCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 63, // 60: hyapp.user.v1.RegionResponse.region:type_name -> hyapp.user.v1.Region + 1, // 61: hyapp.user.v1.GetUserIdentityRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 76, // 62: hyapp.user.v1.GetUserIdentityResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 1, // 63: hyapp.user.v1.ResolveDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 76, // 64: hyapp.user.v1.ResolveDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 1, // 65: hyapp.user.v1.ChangeDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 76, // 66: hyapp.user.v1.ChangeDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 1, // 67: hyapp.user.v1.ApplyPrettyDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 76, // 68: hyapp.user.v1.ApplyPrettyDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 1, // 69: hyapp.user.v1.ExpirePrettyDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 76, // 70: hyapp.user.v1.ExpirePrettyDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 5, // 71: hyapp.user.v1.BatchGetUsersResponse.UsersEntry.value:type_name -> hyapp.user.v1.User + 14, // 72: hyapp.user.v1.UserService.GetUser:input_type -> hyapp.user.v1.GetUserRequest + 16, // 73: hyapp.user.v1.UserService.BusinessUserLookup:input_type -> hyapp.user.v1.BusinessUserLookupRequest + 20, // 74: hyapp.user.v1.UserService.GetMyProfileStats:input_type -> hyapp.user.v1.GetMyProfileStatsRequest + 46, // 75: hyapp.user.v1.UserService.BatchGetUsers:input_type -> hyapp.user.v1.BatchGetUsersRequest + 48, // 76: hyapp.user.v1.UserService.ListUserIDs:input_type -> hyapp.user.v1.ListUserIDsRequest + 9, // 77: hyapp.user.v1.UserService.GetUserMicLifetimeStats:input_type -> hyapp.user.v1.GetUserMicLifetimeStatsRequest + 50, // 78: hyapp.user.v1.UserService.UpdateUserProfile:input_type -> hyapp.user.v1.UpdateUserProfileRequest + 52, // 79: hyapp.user.v1.UserService.ChangeUserCountry:input_type -> hyapp.user.v1.ChangeUserCountryRequest + 54, // 80: hyapp.user.v1.UserService.SetUserStatus:input_type -> hyapp.user.v1.SetUserStatusRequest + 56, // 81: hyapp.user.v1.UserService.CompleteOnboarding:input_type -> hyapp.user.v1.CompleteOnboardingRequest + 22, // 82: hyapp.user.v1.UserSocialService.RecordProfileVisit:input_type -> hyapp.user.v1.RecordProfileVisitRequest + 25, // 83: hyapp.user.v1.UserSocialService.ListProfileVisitors:input_type -> hyapp.user.v1.ListProfileVisitorsRequest + 27, // 84: hyapp.user.v1.UserSocialService.FollowUser:input_type -> hyapp.user.v1.FollowUserRequest + 29, // 85: hyapp.user.v1.UserSocialService.UnfollowUser:input_type -> hyapp.user.v1.UnfollowUserRequest + 32, // 86: hyapp.user.v1.UserSocialService.ListFollowing:input_type -> hyapp.user.v1.ListFollowingRequest + 34, // 87: hyapp.user.v1.UserSocialService.ApplyFriend:input_type -> hyapp.user.v1.ApplyFriendRequest + 36, // 88: hyapp.user.v1.UserSocialService.AcceptFriendApplication:input_type -> hyapp.user.v1.AcceptFriendApplicationRequest + 38, // 89: hyapp.user.v1.UserSocialService.DeleteFriend:input_type -> hyapp.user.v1.DeleteFriendRequest + 41, // 90: hyapp.user.v1.UserSocialService.ListFriends:input_type -> hyapp.user.v1.ListFriendsRequest + 44, // 91: hyapp.user.v1.UserSocialService.ListFriendApplications:input_type -> hyapp.user.v1.ListFriendApplicationsRequest + 11, // 92: hyapp.user.v1.UserCronService.ProcessLoginIPRiskBatch:input_type -> hyapp.user.v1.CronBatchRequest + 11, // 93: hyapp.user.v1.UserCronService.ProcessRegionRebuildBatch:input_type -> hyapp.user.v1.CronBatchRequest + 11, // 94: hyapp.user.v1.UserCronService.CompensateMicOpenSessions:input_type -> hyapp.user.v1.CronBatchRequest + 58, // 95: hyapp.user.v1.UserDeviceService.BindPushToken:input_type -> hyapp.user.v1.BindPushTokenRequest + 60, // 96: hyapp.user.v1.UserDeviceService.DeletePushToken:input_type -> hyapp.user.v1.DeletePushTokenRequest + 3, // 97: hyapp.user.v1.AppRegistryService.ResolveApp:input_type -> hyapp.user.v1.ResolveAppRequest + 64, // 98: hyapp.user.v1.CountryAdminService.ListCountries:input_type -> hyapp.user.v1.ListCountriesRequest + 66, // 99: hyapp.user.v1.CountryAdminService.UpdateCountry:input_type -> hyapp.user.v1.UpdateCountryRequest + 68, // 100: hyapp.user.v1.CountryQueryService.ListRegistrationCountries:input_type -> hyapp.user.v1.ListRegistrationCountriesRequest + 70, // 101: hyapp.user.v1.RegionAdminService.ListRegions:input_type -> hyapp.user.v1.ListRegionsRequest + 72, // 102: hyapp.user.v1.RegionAdminService.GetRegion:input_type -> hyapp.user.v1.GetRegionRequest + 73, // 103: hyapp.user.v1.RegionAdminService.UpdateRegion:input_type -> hyapp.user.v1.UpdateRegionRequest + 74, // 104: hyapp.user.v1.RegionAdminService.ReplaceRegionCountries:input_type -> hyapp.user.v1.ReplaceRegionCountriesRequest + 77, // 105: hyapp.user.v1.UserIdentityService.GetUserIdentity:input_type -> hyapp.user.v1.GetUserIdentityRequest + 79, // 106: hyapp.user.v1.UserIdentityService.ResolveDisplayUserID:input_type -> hyapp.user.v1.ResolveDisplayUserIDRequest + 81, // 107: hyapp.user.v1.UserIdentityService.ChangeDisplayUserID:input_type -> hyapp.user.v1.ChangeDisplayUserIDRequest + 83, // 108: hyapp.user.v1.UserIdentityService.ApplyPrettyDisplayUserID:input_type -> hyapp.user.v1.ApplyPrettyDisplayUserIDRequest + 85, // 109: hyapp.user.v1.UserIdentityService.ExpirePrettyDisplayUserID:input_type -> hyapp.user.v1.ExpirePrettyDisplayUserIDRequest + 15, // 110: hyapp.user.v1.UserService.GetUser:output_type -> hyapp.user.v1.GetUserResponse + 18, // 111: hyapp.user.v1.UserService.BusinessUserLookup:output_type -> hyapp.user.v1.BusinessUserLookupResponse + 21, // 112: hyapp.user.v1.UserService.GetMyProfileStats:output_type -> hyapp.user.v1.GetMyProfileStatsResponse + 47, // 113: hyapp.user.v1.UserService.BatchGetUsers:output_type -> hyapp.user.v1.BatchGetUsersResponse + 49, // 114: hyapp.user.v1.UserService.ListUserIDs:output_type -> hyapp.user.v1.ListUserIDsResponse + 10, // 115: hyapp.user.v1.UserService.GetUserMicLifetimeStats:output_type -> hyapp.user.v1.GetUserMicLifetimeStatsResponse + 51, // 116: hyapp.user.v1.UserService.UpdateUserProfile:output_type -> hyapp.user.v1.UpdateUserProfileResponse + 53, // 117: hyapp.user.v1.UserService.ChangeUserCountry:output_type -> hyapp.user.v1.ChangeUserCountryResponse + 55, // 118: hyapp.user.v1.UserService.SetUserStatus:output_type -> hyapp.user.v1.SetUserStatusResponse + 57, // 119: hyapp.user.v1.UserService.CompleteOnboarding:output_type -> hyapp.user.v1.CompleteOnboardingResponse + 23, // 120: hyapp.user.v1.UserSocialService.RecordProfileVisit:output_type -> hyapp.user.v1.RecordProfileVisitResponse + 26, // 121: hyapp.user.v1.UserSocialService.ListProfileVisitors:output_type -> hyapp.user.v1.ListProfileVisitorsResponse + 28, // 122: hyapp.user.v1.UserSocialService.FollowUser:output_type -> hyapp.user.v1.FollowUserResponse + 30, // 123: hyapp.user.v1.UserSocialService.UnfollowUser:output_type -> hyapp.user.v1.UnfollowUserResponse + 33, // 124: hyapp.user.v1.UserSocialService.ListFollowing:output_type -> hyapp.user.v1.ListFollowingResponse + 35, // 125: hyapp.user.v1.UserSocialService.ApplyFriend:output_type -> hyapp.user.v1.ApplyFriendResponse + 37, // 126: hyapp.user.v1.UserSocialService.AcceptFriendApplication:output_type -> hyapp.user.v1.AcceptFriendApplicationResponse + 39, // 127: hyapp.user.v1.UserSocialService.DeleteFriend:output_type -> hyapp.user.v1.DeleteFriendResponse + 42, // 128: hyapp.user.v1.UserSocialService.ListFriends:output_type -> hyapp.user.v1.ListFriendsResponse + 45, // 129: hyapp.user.v1.UserSocialService.ListFriendApplications:output_type -> hyapp.user.v1.ListFriendApplicationsResponse + 12, // 130: hyapp.user.v1.UserCronService.ProcessLoginIPRiskBatch:output_type -> hyapp.user.v1.CronBatchResponse + 12, // 131: hyapp.user.v1.UserCronService.ProcessRegionRebuildBatch:output_type -> hyapp.user.v1.CronBatchResponse + 12, // 132: hyapp.user.v1.UserCronService.CompensateMicOpenSessions:output_type -> hyapp.user.v1.CronBatchResponse + 59, // 133: hyapp.user.v1.UserDeviceService.BindPushToken:output_type -> hyapp.user.v1.BindPushTokenResponse + 61, // 134: hyapp.user.v1.UserDeviceService.DeletePushToken:output_type -> hyapp.user.v1.DeletePushTokenResponse + 4, // 135: hyapp.user.v1.AppRegistryService.ResolveApp:output_type -> hyapp.user.v1.ResolveAppResponse + 65, // 136: hyapp.user.v1.CountryAdminService.ListCountries:output_type -> hyapp.user.v1.ListCountriesResponse + 67, // 137: hyapp.user.v1.CountryAdminService.UpdateCountry:output_type -> hyapp.user.v1.CountryResponse + 69, // 138: hyapp.user.v1.CountryQueryService.ListRegistrationCountries:output_type -> hyapp.user.v1.ListRegistrationCountriesResponse + 71, // 139: hyapp.user.v1.RegionAdminService.ListRegions:output_type -> hyapp.user.v1.ListRegionsResponse + 75, // 140: hyapp.user.v1.RegionAdminService.GetRegion:output_type -> hyapp.user.v1.RegionResponse + 75, // 141: hyapp.user.v1.RegionAdminService.UpdateRegion:output_type -> hyapp.user.v1.RegionResponse + 75, // 142: hyapp.user.v1.RegionAdminService.ReplaceRegionCountries:output_type -> hyapp.user.v1.RegionResponse + 78, // 143: hyapp.user.v1.UserIdentityService.GetUserIdentity:output_type -> hyapp.user.v1.GetUserIdentityResponse + 80, // 144: hyapp.user.v1.UserIdentityService.ResolveDisplayUserID:output_type -> hyapp.user.v1.ResolveDisplayUserIDResponse + 82, // 145: hyapp.user.v1.UserIdentityService.ChangeDisplayUserID:output_type -> hyapp.user.v1.ChangeDisplayUserIDResponse + 84, // 146: hyapp.user.v1.UserIdentityService.ApplyPrettyDisplayUserID:output_type -> hyapp.user.v1.ApplyPrettyDisplayUserIDResponse + 86, // 147: hyapp.user.v1.UserIdentityService.ExpirePrettyDisplayUserID:output_type -> hyapp.user.v1.ExpirePrettyDisplayUserIDResponse + 110, // [110:148] is the sub-list for method output_type + 72, // [72:110] is the sub-list for method input_type + 72, // [72:72] is the sub-list for extension type_name + 72, // [72:72] is the sub-list for extension extendee + 0, // [0:72] is the sub-list for field type_name } func init() { file_proto_user_v1_user_proto_init() } @@ -7370,14 +7643,14 @@ func file_proto_user_v1_user_proto_init() { return } file_proto_user_v1_user_proto_msgTypes[49].OneofWrappers = []any{} - file_proto_user_v1_user_proto_msgTypes[61].OneofWrappers = []any{} + file_proto_user_v1_user_proto_msgTypes[63].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_user_v1_user_proto_rawDesc, NumEnums: 1, - NumMessages: 85, + NumMessages: 87, NumExtensions: 0, NumServices: 9, }, diff --git a/api/proto/user/v1/user.proto b/api/proto/user/v1/user.proto index 91493045..1826390f 100644 --- a/api/proto/user/v1/user.proto +++ b/api/proto/user/v1/user.proto @@ -419,6 +419,34 @@ message ChangeUserCountryResponse { bool region_changed = 5; } +// SetUserStatusRequest 是封禁、停用和恢复用户的通用内部入口。 +// 非 active 状态会同步吊销 refresh session,并把仍在有效期内的 access session 写入 gateway denylist。 +message SetUserStatusRequest { + RequestMeta meta = 1; + int64 target_user_id = 2; + UserStatus status = 3; + int64 operator_user_id = 4; + string reason = 5; + // operator_type 区分 admin、app_user、system,避免不同身份体系共用一个整数 ID 后无法追溯。 + string operator_type = 6; +} + +// SetUserStatusResponse 返回用户当前状态和封禁相关副作用结果。 +// 外部副作用字段用于后台或 App 管理入口判断是否需要重试补偿。 +message SetUserStatusResponse { + User user = 1; + int64 revoked_session_count = 2; + bool im_kicked = 3; + string im_kick_error = 4; + bool room_evicted = 5; + string room_id = 6; + bool rtc_kicked = 7; + string room_evict_error = 8; + string rtc_kick_error = 9; + bool access_token_revoked = 10; + string access_token_revoke_error = 11; +} + // CompleteOnboardingRequest 是注册页唯一资料提交入口。 message CompleteOnboardingRequest { RequestMeta meta = 1; @@ -657,6 +685,7 @@ service UserService { rpc GetUserMicLifetimeStats(GetUserMicLifetimeStatsRequest) returns (GetUserMicLifetimeStatsResponse); rpc UpdateUserProfile(UpdateUserProfileRequest) returns (UpdateUserProfileResponse); rpc ChangeUserCountry(ChangeUserCountryRequest) returns (ChangeUserCountryResponse); + rpc SetUserStatus(SetUserStatusRequest) returns (SetUserStatusResponse); rpc CompleteOnboarding(CompleteOnboardingRequest) returns (CompleteOnboardingResponse); } diff --git a/api/proto/user/v1/user_grpc.pb.go b/api/proto/user/v1/user_grpc.pb.go index 52b3bc48..5c8369b9 100644 --- a/api/proto/user/v1/user_grpc.pb.go +++ b/api/proto/user/v1/user_grpc.pb.go @@ -27,6 +27,7 @@ const ( UserService_GetUserMicLifetimeStats_FullMethodName = "/hyapp.user.v1.UserService/GetUserMicLifetimeStats" UserService_UpdateUserProfile_FullMethodName = "/hyapp.user.v1.UserService/UpdateUserProfile" UserService_ChangeUserCountry_FullMethodName = "/hyapp.user.v1.UserService/ChangeUserCountry" + UserService_SetUserStatus_FullMethodName = "/hyapp.user.v1.UserService/SetUserStatus" UserService_CompleteOnboarding_FullMethodName = "/hyapp.user.v1.UserService/CompleteOnboarding" ) @@ -44,6 +45,7 @@ type UserServiceClient interface { GetUserMicLifetimeStats(ctx context.Context, in *GetUserMicLifetimeStatsRequest, opts ...grpc.CallOption) (*GetUserMicLifetimeStatsResponse, error) UpdateUserProfile(ctx context.Context, in *UpdateUserProfileRequest, opts ...grpc.CallOption) (*UpdateUserProfileResponse, error) ChangeUserCountry(ctx context.Context, in *ChangeUserCountryRequest, opts ...grpc.CallOption) (*ChangeUserCountryResponse, error) + SetUserStatus(ctx context.Context, in *SetUserStatusRequest, opts ...grpc.CallOption) (*SetUserStatusResponse, error) CompleteOnboarding(ctx context.Context, in *CompleteOnboardingRequest, opts ...grpc.CallOption) (*CompleteOnboardingResponse, error) } @@ -135,6 +137,16 @@ func (c *userServiceClient) ChangeUserCountry(ctx context.Context, in *ChangeUse return out, nil } +func (c *userServiceClient) SetUserStatus(ctx context.Context, in *SetUserStatusRequest, opts ...grpc.CallOption) (*SetUserStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetUserStatusResponse) + err := c.cc.Invoke(ctx, UserService_SetUserStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *userServiceClient) CompleteOnboarding(ctx context.Context, in *CompleteOnboardingRequest, opts ...grpc.CallOption) (*CompleteOnboardingResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CompleteOnboardingResponse) @@ -159,6 +171,7 @@ type UserServiceServer interface { GetUserMicLifetimeStats(context.Context, *GetUserMicLifetimeStatsRequest) (*GetUserMicLifetimeStatsResponse, error) UpdateUserProfile(context.Context, *UpdateUserProfileRequest) (*UpdateUserProfileResponse, error) ChangeUserCountry(context.Context, *ChangeUserCountryRequest) (*ChangeUserCountryResponse, error) + SetUserStatus(context.Context, *SetUserStatusRequest) (*SetUserStatusResponse, error) CompleteOnboarding(context.Context, *CompleteOnboardingRequest) (*CompleteOnboardingResponse, error) mustEmbedUnimplementedUserServiceServer() } @@ -194,6 +207,9 @@ func (UnimplementedUserServiceServer) UpdateUserProfile(context.Context, *Update func (UnimplementedUserServiceServer) ChangeUserCountry(context.Context, *ChangeUserCountryRequest) (*ChangeUserCountryResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ChangeUserCountry not implemented") } +func (UnimplementedUserServiceServer) SetUserStatus(context.Context, *SetUserStatusRequest) (*SetUserStatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetUserStatus not implemented") +} func (UnimplementedUserServiceServer) CompleteOnboarding(context.Context, *CompleteOnboardingRequest) (*CompleteOnboardingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CompleteOnboarding not implemented") } @@ -362,6 +378,24 @@ func _UserService_ChangeUserCountry_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _UserService_SetUserStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetUserStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).SetUserStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserService_SetUserStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).SetUserStatus(ctx, req.(*SetUserStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _UserService_CompleteOnboarding_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CompleteOnboardingRequest) if err := dec(in); err != nil { @@ -419,6 +453,10 @@ var UserService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ChangeUserCountry", Handler: _UserService_ChangeUserCountry_Handler, }, + { + MethodName: "SetUserStatus", + Handler: _UserService_SetUserStatus_Handler, + }, { MethodName: "CompleteOnboarding", Handler: _UserService_CompleteOnboarding_Handler, diff --git a/api/proto/wallet/v1/wallet.pb.go b/api/proto/wallet/v1/wallet.pb.go index 2982c023..c442e971 100644 --- a/api/proto/wallet/v1/wallet.pb.go +++ b/api/proto/wallet/v1/wallet.pb.go @@ -5600,15 +5600,27 @@ type RechargeProduct struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ProductId int64 `protobuf:"varint,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` - ProductCode string `protobuf:"bytes,2,opt,name=product_code,json=productCode,proto3" json:"product_code,omitempty"` - Channel string `protobuf:"bytes,3,opt,name=channel,proto3" json:"channel,omitempty"` - CurrencyCode string `protobuf:"bytes,4,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` - CoinAmount int64 `protobuf:"varint,5,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` - AmountMinor int64 `protobuf:"varint,6,opt,name=amount_minor,json=amountMinor,proto3" json:"amount_minor,omitempty"` - PolicyVersion string `protobuf:"bytes,7,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` - Enabled bool `protobuf:"varint,8,opt,name=enabled,proto3" json:"enabled,omitempty"` - SortOrder int32 `protobuf:"varint,9,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + ProductId int64 `protobuf:"varint,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + ProductCode string `protobuf:"bytes,2,opt,name=product_code,json=productCode,proto3" json:"product_code,omitempty"` + Channel string `protobuf:"bytes,3,opt,name=channel,proto3" json:"channel,omitempty"` + CurrencyCode string `protobuf:"bytes,4,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` + CoinAmount int64 `protobuf:"varint,5,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` + AmountMinor int64 `protobuf:"varint,6,opt,name=amount_minor,json=amountMinor,proto3" json:"amount_minor,omitempty"` + PolicyVersion string `protobuf:"bytes,7,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` + Enabled bool `protobuf:"varint,8,opt,name=enabled,proto3" json:"enabled,omitempty"` + SortOrder int32 `protobuf:"varint,9,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + ProductName string `protobuf:"bytes,10,opt,name=product_name,json=productName,proto3" json:"product_name,omitempty"` + Description string `protobuf:"bytes,11,opt,name=description,proto3" json:"description,omitempty"` + Platform string `protobuf:"bytes,12,opt,name=platform,proto3" json:"platform,omitempty"` + RegionIds []int64 `protobuf:"varint,13,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` + ResourceAssetType string `protobuf:"bytes,14,opt,name=resource_asset_type,json=resourceAssetType,proto3" json:"resource_asset_type,omitempty"` + AmountMicro int64 `protobuf:"varint,15,opt,name=amount_micro,json=amountMicro,proto3" json:"amount_micro,omitempty"` + CreatedByUserId int64 `protobuf:"varint,16,opt,name=created_by_user_id,json=createdByUserId,proto3" json:"created_by_user_id,omitempty"` + UpdatedByUserId int64 `protobuf:"varint,17,opt,name=updated_by_user_id,json=updatedByUserId,proto3" json:"updated_by_user_id,omitempty"` + CreatedAtMs int64 `protobuf:"varint,18,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,19,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` + AppCode string `protobuf:"bytes,20,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + Status string `protobuf:"bytes,21,opt,name=status,proto3" json:"status,omitempty"` } func (x *RechargeProduct) Reset() { @@ -5704,6 +5716,90 @@ func (x *RechargeProduct) GetSortOrder() int32 { return 0 } +func (x *RechargeProduct) GetProductName() string { + if x != nil { + return x.ProductName + } + return "" +} + +func (x *RechargeProduct) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *RechargeProduct) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *RechargeProduct) GetRegionIds() []int64 { + if x != nil { + return x.RegionIds + } + return nil +} + +func (x *RechargeProduct) GetResourceAssetType() string { + if x != nil { + return x.ResourceAssetType + } + return "" +} + +func (x *RechargeProduct) GetAmountMicro() int64 { + if x != nil { + return x.AmountMicro + } + return 0 +} + +func (x *RechargeProduct) GetCreatedByUserId() int64 { + if x != nil { + return x.CreatedByUserId + } + return 0 +} + +func (x *RechargeProduct) GetUpdatedByUserId() int64 { + if x != nil { + return x.UpdatedByUserId + } + return 0 +} + +func (x *RechargeProduct) GetCreatedAtMs() int64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *RechargeProduct) GetUpdatedAtMs() int64 { + if x != nil { + return x.UpdatedAtMs + } + return 0 +} + +func (x *RechargeProduct) GetAppCode() string { + if x != nil { + return x.AppCode + } + return "" +} + +func (x *RechargeProduct) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + type ListRechargeProductsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5713,6 +5809,8 @@ type ListRechargeProductsRequest struct { AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` RegionId int64 `protobuf:"varint,4,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + // platform 来自 gateway 解析的 App 平台请求头;为空时返回该区域全部已上架商品。 + Platform string `protobuf:"bytes,5,opt,name=platform,proto3" json:"platform,omitempty"` } func (x *ListRechargeProductsRequest) Reset() { @@ -5773,6 +5871,13 @@ func (x *ListRechargeProductsRequest) GetRegionId() int64 { return 0 } +func (x *ListRechargeProductsRequest) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + type ListRechargeProductsResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5826,6 +5931,563 @@ func (x *ListRechargeProductsResponse) GetChannels() []string { return nil } +// ListAdminRechargeProductsRequest 是后台内购配置列表查询,不参与用户充值主链路。 +type ListAdminRechargeProductsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + Platform string `protobuf:"bytes,4,opt,name=platform,proto3" json:"platform,omitempty"` + RegionId int64 `protobuf:"varint,5,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + Keyword string `protobuf:"bytes,6,opt,name=keyword,proto3" json:"keyword,omitempty"` + Page int32 `protobuf:"varint,7,opt,name=page,proto3" json:"page,omitempty"` + PageSize int32 `protobuf:"varint,8,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` +} + +func (x *ListAdminRechargeProductsRequest) Reset() { + *x = ListAdminRechargeProductsRequest{} + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListAdminRechargeProductsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAdminRechargeProductsRequest) ProtoMessage() {} + +func (x *ListAdminRechargeProductsRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[62] + 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 ListAdminRechargeProductsRequest.ProtoReflect.Descriptor instead. +func (*ListAdminRechargeProductsRequest) Descriptor() ([]byte, []int) { + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{62} +} + +func (x *ListAdminRechargeProductsRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *ListAdminRechargeProductsRequest) GetAppCode() string { + if x != nil { + return x.AppCode + } + return "" +} + +func (x *ListAdminRechargeProductsRequest) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *ListAdminRechargeProductsRequest) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *ListAdminRechargeProductsRequest) GetRegionId() int64 { + if x != nil { + return x.RegionId + } + return 0 +} + +func (x *ListAdminRechargeProductsRequest) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *ListAdminRechargeProductsRequest) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *ListAdminRechargeProductsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +type ListAdminRechargeProductsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Products []*RechargeProduct `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"` + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` +} + +func (x *ListAdminRechargeProductsResponse) Reset() { + *x = ListAdminRechargeProductsResponse{} + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListAdminRechargeProductsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAdminRechargeProductsResponse) ProtoMessage() {} + +func (x *ListAdminRechargeProductsResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[63] + 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 ListAdminRechargeProductsResponse.ProtoReflect.Descriptor instead. +func (*ListAdminRechargeProductsResponse) Descriptor() ([]byte, []int) { + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{63} +} + +func (x *ListAdminRechargeProductsResponse) GetProducts() []*RechargeProduct { + if x != nil { + return x.Products + } + return nil +} + +func (x *ListAdminRechargeProductsResponse) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +// CreateRechargeProductRequest 配置一个 App 内购商品;首版资源资产固定为 COIN。 +type CreateRechargeProductRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + AmountMicro int64 `protobuf:"varint,3,opt,name=amount_micro,json=amountMicro,proto3" json:"amount_micro,omitempty"` + CoinAmount int64 `protobuf:"varint,4,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` + ProductName string `protobuf:"bytes,5,opt,name=product_name,json=productName,proto3" json:"product_name,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + Platform string `protobuf:"bytes,7,opt,name=platform,proto3" json:"platform,omitempty"` + RegionIds []int64 `protobuf:"varint,8,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` + Enabled bool `protobuf:"varint,9,opt,name=enabled,proto3" json:"enabled,omitempty"` + OperatorUserId int64 `protobuf:"varint,10,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` +} + +func (x *CreateRechargeProductRequest) Reset() { + *x = CreateRechargeProductRequest{} + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateRechargeProductRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateRechargeProductRequest) ProtoMessage() {} + +func (x *CreateRechargeProductRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[64] + 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 CreateRechargeProductRequest.ProtoReflect.Descriptor instead. +func (*CreateRechargeProductRequest) Descriptor() ([]byte, []int) { + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{64} +} + +func (x *CreateRechargeProductRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *CreateRechargeProductRequest) GetAppCode() string { + if x != nil { + return x.AppCode + } + return "" +} + +func (x *CreateRechargeProductRequest) GetAmountMicro() int64 { + if x != nil { + return x.AmountMicro + } + return 0 +} + +func (x *CreateRechargeProductRequest) GetCoinAmount() int64 { + if x != nil { + return x.CoinAmount + } + return 0 +} + +func (x *CreateRechargeProductRequest) GetProductName() string { + if x != nil { + return x.ProductName + } + return "" +} + +func (x *CreateRechargeProductRequest) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *CreateRechargeProductRequest) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *CreateRechargeProductRequest) GetRegionIds() []int64 { + if x != nil { + return x.RegionIds + } + return nil +} + +func (x *CreateRechargeProductRequest) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *CreateRechargeProductRequest) GetOperatorUserId() int64 { + if x != nil { + return x.OperatorUserId + } + return 0 +} + +type UpdateRechargeProductRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + ProductId int64 `protobuf:"varint,3,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + AmountMicro int64 `protobuf:"varint,4,opt,name=amount_micro,json=amountMicro,proto3" json:"amount_micro,omitempty"` + CoinAmount int64 `protobuf:"varint,5,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` + ProductName string `protobuf:"bytes,6,opt,name=product_name,json=productName,proto3" json:"product_name,omitempty"` + Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"` + Platform string `protobuf:"bytes,8,opt,name=platform,proto3" json:"platform,omitempty"` + RegionIds []int64 `protobuf:"varint,9,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` + Enabled bool `protobuf:"varint,10,opt,name=enabled,proto3" json:"enabled,omitempty"` + OperatorUserId int64 `protobuf:"varint,11,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` +} + +func (x *UpdateRechargeProductRequest) Reset() { + *x = UpdateRechargeProductRequest{} + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateRechargeProductRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRechargeProductRequest) ProtoMessage() {} + +func (x *UpdateRechargeProductRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[65] + 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 UpdateRechargeProductRequest.ProtoReflect.Descriptor instead. +func (*UpdateRechargeProductRequest) Descriptor() ([]byte, []int) { + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{65} +} + +func (x *UpdateRechargeProductRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *UpdateRechargeProductRequest) GetAppCode() string { + if x != nil { + return x.AppCode + } + return "" +} + +func (x *UpdateRechargeProductRequest) GetProductId() int64 { + if x != nil { + return x.ProductId + } + return 0 +} + +func (x *UpdateRechargeProductRequest) GetAmountMicro() int64 { + if x != nil { + return x.AmountMicro + } + return 0 +} + +func (x *UpdateRechargeProductRequest) GetCoinAmount() int64 { + if x != nil { + return x.CoinAmount + } + return 0 +} + +func (x *UpdateRechargeProductRequest) GetProductName() string { + if x != nil { + return x.ProductName + } + return "" +} + +func (x *UpdateRechargeProductRequest) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *UpdateRechargeProductRequest) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *UpdateRechargeProductRequest) GetRegionIds() []int64 { + if x != nil { + return x.RegionIds + } + return nil +} + +func (x *UpdateRechargeProductRequest) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *UpdateRechargeProductRequest) GetOperatorUserId() int64 { + if x != nil { + return x.OperatorUserId + } + return 0 +} + +type DeleteRechargeProductRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + ProductId int64 `protobuf:"varint,3,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + OperatorUserId int64 `protobuf:"varint,4,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` +} + +func (x *DeleteRechargeProductRequest) Reset() { + *x = DeleteRechargeProductRequest{} + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteRechargeProductRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRechargeProductRequest) ProtoMessage() {} + +func (x *DeleteRechargeProductRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[66] + 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 DeleteRechargeProductRequest.ProtoReflect.Descriptor instead. +func (*DeleteRechargeProductRequest) Descriptor() ([]byte, []int) { + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{66} +} + +func (x *DeleteRechargeProductRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *DeleteRechargeProductRequest) GetAppCode() string { + if x != nil { + return x.AppCode + } + return "" +} + +func (x *DeleteRechargeProductRequest) GetProductId() int64 { + if x != nil { + return x.ProductId + } + return 0 +} + +func (x *DeleteRechargeProductRequest) GetOperatorUserId() int64 { + if x != nil { + return x.OperatorUserId + } + return 0 +} + +type RechargeProductResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Product *RechargeProduct `protobuf:"bytes,1,opt,name=product,proto3" json:"product,omitempty"` +} + +func (x *RechargeProductResponse) Reset() { + *x = RechargeProductResponse{} + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RechargeProductResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RechargeProductResponse) ProtoMessage() {} + +func (x *RechargeProductResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[67] + 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 RechargeProductResponse.ProtoReflect.Descriptor instead. +func (*RechargeProductResponse) Descriptor() ([]byte, []int) { + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{67} +} + +func (x *RechargeProductResponse) GetProduct() *RechargeProduct { + if x != nil { + return x.Product + } + return nil +} + +type DeleteRechargeProductResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"` +} + +func (x *DeleteRechargeProductResponse) Reset() { + *x = DeleteRechargeProductResponse{} + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteRechargeProductResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRechargeProductResponse) ProtoMessage() {} + +func (x *DeleteRechargeProductResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[68] + 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 DeleteRechargeProductResponse.ProtoReflect.Descriptor instead. +func (*DeleteRechargeProductResponse) Descriptor() ([]byte, []int) { + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{68} +} + +func (x *DeleteRechargeProductResponse) GetDeleted() bool { + if x != nil { + return x.Deleted + } + return false +} + type DiamondExchangeRule struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5841,7 +6503,7 @@ type DiamondExchangeRule struct { func (x *DiamondExchangeRule) Reset() { *x = DiamondExchangeRule{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[62] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5853,7 +6515,7 @@ func (x *DiamondExchangeRule) String() string { func (*DiamondExchangeRule) ProtoMessage() {} func (x *DiamondExchangeRule) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[62] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5866,7 +6528,7 @@ func (x *DiamondExchangeRule) ProtoReflect() protoreflect.Message { // Deprecated: Use DiamondExchangeRule.ProtoReflect.Descriptor instead. func (*DiamondExchangeRule) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{62} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{69} } func (x *DiamondExchangeRule) GetExchangeType() string { @@ -5923,7 +6585,7 @@ type GetDiamondExchangeConfigRequest struct { func (x *GetDiamondExchangeConfigRequest) Reset() { *x = GetDiamondExchangeConfigRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[63] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5935,7 +6597,7 @@ func (x *GetDiamondExchangeConfigRequest) String() string { func (*GetDiamondExchangeConfigRequest) ProtoMessage() {} func (x *GetDiamondExchangeConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[63] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5948,7 +6610,7 @@ func (x *GetDiamondExchangeConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDiamondExchangeConfigRequest.ProtoReflect.Descriptor instead. func (*GetDiamondExchangeConfigRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{63} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{70} } func (x *GetDiamondExchangeConfigRequest) GetRequestId() string { @@ -5982,7 +6644,7 @@ type GetDiamondExchangeConfigResponse struct { func (x *GetDiamondExchangeConfigResponse) Reset() { *x = GetDiamondExchangeConfigResponse{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[64] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5994,7 +6656,7 @@ func (x *GetDiamondExchangeConfigResponse) String() string { func (*GetDiamondExchangeConfigResponse) ProtoMessage() {} func (x *GetDiamondExchangeConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[64] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6007,7 +6669,7 @@ func (x *GetDiamondExchangeConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDiamondExchangeConfigResponse.ProtoReflect.Descriptor instead. func (*GetDiamondExchangeConfigResponse) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{64} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{71} } func (x *GetDiamondExchangeConfigResponse) GetRules() []*DiamondExchangeRule { @@ -6038,7 +6700,7 @@ type WalletTransaction struct { func (x *WalletTransaction) Reset() { *x = WalletTransaction{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[65] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6050,7 +6712,7 @@ func (x *WalletTransaction) String() string { func (*WalletTransaction) ProtoMessage() {} func (x *WalletTransaction) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[65] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6063,7 +6725,7 @@ func (x *WalletTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use WalletTransaction.ProtoReflect.Descriptor instead. func (*WalletTransaction) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{65} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{72} } func (x *WalletTransaction) GetEntryId() int64 { @@ -6158,7 +6820,7 @@ type ListWalletTransactionsRequest struct { func (x *ListWalletTransactionsRequest) Reset() { *x = ListWalletTransactionsRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[66] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6170,7 +6832,7 @@ func (x *ListWalletTransactionsRequest) String() string { func (*ListWalletTransactionsRequest) ProtoMessage() {} func (x *ListWalletTransactionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[66] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6183,7 +6845,7 @@ func (x *ListWalletTransactionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWalletTransactionsRequest.ProtoReflect.Descriptor instead. func (*ListWalletTransactionsRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{66} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{73} } func (x *ListWalletTransactionsRequest) GetRequestId() string { @@ -6239,7 +6901,7 @@ type ListWalletTransactionsResponse struct { func (x *ListWalletTransactionsResponse) Reset() { *x = ListWalletTransactionsResponse{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[67] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6251,7 +6913,7 @@ func (x *ListWalletTransactionsResponse) String() string { func (*ListWalletTransactionsResponse) ProtoMessage() {} func (x *ListWalletTransactionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[67] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6264,7 +6926,7 @@ func (x *ListWalletTransactionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWalletTransactionsResponse.ProtoReflect.Descriptor instead. func (*ListWalletTransactionsResponse) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{67} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{74} } func (x *ListWalletTransactionsResponse) GetTransactions() []*WalletTransaction { @@ -6299,7 +6961,7 @@ type WithdrawalRequest struct { func (x *WithdrawalRequest) Reset() { *x = WithdrawalRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[68] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6311,7 +6973,7 @@ func (x *WithdrawalRequest) String() string { func (*WithdrawalRequest) ProtoMessage() {} func (x *WithdrawalRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[68] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6324,7 +6986,7 @@ func (x *WithdrawalRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WithdrawalRequest.ProtoReflect.Descriptor instead. func (*WithdrawalRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{68} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{75} } func (x *WithdrawalRequest) GetWithdrawalId() string { @@ -6405,7 +7067,7 @@ type ApplyWithdrawalRequest struct { func (x *ApplyWithdrawalRequest) Reset() { *x = ApplyWithdrawalRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[69] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6417,7 +7079,7 @@ func (x *ApplyWithdrawalRequest) String() string { func (*ApplyWithdrawalRequest) ProtoMessage() {} func (x *ApplyWithdrawalRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[69] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6430,7 +7092,7 @@ func (x *ApplyWithdrawalRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyWithdrawalRequest.ProtoReflect.Descriptor instead. func (*ApplyWithdrawalRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{69} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{76} } func (x *ApplyWithdrawalRequest) GetCommandId() string { @@ -6486,7 +7148,7 @@ type ApplyWithdrawalResponse struct { func (x *ApplyWithdrawalResponse) Reset() { *x = ApplyWithdrawalResponse{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[70] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6498,7 +7160,7 @@ func (x *ApplyWithdrawalResponse) String() string { func (*ApplyWithdrawalResponse) ProtoMessage() {} func (x *ApplyWithdrawalResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[70] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6511,7 +7173,7 @@ func (x *ApplyWithdrawalResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyWithdrawalResponse.ProtoReflect.Descriptor instead. func (*ApplyWithdrawalResponse) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{70} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{77} } func (x *ApplyWithdrawalResponse) GetWithdrawal() *WithdrawalRequest { @@ -6543,7 +7205,7 @@ type VipRewardItem struct { func (x *VipRewardItem) Reset() { *x = VipRewardItem{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[71] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6555,7 +7217,7 @@ func (x *VipRewardItem) String() string { func (*VipRewardItem) ProtoMessage() {} func (x *VipRewardItem) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[71] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6568,7 +7230,7 @@ func (x *VipRewardItem) ProtoReflect() protoreflect.Message { // Deprecated: Use VipRewardItem.ProtoReflect.Descriptor instead. func (*VipRewardItem) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{71} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{78} } func (x *VipRewardItem) GetResourceId() int64 { @@ -6631,7 +7293,7 @@ type VipLevel struct { func (x *VipLevel) Reset() { *x = VipLevel{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[72] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6643,7 +7305,7 @@ func (x *VipLevel) String() string { func (*VipLevel) ProtoMessage() {} func (x *VipLevel) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[72] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6656,7 +7318,7 @@ func (x *VipLevel) ProtoReflect() protoreflect.Message { // Deprecated: Use VipLevel.ProtoReflect.Descriptor instead. func (*VipLevel) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{72} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{79} } func (x *VipLevel) GetLevel() int32 { @@ -6738,7 +7400,7 @@ type UserVip struct { func (x *UserVip) Reset() { *x = UserVip{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[73] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6750,7 +7412,7 @@ func (x *UserVip) String() string { func (*UserVip) ProtoMessage() {} func (x *UserVip) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[73] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6763,7 +7425,7 @@ func (x *UserVip) ProtoReflect() protoreflect.Message { // Deprecated: Use UserVip.ProtoReflect.Descriptor instead. func (*UserVip) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{73} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{80} } func (x *UserVip) GetUserId() int64 { @@ -6827,7 +7489,7 @@ type ListVipPackagesRequest struct { func (x *ListVipPackagesRequest) Reset() { *x = ListVipPackagesRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[74] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6839,7 +7501,7 @@ func (x *ListVipPackagesRequest) String() string { func (*ListVipPackagesRequest) ProtoMessage() {} func (x *ListVipPackagesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[74] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6852,7 +7514,7 @@ func (x *ListVipPackagesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListVipPackagesRequest.ProtoReflect.Descriptor instead. func (*ListVipPackagesRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{74} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{81} } func (x *ListVipPackagesRequest) GetRequestId() string { @@ -6887,7 +7549,7 @@ type ListVipPackagesResponse struct { func (x *ListVipPackagesResponse) Reset() { *x = ListVipPackagesResponse{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[75] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6899,7 +7561,7 @@ func (x *ListVipPackagesResponse) String() string { func (*ListVipPackagesResponse) ProtoMessage() {} func (x *ListVipPackagesResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[75] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6912,7 +7574,7 @@ func (x *ListVipPackagesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListVipPackagesResponse.ProtoReflect.Descriptor instead. func (*ListVipPackagesResponse) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{75} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{82} } func (x *ListVipPackagesResponse) GetCurrentVip() *UserVip { @@ -6941,7 +7603,7 @@ type GetMyVipRequest struct { func (x *GetMyVipRequest) Reset() { *x = GetMyVipRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[76] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6953,7 +7615,7 @@ func (x *GetMyVipRequest) String() string { func (*GetMyVipRequest) ProtoMessage() {} func (x *GetMyVipRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[76] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6966,7 +7628,7 @@ func (x *GetMyVipRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMyVipRequest.ProtoReflect.Descriptor instead. func (*GetMyVipRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{76} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{83} } func (x *GetMyVipRequest) GetRequestId() string { @@ -7000,7 +7662,7 @@ type GetMyVipResponse struct { func (x *GetMyVipResponse) Reset() { *x = GetMyVipResponse{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[77] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7012,7 +7674,7 @@ func (x *GetMyVipResponse) String() string { func (*GetMyVipResponse) ProtoMessage() {} func (x *GetMyVipResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[77] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7025,7 +7687,7 @@ func (x *GetMyVipResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMyVipResponse.ProtoReflect.Descriptor instead. func (*GetMyVipResponse) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{77} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{84} } func (x *GetMyVipResponse) GetVip() *UserVip { @@ -7048,7 +7710,7 @@ type PurchaseVipRequest struct { func (x *PurchaseVipRequest) Reset() { *x = PurchaseVipRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[78] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7060,7 +7722,7 @@ func (x *PurchaseVipRequest) String() string { func (*PurchaseVipRequest) ProtoMessage() {} func (x *PurchaseVipRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[78] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7073,7 +7735,7 @@ func (x *PurchaseVipRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PurchaseVipRequest.ProtoReflect.Descriptor instead. func (*PurchaseVipRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{78} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{85} } func (x *PurchaseVipRequest) GetCommandId() string { @@ -7119,7 +7781,7 @@ type PurchaseVipResponse struct { func (x *PurchaseVipResponse) Reset() { *x = PurchaseVipResponse{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[79] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7131,7 +7793,7 @@ func (x *PurchaseVipResponse) String() string { func (*PurchaseVipResponse) ProtoMessage() {} func (x *PurchaseVipResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[79] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7144,7 +7806,7 @@ func (x *PurchaseVipResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PurchaseVipResponse.ProtoReflect.Descriptor instead. func (*PurchaseVipResponse) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{79} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{86} } func (x *PurchaseVipResponse) GetOrderId() string { @@ -7207,7 +7869,7 @@ type CreditTaskRewardRequest struct { func (x *CreditTaskRewardRequest) Reset() { *x = CreditTaskRewardRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[80] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7219,7 +7881,7 @@ func (x *CreditTaskRewardRequest) String() string { func (*CreditTaskRewardRequest) ProtoMessage() {} func (x *CreditTaskRewardRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[80] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7232,7 +7894,7 @@ func (x *CreditTaskRewardRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreditTaskRewardRequest.ProtoReflect.Descriptor instead. func (*CreditTaskRewardRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{80} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{87} } func (x *CreditTaskRewardRequest) GetCommandId() string { @@ -7305,7 +7967,7 @@ type CreditTaskRewardResponse struct { func (x *CreditTaskRewardResponse) Reset() { *x = CreditTaskRewardResponse{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[81] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7317,7 +7979,7 @@ func (x *CreditTaskRewardResponse) String() string { func (*CreditTaskRewardResponse) ProtoMessage() {} func (x *CreditTaskRewardResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[81] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7330,7 +7992,7 @@ func (x *CreditTaskRewardResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreditTaskRewardResponse.ProtoReflect.Descriptor instead. func (*CreditTaskRewardResponse) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{81} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{88} } func (x *CreditTaskRewardResponse) GetTransactionId() string { @@ -7383,7 +8045,7 @@ type ApplyGameCoinChangeRequest struct { func (x *ApplyGameCoinChangeRequest) Reset() { *x = ApplyGameCoinChangeRequest{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[82] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7395,7 +8057,7 @@ func (x *ApplyGameCoinChangeRequest) String() string { func (*ApplyGameCoinChangeRequest) ProtoMessage() {} func (x *ApplyGameCoinChangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[82] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7408,7 +8070,7 @@ func (x *ApplyGameCoinChangeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyGameCoinChangeRequest.ProtoReflect.Descriptor instead. func (*ApplyGameCoinChangeRequest) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{82} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{89} } func (x *ApplyGameCoinChangeRequest) GetRequestId() string { @@ -7508,7 +8170,7 @@ type ApplyGameCoinChangeResponse struct { func (x *ApplyGameCoinChangeResponse) Reset() { *x = ApplyGameCoinChangeResponse{} - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[83] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7520,7 +8182,7 @@ func (x *ApplyGameCoinChangeResponse) String() string { func (*ApplyGameCoinChangeResponse) ProtoMessage() {} func (x *ApplyGameCoinChangeResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_wallet_v1_wallet_proto_msgTypes[83] + mi := &file_proto_wallet_v1_wallet_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7533,7 +8195,7 @@ func (x *ApplyGameCoinChangeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyGameCoinChangeResponse.ProtoReflect.Descriptor instead. func (*ApplyGameCoinChangeResponse) Descriptor() ([]byte, []int) { - return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{83} + return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{90} } func (x *ApplyGameCoinChangeResponse) GetWalletTransactionId() string { @@ -8594,7 +9256,7 @@ var file_proto_wallet_v1_wallet_proto_rawDesc = []byte{ 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, - 0x22, 0xb6, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x22, 0xde, 0x05, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x63, @@ -8613,541 +9275,688 @@ var file_proto_wallet_v1_wallet_proto_rawDesc = []byte{ 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, - 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x8d, 0x01, 0x0a, 0x1b, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, - 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, - 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, - 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, - 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x78, 0x0a, 0x1c, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x70, 0x72, 0x6f, - 0x64, 0x75, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x08, 0x70, - 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x22, 0xde, 0x01, 0x0a, 0x13, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x26, 0x0a, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6d, 0x41, - 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x74, 0x6f, 0x5f, 0x61, - 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x74, 0x6f, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0a, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, - 0x09, 0x74, 0x6f, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x08, 0x74, 0x6f, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x22, 0x74, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x44, 0x69, 0x61, 0x6d, 0x6f, - 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, - 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, - 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x5e, 0x0a, 0x20, 0x47, 0x65, - 0x74, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, - 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, - 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x96, 0x03, 0x0a, 0x11, 0x57, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x69, 0x7a, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x69, 0x7a, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, - 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x5f, - 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x72, 0x6f, - 0x7a, 0x65, 0x6e, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, - 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x66, 0x74, 0x65, - 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x5f, 0x61, 0x66, 0x74, 0x65, - 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x41, - 0x66, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x70, - 0x61, 0x72, 0x74, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x61, 0x72, 0x74, 0x79, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, - 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, - 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x4d, 0x73, 0x22, 0xc2, 0x01, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, - 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x73, 0x73, 0x65, - 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x73, - 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, - 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, - 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x7e, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, - 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0c, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0xa7, 0x02, 0x0a, 0x11, 0x57, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, - 0x0a, 0x0d, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, - 0x6c, 0x49, 0x64, 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, - 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x70, - 0x61, 0x79, 0x6f, 0x75, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, - 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x4d, 0x73, 0x22, 0xc2, 0x01, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x57, 0x69, 0x74, 0x68, - 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, - 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, - 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x79, 0x6f, - 0x75, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x96, 0x01, 0x0a, 0x17, 0x41, 0x70, 0x70, 0x6c, - 0x79, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, - 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, 0x77, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x12, 0x37, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, - 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x22, 0xce, 0x01, 0x0a, 0x0d, 0x56, 0x69, 0x70, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, - 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x22, 0x0a, - 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x4d, - 0x73, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x56, 0x69, 0x70, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x14, - 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, - 0x65, 0x76, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x70, 0x72, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, - 0x1f, 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, - 0x12, 0x37, 0x0a, 0x18, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x15, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x41, 0x0a, 0x0c, 0x72, 0x65, 0x77, - 0x61, 0x72, 0x64, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x56, 0x69, 0x70, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x52, - 0x0b, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x0c, - 0x63, 0x61, 0x6e, 0x5f, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0b, 0x63, 0x61, 0x6e, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0xd0, - 0x01, 0x0a, 0x07, 0x55, 0x73, 0x65, 0x72, 0x56, 0x69, 0x70, 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, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x61, - 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, - 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, - 0x73, 0x22, 0x6b, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x69, 0x70, 0x50, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, - 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, - 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x8b, - 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x69, 0x70, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x56, 0x69, 0x70, 0x52, 0x0a, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x56, 0x69, 0x70, 0x12, 0x35, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x69, 0x70, 0x4c, 0x65, 0x76, - 0x65, 0x6c, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x22, 0x64, 0x0a, 0x0f, - 0x47, 0x65, 0x74, 0x4d, 0x79, 0x56, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x12, 0x2b, 0x0a, 0x12, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x42, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x12, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x11, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x19, + 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, + 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x78, 0x0a, + 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x74, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xf8, 0x01, 0x0a, 0x20, 0x4c, 0x69, 0x73, 0x74, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, + 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, + 0x72, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, + 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, + 0x7a, 0x65, 0x22, 0x77, 0x0a, 0x21, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, + 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x68, + 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x08, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0xe0, 0x02, 0x0a, 0x1c, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, + 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x69, + 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x03, 0x52, + 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0xff, + 0x02, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, + 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x22, 0x3e, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x56, 0x69, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x76, 0x69, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x56, 0x69, 0x70, 0x52, 0x03, 0x76, - 0x69, 0x70, 0x22, 0x7d, 0x0a, 0x12, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x69, - 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, + 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x70, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x63, + 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, + 0x03, 0x52, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, + 0x22, 0xa1, 0x01, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x63, 0x68, 0x61, + 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x22, 0x55, 0x0a, 0x17, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, + 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3a, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x22, 0x39, 0x0a, 0x1d, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0xde, 0x01, 0x0a, 0x13, 0x44, 0x69, 0x61, 0x6d, 0x6f, + 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x23, + 0x0a, 0x0d, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x73, 0x73, 0x65, + 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x72, + 0x6f, 0x6d, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x74, + 0x6f, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x74, 0x6f, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x08, 0x74, 0x6f, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, + 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x74, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x44, 0x69, + 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x5e, 0x0a, + 0x20, 0x47, 0x65, 0x74, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x96, 0x03, + 0x0a, 0x11, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x25, + 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x69, 0x7a, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x69, 0x7a, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x27, 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x6c, + 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x7a, + 0x65, 0x6e, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, + 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x27, 0x0a, 0x0f, 0x61, + 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x41, + 0x66, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x5f, 0x61, + 0x66, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x7a, + 0x65, 0x6e, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x70, 0x61, 0x72, 0x74, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x61, + 0x72, 0x74, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, + 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, + 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x5f, 0x6d, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xc2, 0x01, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, - 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, - 0x6c, 0x22, 0x93, 0x02, 0x0a, 0x13, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x69, - 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x72, 0x64, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x72, 0x64, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x03, 0x76, - 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x56, - 0x69, 0x70, 0x52, 0x03, 0x76, 0x69, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x5f, - 0x73, 0x70, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x69, - 0x6e, 0x53, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x62, - 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x10, 0x63, 0x6f, 0x69, 0x6e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x41, - 0x66, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x69, 0x70, - 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0b, 0x72, 0x65, 0x77, 0x61, - 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xfc, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x64, - 0x69, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x24, 0x0a, - 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, + 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x7e, 0x0a, 0x1e, 0x4c, + 0x69, 0x73, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, + 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0xa7, 0x02, 0x0a, 0x11, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x61, 0x6c, 0x49, 0x64, 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, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x25, + 0x0a, 0x0e, 0x70, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x22, 0x0a, + 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, + 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, + 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xc2, 0x01, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x57, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, + 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, - 0x61, 0x73, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x74, 0x61, 0x73, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, - 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, - 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x16, - 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x64, 0x69, - 0x74, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x37, 0x0a, 0x07, 0x62, 0x61, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, + 0x61, 0x79, 0x6f, 0x75, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x96, 0x01, 0x0a, 0x17, 0x41, + 0x70, 0x70, 0x6c, 0x79, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x69, 0x74, + 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, + 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x12, 0x37, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x67, - 0x72, 0x61, 0x6e, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0b, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, - 0x9a, 0x03, 0x0a, 0x1a, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, + 0x6e, 0x63, 0x65, 0x22, 0xce, 0x01, 0x0a, 0x0d, 0x56, 0x69, 0x70, 0x52, 0x65, 0x77, 0x61, 0x72, + 0x64, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x5f, 0x6d, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x41, 0x74, 0x4d, 0x73, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x56, 0x69, 0x70, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x69, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x70, 0x72, 0x69, 0x63, 0x65, 0x43, 0x6f, + 0x69, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, + 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x41, 0x0a, 0x0c, + 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x69, 0x70, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, + 0x65, 0x6d, 0x52, 0x0b, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x63, 0x61, 0x6e, 0x5f, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x63, 0x61, 0x6e, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, + 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x22, 0xd0, 0x01, 0x0a, 0x07, 0x55, 0x73, 0x65, 0x72, 0x56, 0x69, 0x70, 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, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x4d, 0x73, + 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, + 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x4d, 0x73, 0x22, 0x6b, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x69, 0x70, 0x50, + 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x63, 0x6f, 0x64, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2a, - 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, - 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, - 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6f, 0x70, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0xa3, 0x01, 0x0a, - 0x1b, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x15, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x61, 0x66, 0x74, 0x65, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, - 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x10, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, - 0x61, 0x79, 0x32, 0xdb, 0x1d, 0x0a, 0x0d, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x69, 0x74, 0x47, 0x69, 0x66, - 0x74, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x69, 0x74, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x69, 0x74, 0x47, 0x69, 0x66, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x42, - 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x67, 0x0a, 0x10, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, - 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, - 0x65, 0x64, 0x69, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x41, 0x73, - 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x1a, - 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, - 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x12, 0x32, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, - 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, - 0x65, 0x72, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, + 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x22, 0x8b, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x69, 0x70, 0x50, 0x61, 0x63, + 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, + 0x0b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x56, 0x69, 0x70, 0x52, 0x0a, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x56, 0x69, 0x70, 0x12, 0x35, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, + 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x69, 0x70, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x22, + 0x64, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x56, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x3e, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x56, 0x69, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x76, 0x69, 0x70, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x56, 0x69, 0x70, + 0x52, 0x03, 0x76, 0x69, 0x70, 0x22, 0x7d, 0x0a, 0x12, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, + 0x65, 0x56, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, + 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, + 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x22, 0x93, 0x02, 0x0a, 0x13, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, + 0x65, 0x56, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2a, + 0x0a, 0x03, 0x76, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x56, 0x69, 0x70, 0x52, 0x03, 0x76, 0x69, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, + 0x69, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x63, 0x6f, 0x69, 0x6e, 0x53, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6f, 0x69, + 0x6e, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x6f, 0x69, 0x6e, 0x42, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x72, 0x65, 0x77, 0x61, 0x72, + 0x64, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x56, 0x69, 0x70, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0b, 0x72, + 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xfc, 0x01, 0x0a, 0x17, 0x43, + 0x72, 0x65, 0x64, 0x69, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x74, + 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, + 0x73, 0x6b, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x4b, 0x65, + 0x79, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x43, 0x72, + 0x65, 0x64, 0x69, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x37, 0x0a, + 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x69, 0x6e, - 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, - 0x6f, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x2e, 0x2e, + 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x07, 0x62, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, + 0x0a, 0x0d, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x73, 0x22, 0x9a, 0x03, 0x0a, 0x1a, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, 0x6d, 0x65, + 0x43, 0x6f, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x61, 0x6d, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x61, 0x6d, 0x65, 0x49, + 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2a, 0x0a, + 0x11, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, + 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6f, 0x70, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x70, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, + 0xa3, 0x01, 0x0a, 0x1b, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x32, 0x0a, 0x15, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x61, + 0x66, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6d, + 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x70, 0x6c, 0x61, 0x79, 0x32, 0xbc, 0x21, 0x0a, 0x0d, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x69, 0x74, + 0x47, 0x69, 0x66, 0x74, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x69, 0x74, 0x47, 0x69, 0x66, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x69, 0x74, 0x47, + 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0b, 0x47, + 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x10, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, + 0x65, 0x64, 0x69, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, + 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x85, + 0x01, 0x0a, 0x1a, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x43, 0x6f, + 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x12, 0x32, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, - 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, + 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x33, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x43, + 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, + 0x12, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x46, + 0x72, 0x6f, 0x6d, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x46, + 0x72, 0x6f, 0x6d, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x58, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, - 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, - 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, - 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, - 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x61, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, - 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x13, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x47, - 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x2a, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, - 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, - 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x61, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, + 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x28, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x6a, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x13, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x4c, 0x69, + 0x73, 0x74, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x27, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x66, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x61, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, + 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, - 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x0d, - 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x25, 0x2e, + 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x47, 0x69, 0x66, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, - 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x12, - 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, + 0x53, 0x65, 0x74, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x66, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x5e, 0x0a, 0x0d, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x68, 0x0a, 0x12, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x11, 0x4c, 0x69, 0x73, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x11, 0x45, 0x71, 0x75, 0x69, 0x70, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x71, 0x75, 0x69, 0x70, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x71, 0x75, 0x69, 0x70, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, - 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, - 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, - 0x72, 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, - 0x11, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x42, 0x69, 0x6c, - 0x6c, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, - 0x65, 0x42, 0x69, 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x42, 0x69, 0x6c, 0x6c, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x11, 0x47, 0x65, 0x74, - 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x12, 0x29, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, - 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x2d, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x75, - 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x73, 0x0a, - 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, - 0x64, 0x75, 0x63, 0x74, 0x73, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x11, 0x45, 0x71, 0x75, 0x69, 0x70, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x71, 0x75, + 0x69, 0x70, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x71, 0x75, 0x69, 0x70, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x6d, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x6a, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, + 0x42, 0x69, 0x6c, 0x6c, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, - 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, - 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x7f, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, - 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, + 0x61, 0x72, 0x67, 0x65, 0x42, 0x69, 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x42, + 0x69, 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x11, + 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, + 0x77, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4f, 0x76, 0x65, + 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x73, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, + 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x12, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, + 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x74, 0x73, 0x12, 0x31, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, + 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x15, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x63, 0x68, + 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x15, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x74, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76, + 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, + 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7f, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x69, 0x61, + 0x6d, 0x6f, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, + 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, + 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x57, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x61, 0x6c, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x57, 0x69, 0x74, + 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x31, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x61, 0x6d, 0x6f, 0x6e, 0x64, 0x45, 0x78, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x2e, + 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, + 0x56, 0x69, 0x70, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x27, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x56, 0x69, 0x70, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x69, 0x70, 0x50, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, + 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x56, 0x69, 0x70, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x4d, 0x79, 0x56, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x4d, 0x79, 0x56, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x58, 0x0a, 0x0b, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x69, 0x70, 0x12, 0x23, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x69, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x10, 0x43, 0x72, 0x65, + 0x64, 0x69, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, - 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, - 0x6c, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, - 0x77, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, - 0x6c, 0x79, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x69, 0x70, 0x50, - 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x69, - 0x70, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x69, 0x70, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x08, 0x47, 0x65, - 0x74, 0x4d, 0x79, 0x56, 0x69, 0x70, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x56, 0x69, - 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x79, - 0x56, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0b, 0x50, - 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x69, 0x70, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x72, - 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x69, 0x70, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x54, - 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, - 0x69, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x54, 0x61, 0x73, 0x6b, - 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, - 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, 0x6d, - 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, 0x6d, 0x65, 0x43, 0x6f, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x42, 0x2a, 0x5a, 0x28, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x2f, 0x76, 0x31, 0x3b, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, + 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x70, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, 0x6d, 0x65, 0x43, + 0x6f, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x79, 0x47, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x47, 0x61, + 0x6d, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x76, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -9162,7 +9971,7 @@ func file_proto_wallet_v1_wallet_proto_rawDescGZIP() []byte { return file_proto_wallet_v1_wallet_proto_rawDescData } -var file_proto_wallet_v1_wallet_proto_msgTypes = make([]protoimpl.MessageInfo, 84) +var file_proto_wallet_v1_wallet_proto_msgTypes = make([]protoimpl.MessageInfo, 91) var file_proto_wallet_v1_wallet_proto_goTypes = []any{ (*DebitGiftRequest)(nil), // 0: hyapp.wallet.v1.DebitGiftRequest (*DebitGiftResponse)(nil), // 1: hyapp.wallet.v1.DebitGiftResponse @@ -9226,28 +10035,35 @@ var file_proto_wallet_v1_wallet_proto_goTypes = []any{ (*RechargeProduct)(nil), // 59: hyapp.wallet.v1.RechargeProduct (*ListRechargeProductsRequest)(nil), // 60: hyapp.wallet.v1.ListRechargeProductsRequest (*ListRechargeProductsResponse)(nil), // 61: hyapp.wallet.v1.ListRechargeProductsResponse - (*DiamondExchangeRule)(nil), // 62: hyapp.wallet.v1.DiamondExchangeRule - (*GetDiamondExchangeConfigRequest)(nil), // 63: hyapp.wallet.v1.GetDiamondExchangeConfigRequest - (*GetDiamondExchangeConfigResponse)(nil), // 64: hyapp.wallet.v1.GetDiamondExchangeConfigResponse - (*WalletTransaction)(nil), // 65: hyapp.wallet.v1.WalletTransaction - (*ListWalletTransactionsRequest)(nil), // 66: hyapp.wallet.v1.ListWalletTransactionsRequest - (*ListWalletTransactionsResponse)(nil), // 67: hyapp.wallet.v1.ListWalletTransactionsResponse - (*WithdrawalRequest)(nil), // 68: hyapp.wallet.v1.WithdrawalRequest - (*ApplyWithdrawalRequest)(nil), // 69: hyapp.wallet.v1.ApplyWithdrawalRequest - (*ApplyWithdrawalResponse)(nil), // 70: hyapp.wallet.v1.ApplyWithdrawalResponse - (*VipRewardItem)(nil), // 71: hyapp.wallet.v1.VipRewardItem - (*VipLevel)(nil), // 72: hyapp.wallet.v1.VipLevel - (*UserVip)(nil), // 73: hyapp.wallet.v1.UserVip - (*ListVipPackagesRequest)(nil), // 74: hyapp.wallet.v1.ListVipPackagesRequest - (*ListVipPackagesResponse)(nil), // 75: hyapp.wallet.v1.ListVipPackagesResponse - (*GetMyVipRequest)(nil), // 76: hyapp.wallet.v1.GetMyVipRequest - (*GetMyVipResponse)(nil), // 77: hyapp.wallet.v1.GetMyVipResponse - (*PurchaseVipRequest)(nil), // 78: hyapp.wallet.v1.PurchaseVipRequest - (*PurchaseVipResponse)(nil), // 79: hyapp.wallet.v1.PurchaseVipResponse - (*CreditTaskRewardRequest)(nil), // 80: hyapp.wallet.v1.CreditTaskRewardRequest - (*CreditTaskRewardResponse)(nil), // 81: hyapp.wallet.v1.CreditTaskRewardResponse - (*ApplyGameCoinChangeRequest)(nil), // 82: hyapp.wallet.v1.ApplyGameCoinChangeRequest - (*ApplyGameCoinChangeResponse)(nil), // 83: hyapp.wallet.v1.ApplyGameCoinChangeResponse + (*ListAdminRechargeProductsRequest)(nil), // 62: hyapp.wallet.v1.ListAdminRechargeProductsRequest + (*ListAdminRechargeProductsResponse)(nil), // 63: hyapp.wallet.v1.ListAdminRechargeProductsResponse + (*CreateRechargeProductRequest)(nil), // 64: hyapp.wallet.v1.CreateRechargeProductRequest + (*UpdateRechargeProductRequest)(nil), // 65: hyapp.wallet.v1.UpdateRechargeProductRequest + (*DeleteRechargeProductRequest)(nil), // 66: hyapp.wallet.v1.DeleteRechargeProductRequest + (*RechargeProductResponse)(nil), // 67: hyapp.wallet.v1.RechargeProductResponse + (*DeleteRechargeProductResponse)(nil), // 68: hyapp.wallet.v1.DeleteRechargeProductResponse + (*DiamondExchangeRule)(nil), // 69: hyapp.wallet.v1.DiamondExchangeRule + (*GetDiamondExchangeConfigRequest)(nil), // 70: hyapp.wallet.v1.GetDiamondExchangeConfigRequest + (*GetDiamondExchangeConfigResponse)(nil), // 71: hyapp.wallet.v1.GetDiamondExchangeConfigResponse + (*WalletTransaction)(nil), // 72: hyapp.wallet.v1.WalletTransaction + (*ListWalletTransactionsRequest)(nil), // 73: hyapp.wallet.v1.ListWalletTransactionsRequest + (*ListWalletTransactionsResponse)(nil), // 74: hyapp.wallet.v1.ListWalletTransactionsResponse + (*WithdrawalRequest)(nil), // 75: hyapp.wallet.v1.WithdrawalRequest + (*ApplyWithdrawalRequest)(nil), // 76: hyapp.wallet.v1.ApplyWithdrawalRequest + (*ApplyWithdrawalResponse)(nil), // 77: hyapp.wallet.v1.ApplyWithdrawalResponse + (*VipRewardItem)(nil), // 78: hyapp.wallet.v1.VipRewardItem + (*VipLevel)(nil), // 79: hyapp.wallet.v1.VipLevel + (*UserVip)(nil), // 80: hyapp.wallet.v1.UserVip + (*ListVipPackagesRequest)(nil), // 81: hyapp.wallet.v1.ListVipPackagesRequest + (*ListVipPackagesResponse)(nil), // 82: hyapp.wallet.v1.ListVipPackagesResponse + (*GetMyVipRequest)(nil), // 83: hyapp.wallet.v1.GetMyVipRequest + (*GetMyVipResponse)(nil), // 84: hyapp.wallet.v1.GetMyVipResponse + (*PurchaseVipRequest)(nil), // 85: hyapp.wallet.v1.PurchaseVipRequest + (*PurchaseVipResponse)(nil), // 86: hyapp.wallet.v1.PurchaseVipResponse + (*CreditTaskRewardRequest)(nil), // 87: hyapp.wallet.v1.CreditTaskRewardRequest + (*CreditTaskRewardResponse)(nil), // 88: hyapp.wallet.v1.CreditTaskRewardResponse + (*ApplyGameCoinChangeRequest)(nil), // 89: hyapp.wallet.v1.ApplyGameCoinChangeRequest + (*ApplyGameCoinChangeResponse)(nil), // 90: hyapp.wallet.v1.ApplyGameCoinChangeResponse } var file_proto_wallet_v1_wallet_proto_depIdxs = []int32{ 2, // 0: hyapp.wallet.v1.GetBalancesResponse.balances:type_name -> hyapp.wallet.v1.AssetBalance @@ -9276,94 +10092,104 @@ var file_proto_wallet_v1_wallet_proto_depIdxs = []int32{ 53, // 23: hyapp.wallet.v1.GetWalletOverviewResponse.feature_flags:type_name -> hyapp.wallet.v1.WalletFeatureFlags 56, // 24: hyapp.wallet.v1.GetWalletValueSummaryResponse.summary:type_name -> hyapp.wallet.v1.WalletValueSummary 59, // 25: hyapp.wallet.v1.ListRechargeProductsResponse.products:type_name -> hyapp.wallet.v1.RechargeProduct - 62, // 26: hyapp.wallet.v1.GetDiamondExchangeConfigResponse.rules:type_name -> hyapp.wallet.v1.DiamondExchangeRule - 65, // 27: hyapp.wallet.v1.ListWalletTransactionsResponse.transactions:type_name -> hyapp.wallet.v1.WalletTransaction - 68, // 28: hyapp.wallet.v1.ApplyWithdrawalResponse.withdrawal:type_name -> hyapp.wallet.v1.WithdrawalRequest - 2, // 29: hyapp.wallet.v1.ApplyWithdrawalResponse.balance:type_name -> hyapp.wallet.v1.AssetBalance - 71, // 30: hyapp.wallet.v1.VipLevel.reward_items:type_name -> hyapp.wallet.v1.VipRewardItem - 73, // 31: hyapp.wallet.v1.ListVipPackagesResponse.current_vip:type_name -> hyapp.wallet.v1.UserVip - 72, // 32: hyapp.wallet.v1.ListVipPackagesResponse.packages:type_name -> hyapp.wallet.v1.VipLevel - 73, // 33: hyapp.wallet.v1.GetMyVipResponse.vip:type_name -> hyapp.wallet.v1.UserVip - 73, // 34: hyapp.wallet.v1.PurchaseVipResponse.vip:type_name -> hyapp.wallet.v1.UserVip - 71, // 35: hyapp.wallet.v1.PurchaseVipResponse.reward_items:type_name -> hyapp.wallet.v1.VipRewardItem - 2, // 36: hyapp.wallet.v1.CreditTaskRewardResponse.balance:type_name -> hyapp.wallet.v1.AssetBalance - 0, // 37: hyapp.wallet.v1.WalletService.DebitGift:input_type -> hyapp.wallet.v1.DebitGiftRequest - 3, // 38: hyapp.wallet.v1.WalletService.GetBalances:input_type -> hyapp.wallet.v1.GetBalancesRequest - 5, // 39: hyapp.wallet.v1.WalletService.AdminCreditAsset:input_type -> hyapp.wallet.v1.AdminCreditAssetRequest - 7, // 40: hyapp.wallet.v1.WalletService.AdminCreditCoinSellerStock:input_type -> hyapp.wallet.v1.AdminCreditCoinSellerStockRequest - 9, // 41: hyapp.wallet.v1.WalletService.TransferCoinFromSeller:input_type -> hyapp.wallet.v1.TransferCoinFromSellerRequest - 19, // 42: hyapp.wallet.v1.WalletService.ListResources:input_type -> hyapp.wallet.v1.ListResourcesRequest - 21, // 43: hyapp.wallet.v1.WalletService.GetResource:input_type -> hyapp.wallet.v1.GetResourceRequest - 23, // 44: hyapp.wallet.v1.WalletService.CreateResource:input_type -> hyapp.wallet.v1.CreateResourceRequest - 24, // 45: hyapp.wallet.v1.WalletService.UpdateResource:input_type -> hyapp.wallet.v1.UpdateResourceRequest - 25, // 46: hyapp.wallet.v1.WalletService.SetResourceStatus:input_type -> hyapp.wallet.v1.SetResourceStatusRequest - 27, // 47: hyapp.wallet.v1.WalletService.ListResourceGroups:input_type -> hyapp.wallet.v1.ListResourceGroupsRequest - 29, // 48: hyapp.wallet.v1.WalletService.GetResourceGroup:input_type -> hyapp.wallet.v1.GetResourceGroupRequest - 31, // 49: hyapp.wallet.v1.WalletService.CreateResourceGroup:input_type -> hyapp.wallet.v1.CreateResourceGroupRequest - 32, // 50: hyapp.wallet.v1.WalletService.UpdateResourceGroup:input_type -> hyapp.wallet.v1.UpdateResourceGroupRequest - 33, // 51: hyapp.wallet.v1.WalletService.SetResourceGroupStatus:input_type -> hyapp.wallet.v1.SetResourceGroupStatusRequest - 35, // 52: hyapp.wallet.v1.WalletService.ListGiftConfigs:input_type -> hyapp.wallet.v1.ListGiftConfigsRequest - 37, // 53: hyapp.wallet.v1.WalletService.CreateGiftConfig:input_type -> hyapp.wallet.v1.CreateGiftConfigRequest - 38, // 54: hyapp.wallet.v1.WalletService.UpdateGiftConfig:input_type -> hyapp.wallet.v1.UpdateGiftConfigRequest - 39, // 55: hyapp.wallet.v1.WalletService.SetGiftConfigStatus:input_type -> hyapp.wallet.v1.SetGiftConfigStatusRequest - 41, // 56: hyapp.wallet.v1.WalletService.GrantResource:input_type -> hyapp.wallet.v1.GrantResourceRequest - 42, // 57: hyapp.wallet.v1.WalletService.GrantResourceGroup:input_type -> hyapp.wallet.v1.GrantResourceGroupRequest - 44, // 58: hyapp.wallet.v1.WalletService.ListUserResources:input_type -> hyapp.wallet.v1.ListUserResourcesRequest - 46, // 59: hyapp.wallet.v1.WalletService.EquipUserResource:input_type -> hyapp.wallet.v1.EquipUserResourceRequest - 48, // 60: hyapp.wallet.v1.WalletService.ListResourceGrants:input_type -> hyapp.wallet.v1.ListResourceGrantsRequest - 51, // 61: hyapp.wallet.v1.WalletService.ListRechargeBills:input_type -> hyapp.wallet.v1.ListRechargeBillsRequest - 54, // 62: hyapp.wallet.v1.WalletService.GetWalletOverview:input_type -> hyapp.wallet.v1.GetWalletOverviewRequest - 57, // 63: hyapp.wallet.v1.WalletService.GetWalletValueSummary:input_type -> hyapp.wallet.v1.GetWalletValueSummaryRequest - 60, // 64: hyapp.wallet.v1.WalletService.ListRechargeProducts:input_type -> hyapp.wallet.v1.ListRechargeProductsRequest - 63, // 65: hyapp.wallet.v1.WalletService.GetDiamondExchangeConfig:input_type -> hyapp.wallet.v1.GetDiamondExchangeConfigRequest - 66, // 66: hyapp.wallet.v1.WalletService.ListWalletTransactions:input_type -> hyapp.wallet.v1.ListWalletTransactionsRequest - 69, // 67: hyapp.wallet.v1.WalletService.ApplyWithdrawal:input_type -> hyapp.wallet.v1.ApplyWithdrawalRequest - 74, // 68: hyapp.wallet.v1.WalletService.ListVipPackages:input_type -> hyapp.wallet.v1.ListVipPackagesRequest - 76, // 69: hyapp.wallet.v1.WalletService.GetMyVip:input_type -> hyapp.wallet.v1.GetMyVipRequest - 78, // 70: hyapp.wallet.v1.WalletService.PurchaseVip:input_type -> hyapp.wallet.v1.PurchaseVipRequest - 80, // 71: hyapp.wallet.v1.WalletService.CreditTaskReward:input_type -> hyapp.wallet.v1.CreditTaskRewardRequest - 82, // 72: hyapp.wallet.v1.WalletService.ApplyGameCoinChange:input_type -> hyapp.wallet.v1.ApplyGameCoinChangeRequest - 1, // 73: hyapp.wallet.v1.WalletService.DebitGift:output_type -> hyapp.wallet.v1.DebitGiftResponse - 4, // 74: hyapp.wallet.v1.WalletService.GetBalances:output_type -> hyapp.wallet.v1.GetBalancesResponse - 6, // 75: hyapp.wallet.v1.WalletService.AdminCreditAsset:output_type -> hyapp.wallet.v1.AdminCreditAssetResponse - 8, // 76: hyapp.wallet.v1.WalletService.AdminCreditCoinSellerStock:output_type -> hyapp.wallet.v1.AdminCreditCoinSellerStockResponse - 10, // 77: hyapp.wallet.v1.WalletService.TransferCoinFromSeller:output_type -> hyapp.wallet.v1.TransferCoinFromSellerResponse - 20, // 78: hyapp.wallet.v1.WalletService.ListResources:output_type -> hyapp.wallet.v1.ListResourcesResponse - 22, // 79: hyapp.wallet.v1.WalletService.GetResource:output_type -> hyapp.wallet.v1.GetResourceResponse - 26, // 80: hyapp.wallet.v1.WalletService.CreateResource:output_type -> hyapp.wallet.v1.ResourceResponse - 26, // 81: hyapp.wallet.v1.WalletService.UpdateResource:output_type -> hyapp.wallet.v1.ResourceResponse - 26, // 82: hyapp.wallet.v1.WalletService.SetResourceStatus:output_type -> hyapp.wallet.v1.ResourceResponse - 28, // 83: hyapp.wallet.v1.WalletService.ListResourceGroups:output_type -> hyapp.wallet.v1.ListResourceGroupsResponse - 30, // 84: hyapp.wallet.v1.WalletService.GetResourceGroup:output_type -> hyapp.wallet.v1.GetResourceGroupResponse - 34, // 85: hyapp.wallet.v1.WalletService.CreateResourceGroup:output_type -> hyapp.wallet.v1.ResourceGroupResponse - 34, // 86: hyapp.wallet.v1.WalletService.UpdateResourceGroup:output_type -> hyapp.wallet.v1.ResourceGroupResponse - 34, // 87: hyapp.wallet.v1.WalletService.SetResourceGroupStatus:output_type -> hyapp.wallet.v1.ResourceGroupResponse - 36, // 88: hyapp.wallet.v1.WalletService.ListGiftConfigs:output_type -> hyapp.wallet.v1.ListGiftConfigsResponse - 40, // 89: hyapp.wallet.v1.WalletService.CreateGiftConfig:output_type -> hyapp.wallet.v1.GiftConfigResponse - 40, // 90: hyapp.wallet.v1.WalletService.UpdateGiftConfig:output_type -> hyapp.wallet.v1.GiftConfigResponse - 40, // 91: hyapp.wallet.v1.WalletService.SetGiftConfigStatus:output_type -> hyapp.wallet.v1.GiftConfigResponse - 43, // 92: hyapp.wallet.v1.WalletService.GrantResource:output_type -> hyapp.wallet.v1.ResourceGrantResponse - 43, // 93: hyapp.wallet.v1.WalletService.GrantResourceGroup:output_type -> hyapp.wallet.v1.ResourceGrantResponse - 45, // 94: hyapp.wallet.v1.WalletService.ListUserResources:output_type -> hyapp.wallet.v1.ListUserResourcesResponse - 47, // 95: hyapp.wallet.v1.WalletService.EquipUserResource:output_type -> hyapp.wallet.v1.EquipUserResourceResponse - 49, // 96: hyapp.wallet.v1.WalletService.ListResourceGrants:output_type -> hyapp.wallet.v1.ListResourceGrantsResponse - 52, // 97: hyapp.wallet.v1.WalletService.ListRechargeBills:output_type -> hyapp.wallet.v1.ListRechargeBillsResponse - 55, // 98: hyapp.wallet.v1.WalletService.GetWalletOverview:output_type -> hyapp.wallet.v1.GetWalletOverviewResponse - 58, // 99: hyapp.wallet.v1.WalletService.GetWalletValueSummary:output_type -> hyapp.wallet.v1.GetWalletValueSummaryResponse - 61, // 100: hyapp.wallet.v1.WalletService.ListRechargeProducts:output_type -> hyapp.wallet.v1.ListRechargeProductsResponse - 64, // 101: hyapp.wallet.v1.WalletService.GetDiamondExchangeConfig:output_type -> hyapp.wallet.v1.GetDiamondExchangeConfigResponse - 67, // 102: hyapp.wallet.v1.WalletService.ListWalletTransactions:output_type -> hyapp.wallet.v1.ListWalletTransactionsResponse - 70, // 103: hyapp.wallet.v1.WalletService.ApplyWithdrawal:output_type -> hyapp.wallet.v1.ApplyWithdrawalResponse - 75, // 104: hyapp.wallet.v1.WalletService.ListVipPackages:output_type -> hyapp.wallet.v1.ListVipPackagesResponse - 77, // 105: hyapp.wallet.v1.WalletService.GetMyVip:output_type -> hyapp.wallet.v1.GetMyVipResponse - 79, // 106: hyapp.wallet.v1.WalletService.PurchaseVip:output_type -> hyapp.wallet.v1.PurchaseVipResponse - 81, // 107: hyapp.wallet.v1.WalletService.CreditTaskReward:output_type -> hyapp.wallet.v1.CreditTaskRewardResponse - 83, // 108: hyapp.wallet.v1.WalletService.ApplyGameCoinChange:output_type -> hyapp.wallet.v1.ApplyGameCoinChangeResponse - 73, // [73:109] is the sub-list for method output_type - 37, // [37:73] is the sub-list for method input_type - 37, // [37:37] is the sub-list for extension type_name - 37, // [37:37] is the sub-list for extension extendee - 0, // [0:37] is the sub-list for field type_name + 59, // 26: hyapp.wallet.v1.ListAdminRechargeProductsResponse.products:type_name -> hyapp.wallet.v1.RechargeProduct + 59, // 27: hyapp.wallet.v1.RechargeProductResponse.product:type_name -> hyapp.wallet.v1.RechargeProduct + 69, // 28: hyapp.wallet.v1.GetDiamondExchangeConfigResponse.rules:type_name -> hyapp.wallet.v1.DiamondExchangeRule + 72, // 29: hyapp.wallet.v1.ListWalletTransactionsResponse.transactions:type_name -> hyapp.wallet.v1.WalletTransaction + 75, // 30: hyapp.wallet.v1.ApplyWithdrawalResponse.withdrawal:type_name -> hyapp.wallet.v1.WithdrawalRequest + 2, // 31: hyapp.wallet.v1.ApplyWithdrawalResponse.balance:type_name -> hyapp.wallet.v1.AssetBalance + 78, // 32: hyapp.wallet.v1.VipLevel.reward_items:type_name -> hyapp.wallet.v1.VipRewardItem + 80, // 33: hyapp.wallet.v1.ListVipPackagesResponse.current_vip:type_name -> hyapp.wallet.v1.UserVip + 79, // 34: hyapp.wallet.v1.ListVipPackagesResponse.packages:type_name -> hyapp.wallet.v1.VipLevel + 80, // 35: hyapp.wallet.v1.GetMyVipResponse.vip:type_name -> hyapp.wallet.v1.UserVip + 80, // 36: hyapp.wallet.v1.PurchaseVipResponse.vip:type_name -> hyapp.wallet.v1.UserVip + 78, // 37: hyapp.wallet.v1.PurchaseVipResponse.reward_items:type_name -> hyapp.wallet.v1.VipRewardItem + 2, // 38: hyapp.wallet.v1.CreditTaskRewardResponse.balance:type_name -> hyapp.wallet.v1.AssetBalance + 0, // 39: hyapp.wallet.v1.WalletService.DebitGift:input_type -> hyapp.wallet.v1.DebitGiftRequest + 3, // 40: hyapp.wallet.v1.WalletService.GetBalances:input_type -> hyapp.wallet.v1.GetBalancesRequest + 5, // 41: hyapp.wallet.v1.WalletService.AdminCreditAsset:input_type -> hyapp.wallet.v1.AdminCreditAssetRequest + 7, // 42: hyapp.wallet.v1.WalletService.AdminCreditCoinSellerStock:input_type -> hyapp.wallet.v1.AdminCreditCoinSellerStockRequest + 9, // 43: hyapp.wallet.v1.WalletService.TransferCoinFromSeller:input_type -> hyapp.wallet.v1.TransferCoinFromSellerRequest + 19, // 44: hyapp.wallet.v1.WalletService.ListResources:input_type -> hyapp.wallet.v1.ListResourcesRequest + 21, // 45: hyapp.wallet.v1.WalletService.GetResource:input_type -> hyapp.wallet.v1.GetResourceRequest + 23, // 46: hyapp.wallet.v1.WalletService.CreateResource:input_type -> hyapp.wallet.v1.CreateResourceRequest + 24, // 47: hyapp.wallet.v1.WalletService.UpdateResource:input_type -> hyapp.wallet.v1.UpdateResourceRequest + 25, // 48: hyapp.wallet.v1.WalletService.SetResourceStatus:input_type -> hyapp.wallet.v1.SetResourceStatusRequest + 27, // 49: hyapp.wallet.v1.WalletService.ListResourceGroups:input_type -> hyapp.wallet.v1.ListResourceGroupsRequest + 29, // 50: hyapp.wallet.v1.WalletService.GetResourceGroup:input_type -> hyapp.wallet.v1.GetResourceGroupRequest + 31, // 51: hyapp.wallet.v1.WalletService.CreateResourceGroup:input_type -> hyapp.wallet.v1.CreateResourceGroupRequest + 32, // 52: hyapp.wallet.v1.WalletService.UpdateResourceGroup:input_type -> hyapp.wallet.v1.UpdateResourceGroupRequest + 33, // 53: hyapp.wallet.v1.WalletService.SetResourceGroupStatus:input_type -> hyapp.wallet.v1.SetResourceGroupStatusRequest + 35, // 54: hyapp.wallet.v1.WalletService.ListGiftConfigs:input_type -> hyapp.wallet.v1.ListGiftConfigsRequest + 37, // 55: hyapp.wallet.v1.WalletService.CreateGiftConfig:input_type -> hyapp.wallet.v1.CreateGiftConfigRequest + 38, // 56: hyapp.wallet.v1.WalletService.UpdateGiftConfig:input_type -> hyapp.wallet.v1.UpdateGiftConfigRequest + 39, // 57: hyapp.wallet.v1.WalletService.SetGiftConfigStatus:input_type -> hyapp.wallet.v1.SetGiftConfigStatusRequest + 41, // 58: hyapp.wallet.v1.WalletService.GrantResource:input_type -> hyapp.wallet.v1.GrantResourceRequest + 42, // 59: hyapp.wallet.v1.WalletService.GrantResourceGroup:input_type -> hyapp.wallet.v1.GrantResourceGroupRequest + 44, // 60: hyapp.wallet.v1.WalletService.ListUserResources:input_type -> hyapp.wallet.v1.ListUserResourcesRequest + 46, // 61: hyapp.wallet.v1.WalletService.EquipUserResource:input_type -> hyapp.wallet.v1.EquipUserResourceRequest + 48, // 62: hyapp.wallet.v1.WalletService.ListResourceGrants:input_type -> hyapp.wallet.v1.ListResourceGrantsRequest + 51, // 63: hyapp.wallet.v1.WalletService.ListRechargeBills:input_type -> hyapp.wallet.v1.ListRechargeBillsRequest + 54, // 64: hyapp.wallet.v1.WalletService.GetWalletOverview:input_type -> hyapp.wallet.v1.GetWalletOverviewRequest + 57, // 65: hyapp.wallet.v1.WalletService.GetWalletValueSummary:input_type -> hyapp.wallet.v1.GetWalletValueSummaryRequest + 60, // 66: hyapp.wallet.v1.WalletService.ListRechargeProducts:input_type -> hyapp.wallet.v1.ListRechargeProductsRequest + 62, // 67: hyapp.wallet.v1.WalletService.ListAdminRechargeProducts:input_type -> hyapp.wallet.v1.ListAdminRechargeProductsRequest + 64, // 68: hyapp.wallet.v1.WalletService.CreateRechargeProduct:input_type -> hyapp.wallet.v1.CreateRechargeProductRequest + 65, // 69: hyapp.wallet.v1.WalletService.UpdateRechargeProduct:input_type -> hyapp.wallet.v1.UpdateRechargeProductRequest + 66, // 70: hyapp.wallet.v1.WalletService.DeleteRechargeProduct:input_type -> hyapp.wallet.v1.DeleteRechargeProductRequest + 70, // 71: hyapp.wallet.v1.WalletService.GetDiamondExchangeConfig:input_type -> hyapp.wallet.v1.GetDiamondExchangeConfigRequest + 73, // 72: hyapp.wallet.v1.WalletService.ListWalletTransactions:input_type -> hyapp.wallet.v1.ListWalletTransactionsRequest + 76, // 73: hyapp.wallet.v1.WalletService.ApplyWithdrawal:input_type -> hyapp.wallet.v1.ApplyWithdrawalRequest + 81, // 74: hyapp.wallet.v1.WalletService.ListVipPackages:input_type -> hyapp.wallet.v1.ListVipPackagesRequest + 83, // 75: hyapp.wallet.v1.WalletService.GetMyVip:input_type -> hyapp.wallet.v1.GetMyVipRequest + 85, // 76: hyapp.wallet.v1.WalletService.PurchaseVip:input_type -> hyapp.wallet.v1.PurchaseVipRequest + 87, // 77: hyapp.wallet.v1.WalletService.CreditTaskReward:input_type -> hyapp.wallet.v1.CreditTaskRewardRequest + 89, // 78: hyapp.wallet.v1.WalletService.ApplyGameCoinChange:input_type -> hyapp.wallet.v1.ApplyGameCoinChangeRequest + 1, // 79: hyapp.wallet.v1.WalletService.DebitGift:output_type -> hyapp.wallet.v1.DebitGiftResponse + 4, // 80: hyapp.wallet.v1.WalletService.GetBalances:output_type -> hyapp.wallet.v1.GetBalancesResponse + 6, // 81: hyapp.wallet.v1.WalletService.AdminCreditAsset:output_type -> hyapp.wallet.v1.AdminCreditAssetResponse + 8, // 82: hyapp.wallet.v1.WalletService.AdminCreditCoinSellerStock:output_type -> hyapp.wallet.v1.AdminCreditCoinSellerStockResponse + 10, // 83: hyapp.wallet.v1.WalletService.TransferCoinFromSeller:output_type -> hyapp.wallet.v1.TransferCoinFromSellerResponse + 20, // 84: hyapp.wallet.v1.WalletService.ListResources:output_type -> hyapp.wallet.v1.ListResourcesResponse + 22, // 85: hyapp.wallet.v1.WalletService.GetResource:output_type -> hyapp.wallet.v1.GetResourceResponse + 26, // 86: hyapp.wallet.v1.WalletService.CreateResource:output_type -> hyapp.wallet.v1.ResourceResponse + 26, // 87: hyapp.wallet.v1.WalletService.UpdateResource:output_type -> hyapp.wallet.v1.ResourceResponse + 26, // 88: hyapp.wallet.v1.WalletService.SetResourceStatus:output_type -> hyapp.wallet.v1.ResourceResponse + 28, // 89: hyapp.wallet.v1.WalletService.ListResourceGroups:output_type -> hyapp.wallet.v1.ListResourceGroupsResponse + 30, // 90: hyapp.wallet.v1.WalletService.GetResourceGroup:output_type -> hyapp.wallet.v1.GetResourceGroupResponse + 34, // 91: hyapp.wallet.v1.WalletService.CreateResourceGroup:output_type -> hyapp.wallet.v1.ResourceGroupResponse + 34, // 92: hyapp.wallet.v1.WalletService.UpdateResourceGroup:output_type -> hyapp.wallet.v1.ResourceGroupResponse + 34, // 93: hyapp.wallet.v1.WalletService.SetResourceGroupStatus:output_type -> hyapp.wallet.v1.ResourceGroupResponse + 36, // 94: hyapp.wallet.v1.WalletService.ListGiftConfigs:output_type -> hyapp.wallet.v1.ListGiftConfigsResponse + 40, // 95: hyapp.wallet.v1.WalletService.CreateGiftConfig:output_type -> hyapp.wallet.v1.GiftConfigResponse + 40, // 96: hyapp.wallet.v1.WalletService.UpdateGiftConfig:output_type -> hyapp.wallet.v1.GiftConfigResponse + 40, // 97: hyapp.wallet.v1.WalletService.SetGiftConfigStatus:output_type -> hyapp.wallet.v1.GiftConfigResponse + 43, // 98: hyapp.wallet.v1.WalletService.GrantResource:output_type -> hyapp.wallet.v1.ResourceGrantResponse + 43, // 99: hyapp.wallet.v1.WalletService.GrantResourceGroup:output_type -> hyapp.wallet.v1.ResourceGrantResponse + 45, // 100: hyapp.wallet.v1.WalletService.ListUserResources:output_type -> hyapp.wallet.v1.ListUserResourcesResponse + 47, // 101: hyapp.wallet.v1.WalletService.EquipUserResource:output_type -> hyapp.wallet.v1.EquipUserResourceResponse + 49, // 102: hyapp.wallet.v1.WalletService.ListResourceGrants:output_type -> hyapp.wallet.v1.ListResourceGrantsResponse + 52, // 103: hyapp.wallet.v1.WalletService.ListRechargeBills:output_type -> hyapp.wallet.v1.ListRechargeBillsResponse + 55, // 104: hyapp.wallet.v1.WalletService.GetWalletOverview:output_type -> hyapp.wallet.v1.GetWalletOverviewResponse + 58, // 105: hyapp.wallet.v1.WalletService.GetWalletValueSummary:output_type -> hyapp.wallet.v1.GetWalletValueSummaryResponse + 61, // 106: hyapp.wallet.v1.WalletService.ListRechargeProducts:output_type -> hyapp.wallet.v1.ListRechargeProductsResponse + 63, // 107: hyapp.wallet.v1.WalletService.ListAdminRechargeProducts:output_type -> hyapp.wallet.v1.ListAdminRechargeProductsResponse + 67, // 108: hyapp.wallet.v1.WalletService.CreateRechargeProduct:output_type -> hyapp.wallet.v1.RechargeProductResponse + 67, // 109: hyapp.wallet.v1.WalletService.UpdateRechargeProduct:output_type -> hyapp.wallet.v1.RechargeProductResponse + 68, // 110: hyapp.wallet.v1.WalletService.DeleteRechargeProduct:output_type -> hyapp.wallet.v1.DeleteRechargeProductResponse + 71, // 111: hyapp.wallet.v1.WalletService.GetDiamondExchangeConfig:output_type -> hyapp.wallet.v1.GetDiamondExchangeConfigResponse + 74, // 112: hyapp.wallet.v1.WalletService.ListWalletTransactions:output_type -> hyapp.wallet.v1.ListWalletTransactionsResponse + 77, // 113: hyapp.wallet.v1.WalletService.ApplyWithdrawal:output_type -> hyapp.wallet.v1.ApplyWithdrawalResponse + 82, // 114: hyapp.wallet.v1.WalletService.ListVipPackages:output_type -> hyapp.wallet.v1.ListVipPackagesResponse + 84, // 115: hyapp.wallet.v1.WalletService.GetMyVip:output_type -> hyapp.wallet.v1.GetMyVipResponse + 86, // 116: hyapp.wallet.v1.WalletService.PurchaseVip:output_type -> hyapp.wallet.v1.PurchaseVipResponse + 88, // 117: hyapp.wallet.v1.WalletService.CreditTaskReward:output_type -> hyapp.wallet.v1.CreditTaskRewardResponse + 90, // 118: hyapp.wallet.v1.WalletService.ApplyGameCoinChange:output_type -> hyapp.wallet.v1.ApplyGameCoinChangeResponse + 79, // [79:119] is the sub-list for method output_type + 39, // [39:79] is the sub-list for method input_type + 39, // [39:39] is the sub-list for extension type_name + 39, // [39:39] is the sub-list for extension extendee + 0, // [0:39] is the sub-list for field type_name } func init() { file_proto_wallet_v1_wallet_proto_init() } @@ -9379,7 +10205,7 @@ func file_proto_wallet_v1_wallet_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_wallet_v1_wallet_proto_rawDesc, NumEnums: 0, - NumMessages: 84, + NumMessages: 91, NumExtensions: 0, NumServices: 1, }, diff --git a/api/proto/wallet/v1/wallet.proto b/api/proto/wallet/v1/wallet.proto index ffeed403..96d90f83 100644 --- a/api/proto/wallet/v1/wallet.proto +++ b/api/proto/wallet/v1/wallet.proto @@ -629,6 +629,18 @@ message RechargeProduct { string policy_version = 7; bool enabled = 8; int32 sort_order = 9; + string product_name = 10; + string description = 11; + string platform = 12; + repeated int64 region_ids = 13; + string resource_asset_type = 14; + int64 amount_micro = 15; + int64 created_by_user_id = 16; + int64 updated_by_user_id = 17; + int64 created_at_ms = 18; + int64 updated_at_ms = 19; + string app_code = 20; + string status = 21; } message ListRechargeProductsRequest { @@ -636,6 +648,8 @@ message ListRechargeProductsRequest { string app_code = 2; int64 user_id = 3; int64 region_id = 4; + // platform 来自 gateway 解析的 App 平台请求头;为空时返回该区域全部已上架商品。 + string platform = 5; } message ListRechargeProductsResponse { @@ -643,6 +657,66 @@ message ListRechargeProductsResponse { repeated string channels = 2; } +// ListAdminRechargeProductsRequest 是后台内购配置列表查询,不参与用户充值主链路。 +message ListAdminRechargeProductsRequest { + string request_id = 1; + string app_code = 2; + string status = 3; + string platform = 4; + int64 region_id = 5; + string keyword = 6; + int32 page = 7; + int32 page_size = 8; +} + +message ListAdminRechargeProductsResponse { + repeated RechargeProduct products = 1; + int64 total = 2; +} + +// CreateRechargeProductRequest 配置一个 App 内购商品;首版资源资产固定为 COIN。 +message CreateRechargeProductRequest { + string request_id = 1; + string app_code = 2; + int64 amount_micro = 3; + int64 coin_amount = 4; + string product_name = 5; + string description = 6; + string platform = 7; + repeated int64 region_ids = 8; + bool enabled = 9; + int64 operator_user_id = 10; +} + +message UpdateRechargeProductRequest { + string request_id = 1; + string app_code = 2; + int64 product_id = 3; + int64 amount_micro = 4; + int64 coin_amount = 5; + string product_name = 6; + string description = 7; + string platform = 8; + repeated int64 region_ids = 9; + bool enabled = 10; + int64 operator_user_id = 11; +} + +message DeleteRechargeProductRequest { + string request_id = 1; + string app_code = 2; + int64 product_id = 3; + int64 operator_user_id = 4; +} + +message RechargeProductResponse { + RechargeProduct product = 1; +} + +message DeleteRechargeProductResponse { + bool deleted = 1; +} + message DiamondExchangeRule { string exchange_type = 1; string from_asset_type = 2; @@ -858,6 +932,10 @@ service WalletService { rpc GetWalletOverview(GetWalletOverviewRequest) returns (GetWalletOverviewResponse); rpc GetWalletValueSummary(GetWalletValueSummaryRequest) returns (GetWalletValueSummaryResponse); rpc ListRechargeProducts(ListRechargeProductsRequest) returns (ListRechargeProductsResponse); + rpc ListAdminRechargeProducts(ListAdminRechargeProductsRequest) returns (ListAdminRechargeProductsResponse); + rpc CreateRechargeProduct(CreateRechargeProductRequest) returns (RechargeProductResponse); + rpc UpdateRechargeProduct(UpdateRechargeProductRequest) returns (RechargeProductResponse); + rpc DeleteRechargeProduct(DeleteRechargeProductRequest) returns (DeleteRechargeProductResponse); rpc GetDiamondExchangeConfig(GetDiamondExchangeConfigRequest) returns (GetDiamondExchangeConfigResponse); rpc ListWalletTransactions(ListWalletTransactionsRequest) returns (ListWalletTransactionsResponse); rpc ApplyWithdrawal(ApplyWithdrawalRequest) returns (ApplyWithdrawalResponse); diff --git a/api/proto/wallet/v1/wallet_grpc.pb.go b/api/proto/wallet/v1/wallet_grpc.pb.go index 3502b5fc..f61e372d 100644 --- a/api/proto/wallet/v1/wallet_grpc.pb.go +++ b/api/proto/wallet/v1/wallet_grpc.pb.go @@ -47,6 +47,10 @@ const ( WalletService_GetWalletOverview_FullMethodName = "/hyapp.wallet.v1.WalletService/GetWalletOverview" WalletService_GetWalletValueSummary_FullMethodName = "/hyapp.wallet.v1.WalletService/GetWalletValueSummary" WalletService_ListRechargeProducts_FullMethodName = "/hyapp.wallet.v1.WalletService/ListRechargeProducts" + WalletService_ListAdminRechargeProducts_FullMethodName = "/hyapp.wallet.v1.WalletService/ListAdminRechargeProducts" + WalletService_CreateRechargeProduct_FullMethodName = "/hyapp.wallet.v1.WalletService/CreateRechargeProduct" + WalletService_UpdateRechargeProduct_FullMethodName = "/hyapp.wallet.v1.WalletService/UpdateRechargeProduct" + WalletService_DeleteRechargeProduct_FullMethodName = "/hyapp.wallet.v1.WalletService/DeleteRechargeProduct" WalletService_GetDiamondExchangeConfig_FullMethodName = "/hyapp.wallet.v1.WalletService/GetDiamondExchangeConfig" WalletService_ListWalletTransactions_FullMethodName = "/hyapp.wallet.v1.WalletService/ListWalletTransactions" WalletService_ApplyWithdrawal_FullMethodName = "/hyapp.wallet.v1.WalletService/ApplyWithdrawal" @@ -91,6 +95,10 @@ type WalletServiceClient interface { GetWalletOverview(ctx context.Context, in *GetWalletOverviewRequest, opts ...grpc.CallOption) (*GetWalletOverviewResponse, error) GetWalletValueSummary(ctx context.Context, in *GetWalletValueSummaryRequest, opts ...grpc.CallOption) (*GetWalletValueSummaryResponse, error) ListRechargeProducts(ctx context.Context, in *ListRechargeProductsRequest, opts ...grpc.CallOption) (*ListRechargeProductsResponse, error) + ListAdminRechargeProducts(ctx context.Context, in *ListAdminRechargeProductsRequest, opts ...grpc.CallOption) (*ListAdminRechargeProductsResponse, error) + CreateRechargeProduct(ctx context.Context, in *CreateRechargeProductRequest, opts ...grpc.CallOption) (*RechargeProductResponse, error) + UpdateRechargeProduct(ctx context.Context, in *UpdateRechargeProductRequest, opts ...grpc.CallOption) (*RechargeProductResponse, error) + DeleteRechargeProduct(ctx context.Context, in *DeleteRechargeProductRequest, opts ...grpc.CallOption) (*DeleteRechargeProductResponse, error) GetDiamondExchangeConfig(ctx context.Context, in *GetDiamondExchangeConfigRequest, opts ...grpc.CallOption) (*GetDiamondExchangeConfigResponse, error) ListWalletTransactions(ctx context.Context, in *ListWalletTransactionsRequest, opts ...grpc.CallOption) (*ListWalletTransactionsResponse, error) ApplyWithdrawal(ctx context.Context, in *ApplyWithdrawalRequest, opts ...grpc.CallOption) (*ApplyWithdrawalResponse, error) @@ -389,6 +397,46 @@ func (c *walletServiceClient) ListRechargeProducts(ctx context.Context, in *List return out, nil } +func (c *walletServiceClient) ListAdminRechargeProducts(ctx context.Context, in *ListAdminRechargeProductsRequest, opts ...grpc.CallOption) (*ListAdminRechargeProductsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListAdminRechargeProductsResponse) + err := c.cc.Invoke(ctx, WalletService_ListAdminRechargeProducts_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *walletServiceClient) CreateRechargeProduct(ctx context.Context, in *CreateRechargeProductRequest, opts ...grpc.CallOption) (*RechargeProductResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RechargeProductResponse) + err := c.cc.Invoke(ctx, WalletService_CreateRechargeProduct_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *walletServiceClient) UpdateRechargeProduct(ctx context.Context, in *UpdateRechargeProductRequest, opts ...grpc.CallOption) (*RechargeProductResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RechargeProductResponse) + err := c.cc.Invoke(ctx, WalletService_UpdateRechargeProduct_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *walletServiceClient) DeleteRechargeProduct(ctx context.Context, in *DeleteRechargeProductRequest, opts ...grpc.CallOption) (*DeleteRechargeProductResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteRechargeProductResponse) + err := c.cc.Invoke(ctx, WalletService_DeleteRechargeProduct_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *walletServiceClient) GetDiamondExchangeConfig(ctx context.Context, in *GetDiamondExchangeConfigRequest, opts ...grpc.CallOption) (*GetDiamondExchangeConfigResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetDiamondExchangeConfigResponse) @@ -503,6 +551,10 @@ type WalletServiceServer interface { GetWalletOverview(context.Context, *GetWalletOverviewRequest) (*GetWalletOverviewResponse, error) GetWalletValueSummary(context.Context, *GetWalletValueSummaryRequest) (*GetWalletValueSummaryResponse, error) ListRechargeProducts(context.Context, *ListRechargeProductsRequest) (*ListRechargeProductsResponse, error) + ListAdminRechargeProducts(context.Context, *ListAdminRechargeProductsRequest) (*ListAdminRechargeProductsResponse, error) + CreateRechargeProduct(context.Context, *CreateRechargeProductRequest) (*RechargeProductResponse, error) + UpdateRechargeProduct(context.Context, *UpdateRechargeProductRequest) (*RechargeProductResponse, error) + DeleteRechargeProduct(context.Context, *DeleteRechargeProductRequest) (*DeleteRechargeProductResponse, error) GetDiamondExchangeConfig(context.Context, *GetDiamondExchangeConfigRequest) (*GetDiamondExchangeConfigResponse, error) ListWalletTransactions(context.Context, *ListWalletTransactionsRequest) (*ListWalletTransactionsResponse, error) ApplyWithdrawal(context.Context, *ApplyWithdrawalRequest) (*ApplyWithdrawalResponse, error) @@ -605,6 +657,18 @@ func (UnimplementedWalletServiceServer) GetWalletValueSummary(context.Context, * func (UnimplementedWalletServiceServer) ListRechargeProducts(context.Context, *ListRechargeProductsRequest) (*ListRechargeProductsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListRechargeProducts not implemented") } +func (UnimplementedWalletServiceServer) ListAdminRechargeProducts(context.Context, *ListAdminRechargeProductsRequest) (*ListAdminRechargeProductsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListAdminRechargeProducts not implemented") +} +func (UnimplementedWalletServiceServer) CreateRechargeProduct(context.Context, *CreateRechargeProductRequest) (*RechargeProductResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateRechargeProduct not implemented") +} +func (UnimplementedWalletServiceServer) UpdateRechargeProduct(context.Context, *UpdateRechargeProductRequest) (*RechargeProductResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateRechargeProduct not implemented") +} +func (UnimplementedWalletServiceServer) DeleteRechargeProduct(context.Context, *DeleteRechargeProductRequest) (*DeleteRechargeProductResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteRechargeProduct not implemented") +} func (UnimplementedWalletServiceServer) GetDiamondExchangeConfig(context.Context, *GetDiamondExchangeConfigRequest) (*GetDiamondExchangeConfigResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetDiamondExchangeConfig not implemented") } @@ -1154,6 +1218,78 @@ func _WalletService_ListRechargeProducts_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } +func _WalletService_ListAdminRechargeProducts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListAdminRechargeProductsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WalletServiceServer).ListAdminRechargeProducts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WalletService_ListAdminRechargeProducts_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WalletServiceServer).ListAdminRechargeProducts(ctx, req.(*ListAdminRechargeProductsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WalletService_CreateRechargeProduct_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateRechargeProductRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WalletServiceServer).CreateRechargeProduct(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WalletService_CreateRechargeProduct_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WalletServiceServer).CreateRechargeProduct(ctx, req.(*CreateRechargeProductRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WalletService_UpdateRechargeProduct_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateRechargeProductRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WalletServiceServer).UpdateRechargeProduct(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WalletService_UpdateRechargeProduct_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WalletServiceServer).UpdateRechargeProduct(ctx, req.(*UpdateRechargeProductRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WalletService_DeleteRechargeProduct_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteRechargeProductRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WalletServiceServer).DeleteRechargeProduct(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: WalletService_DeleteRechargeProduct_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WalletServiceServer).DeleteRechargeProduct(ctx, req.(*DeleteRechargeProductRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _WalletService_GetDiamondExchangeConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetDiamondExchangeConfigRequest) if err := dec(in); err != nil { @@ -1417,6 +1553,22 @@ var WalletService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListRechargeProducts", Handler: _WalletService_ListRechargeProducts_Handler, }, + { + MethodName: "ListAdminRechargeProducts", + Handler: _WalletService_ListAdminRechargeProducts_Handler, + }, + { + MethodName: "CreateRechargeProduct", + Handler: _WalletService_CreateRechargeProduct_Handler, + }, + { + MethodName: "UpdateRechargeProduct", + Handler: _WalletService_UpdateRechargeProduct_Handler, + }, + { + MethodName: "DeleteRechargeProduct", + Handler: _WalletService_DeleteRechargeProduct_Handler, + }, { MethodName: "GetDiamondExchangeConfig", Handler: _WalletService_GetDiamondExchangeConfig_Handler, diff --git a/docs/VIP系统架构.md b/docs/VIP系统架构.md index ae6f1d8e..ca920b48 100644 --- a/docs/VIP系统架构.md +++ b/docs/VIP系统架构.md @@ -153,6 +153,7 @@ VIP 属于 `wallet-service` 的账务和权益域,不放在 `user-service`。 资源组继续复用现有资源组能力: - 头像框:`avatar_frame` +- 资料卡:`profile_card` - 座驾:`vehicle` - 聊天气泡:`chat_bubble` - 徽章:`badge` diff --git a/docs/flutter对接/app配置与内购对接.md b/docs/flutter对接/app配置与内购对接.md new file mode 100644 index 00000000..a5810ba5 --- /dev/null +++ b/docs/flutter对接/app配置与内购对接.md @@ -0,0 +1,125 @@ +# Flutter App 配置与内购对接 + +本文只描述当前 App 端需要直接调用的 gateway HTTP 接口。所有业务接口都返回统一外壳: + +```json +{ + "code": "OK", + "message": "ok", + "request_id": "server-generated-request-id", + "data": {} +} +``` + +## 1. 检查 App 更新 + +`GET /api/v1/app/version` + +公开接口,不需要登录。客户端必须传平台,建议同时传当前编译版本号。 + +请求头: + +| Header | 必填 | 说明 | +| --- | --- | --- | +| `X-App-Code` | 否 | App 编码,默认 `lalu`。 | +| `X-App-Platform` | 是 | `android` 或 `ios`。也可以用 query `platform` 覆盖。 | +| `X-App-Build-Number` | 建议 | 当前客户端编译版本号。也可以用 query `build_number` 覆盖。 | +| `X-App-Version` | 否 | 当前客户端展示版本号,只用于客户端侧日志排查。 | + +示例: + +```http +GET /api/v1/app/version?platform=android&build_number=100 +X-App-Code: lalu +X-App-Platform: android +X-App-Build-Number: 100 +``` + +响应: + +```json +{ + "code": "OK", + "message": "ok", + "request_id": "req_abc", + "data": { + "app_code": "lalu", + "platform": "android", + "version": "1.2.0", + "build_number": 120, + "force_update": true, + "download_url": "https://example.com/lalu.apk", + "description": "修复已知问题", + "has_update": true, + "current_build_number": 100, + "updated_at_ms": 1710000000000, + "server_time_ms": 1710000001234 + } +} +``` + +Flutter 处理规则: + +- `has_update=false`:不展示升级弹窗。 +- `has_update=true && force_update=false`:展示普通升级弹窗,允许关闭。 +- `has_update=true && force_update=true`:展示强更弹窗,不允许进入主流程。 +- `download_url` 由后台配置。Android 通常打开 APK 下载页;iOS 通常打开 App Store 链接。 +- 服务端只用 `build_number` 判断新旧,不解析 `version` 语义版本。 + +## 2. 获取内购商品列表 + +`GET /api/v1/wallet/recharge/products` + +登录接口,需要 `Authorization: Bearer `。gateway 会用当前登录用户资料里的 `region_id` 筛选商品,客户端不要自己传区域。 + +请求头: + +| Header | 必填 | 说明 | +| --- | --- | --- | +| `Authorization` | 是 | App 登录 access token。 | +| `X-App-Platform` | 是 | `android` 或 `ios`。也可以用 query `platform` 覆盖。 | + +示例: + +```http +GET /api/v1/wallet/recharge/products +Authorization: Bearer +X-App-Platform: ios +``` + +响应: + +```json +{ + "code": "OK", + "message": "ok", + "request_id": "req_abc", + "data": { + "channels": ["apple"], + "products": [ + { + "product_id": 11, + "product_code": "iap_ios_1500", + "product_name": "1500 Coins", + "description": "coin pack", + "platform": "ios", + "channel": "apple", + "currency_code": "USDT", + "coin_amount": 1500, + "amount_micro": 1500000, + "region_ids": [2002], + "resource_asset_type": "COIN", + "status": "active", + "enabled": true + } + ] + } +} +``` + +Flutter 处理规则: + +- 只展示 `products` 里的商品;后台已经按平台、用户区域、上架状态过滤。 +- `amount_micro` 是 USDT 微单位,`1 USDT = 1000000`。 +- 当前资源类型固定是 `COIN`,后续如果后台新增资源类型,客户端应按 `resource_asset_type` 分支处理。 +- Android 使用 `channel=google` 的商品对接 Google Play Billing;iOS 使用 `channel=apple` 的商品对接 StoreKit。 diff --git a/docs/flutter对接/金币流水对接.md b/docs/flutter对接/金币流水对接.md new file mode 100644 index 00000000..af85f68f --- /dev/null +++ b/docs/flutter对接/金币流水对接.md @@ -0,0 +1,137 @@ +# Flutter 金币流水对接 + +本文只描述 Flutter App 读取当前登录用户金币流水的接口。金币余额和流水事实由 `wallet-service` 维护;客户端只展示 gateway 返回的分录投影,不在本地推算余额。 + +## 接口 + +`GET /api/v1/wallet/coin-transactions` + +登录接口,需要 `Authorization: Bearer `。接口固定查询当前登录用户的 `COIN` 资产流水,不接受客户端传 `user_id` 或 `asset_type`。 + +请求头: + +| Header | 必填 | 说明 | +| --- | --- | --- | +| `Authorization` | 是 | App 登录 access token。 | +| `X-App-Code` | 否 | App 编码,默认 `lalu`。 | + +Query: + +| 字段 | 必填 | 默认 | 说明 | +| --- | --- | --- | --- | +| `page` | 否 | `1` | 页码,从 1 开始。 | +| `page_size` | 否 | `30` | 每页数量。首屏不传时返回最近 30 条。 | + +排序固定为 `created_at_ms DESC, entry_id DESC`,即最新流水在前。分页字段使用通用 `page` / `page_size`,不要使用业务专属分页名。 + +示例: + +```http +GET /api/v1/wallet/coin-transactions?page=1&page_size=30 +Authorization: Bearer +X-App-Code: lalu +``` + +成功响应: + +```json +{ + "code": "OK", + "message": "ok", + "request_id": "req_abc", + "data": { + "items": [ + { + "entry_id": 101, + "transaction_id": "wtx_abc", + "biz_type": "coin_seller_transfer", + "asset_type": "COIN", + "available_delta": 3000, + "frozen_delta": 0, + "available_after": 12800, + "frozen_after": 0, + "counterparty_user_id": 90001, + "room_id": "", + "created_at_ms": 1710000000000 + } + ], + "total": 48, + "page": 1, + "page_size": 30 + } +} +``` + +字段规则: + +| 字段 | 说明 | +| --- | --- | +| `available_delta` | 本次可用金币变化;正数是收入,负数是支出。 | +| `available_after` | 本条流水落账后的可用金币余额,余额展示以该字段为准。 | +| `biz_type` | 业务类型,例如 `coin_seller_transfer`、`gift_debit`、`task_reward`、`game_credit`、`game_debit`、`game_refund`、`vip_purchase`。客户端可本地映射展示文案。 | +| `counterparty_user_id` | 对手用户长 ID;没有对手方时为 `0`。 | +| `room_id` | 房间相关流水的房间 ID;非房间流水为空字符串。 | +| `created_at_ms` | Unix epoch milliseconds;展示层按用户本地时区格式化。 | + +## Flutter 解析示例 + +```dart +class CoinTransactionPage { + CoinTransactionPage({ + required this.items, + required this.total, + required this.page, + required this.pageSize, + }); + + final List items; + final int total; + final int page; + final int pageSize; + + factory CoinTransactionPage.fromJson(Map json) { + return CoinTransactionPage( + items: (json['items'] as List? ?? const []) + .map((item) => CoinTransaction.fromJson(item as Map)) + .toList(), + total: (json['total'] as num?)?.toInt() ?? 0, + page: (json['page'] as num?)?.toInt() ?? 1, + pageSize: (json['page_size'] as num?)?.toInt() ?? 30, + ); + } +} + +class CoinTransaction { + CoinTransaction({ + required this.entryId, + required this.transactionId, + required this.bizType, + required this.availableDelta, + required this.availableAfter, + required this.createdAtMs, + }); + + final int entryId; + final String transactionId; + final String bizType; + final int availableDelta; + final int availableAfter; + final int createdAtMs; + + bool get isIncome => availableDelta > 0; + int get amount => availableDelta.abs(); + + factory CoinTransaction.fromJson(Map json) { + return CoinTransaction( + entryId: (json['entry_id'] as num).toInt(), + transactionId: json['transaction_id'] as String? ?? '', + bizType: json['biz_type'] as String? ?? '', + availableDelta: (json['available_delta'] as num?)?.toInt() ?? 0, + availableAfter: (json['available_after'] as num?)?.toInt() ?? 0, + createdAtMs: (json['created_at_ms'] as num?)?.toInt() ?? 0, + ); + } +} +``` + +接口调用时,先解析外层 envelope:只有 `code == "OK"` 时读取 `data`;其他 `code` 按登录态、参数错误或服务错误处理,并把 `request_id` 记录到客户端日志。 diff --git a/docs/openapi/gateway.swagger.yaml b/docs/openapi/gateway.swagger.yaml index 0ebc35c0..0b320cab 100644 --- a/docs/openapi/gateway.swagger.yaml +++ b/docs/openapi/gateway.swagger.yaml @@ -339,6 +339,45 @@ paths: description: 查询成功,`data` 返回 App 启动状态机需要的轻量配置摘要。 schema: $ref: "#/definitions/AppBootstrapEnvelope" + /api/v1/app/version: + get: + tags: + - app-config + summary: 获取 App 最新版本信息 + operationId: getAppVersion + description: 公开读接口,gateway 根据 App 平台返回后台 APP配置/版本管理 中最高 `build_number` 版本,并按客户端当前 `build_number` 计算是否需要提示更新。 + parameters: + - name: platform + in: query + required: false + type: string + enum: [android, ios] + description: 可选平台覆盖值;不传时读取 `X-App-Platform` / `X-Platform`。 + - name: build_number + in: query + required: false + type: integer + format: int64 + description: 当前客户端编译版本号;不传时读取 `X-App-Build-Number` / `X-Build-Number`。 + - name: X-App-Platform + in: header + required: false + type: string + enum: [android, ios] + - name: X-App-Build-Number + in: header + required: false + type: integer + format: int64 + responses: + "200": + description: 查询成功,`data` 返回最新版本和更新判定。 + schema: + $ref: "#/definitions/AppVersionEnvelope" + "400": + $ref: "#/responses/BadRequest" + "502": + $ref: "#/responses/UpstreamError" /api/v1/app/h5-links: get: tags: @@ -1036,8 +1075,8 @@ paths: summary: 创建房间 operationId: createRoom description: | - gateway 从 access token 取当前 `user_id` 写入 room-service `RequestMeta.actor_user_id`,room-service 由该 actor 确定 owner 和默认 host。 - 请求体不接收 `room_id`、`owner_user_id` 或 `host_user_id`;`command_id` 由客户端按创建动作生成,gateway 生成内部 room_id。 + gateway 从 access token 取当前 `user_id` 写入 room-service `RequestMeta.actor_user_id`,room-service 由该 actor 确定 owner。 + 请求体不接收 `room_id` 或 `owner_user_id`;`command_id` 由客户端按创建动作生成,gateway 生成内部 room_id。 同一个登录用户只能作为 owner 创建一个房间;已有房间时返回 409 Conflict。 security: - BearerAuth: [] @@ -1429,39 +1468,6 @@ paths: $ref: "#/responses/Internal" "502": $ref: "#/responses/UpstreamError" - /api/v1/rooms/host/transfer: - post: - tags: - - rooms - summary: 转移房间主持人 - operationId: transferRoomHost - security: - - BearerAuth: [] - parameters: - - name: body - in: body - required: true - schema: - $ref: "#/definitions/TransferRoomHostRequest" - responses: - "200": - description: 主持人转移成功,`data` 返回最新房间快照。 - schema: - $ref: "#/definitions/TransferRoomHostEnvelope" - "400": - $ref: "#/responses/BadRequest" - "401": - $ref: "#/responses/Unauthorized" - "403": - $ref: "#/responses/Forbidden" - "404": - $ref: "#/responses/NotFound" - "409": - $ref: "#/responses/Conflict" - "500": - $ref: "#/responses/Internal" - "502": - $ref: "#/responses/UpstreamError" /api/v1/rooms/user/mute: post: tags: @@ -1605,7 +1611,7 @@ paths: in: query required: false type: string - enum: [avatar_frame, coin, vehicle, chat_bubble, badge, floating_screen, gift] + enum: [avatar_frame, profile_card, coin, vehicle, chat_bubble, badge, floating_screen, gift] - name: keyword in: query required: false @@ -1649,7 +1655,7 @@ paths: in: query required: false type: string - enum: [avatar_frame, coin, vehicle, chat_bubble, badge, floating_screen, gift] + enum: [avatar_frame, profile_card, coin, vehicle, chat_bubble, badge, floating_screen, gift] - name: page in: query required: false @@ -1813,7 +1819,7 @@ paths: in: query required: false type: string - enum: [avatar_frame, coin, vehicle, chat_bubble, badge, floating_screen, gift] + enum: [avatar_frame, profile_card, coin, vehicle, chat_bubble, badge, floating_screen, gift] responses: "200": description: 返回当前用户有效资源权益。 @@ -1995,6 +2001,49 @@ paths: $ref: "#/responses/NotFound" "502": $ref: "#/responses/UpstreamError" + /api/v1/wallet/recharge/products: + get: + tags: + - wallet + summary: 获取充值商品列表 + operationId: listRechargeProducts + description: gateway 根据当前登录用户资料中的 `region_id` 和 App 平台筛选已上架内购商品;平台可通过 `platform` query 覆盖,默认读取 `X-App-Platform` / `X-Platform` 请求头。 + security: + - BearerAuth: [] + parameters: + - name: platform + in: query + required: false + type: string + enum: [android, ios] + description: 可选平台覆盖值;不传时读取 App 平台请求头。 + - name: X-App-Platform + in: header + required: false + type: string + enum: [android, ios] + description: App 平台请求头。 + - name: X-Platform + in: header + required: false + type: string + enum: [android, ios] + description: 兼容平台请求头。 + responses: + "200": + description: 返回当前用户区域和平台可购买的上架商品。 + schema: + $ref: "#/definitions/RechargeProductListEnvelope" + "400": + $ref: "#/responses/BadRequest" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "500": + $ref: "#/responses/Internal" + "502": + $ref: "#/responses/UpstreamError" /api/v1/wallet/coin-seller/transfer: post: tags: @@ -3068,6 +3117,39 @@ definitions: type: object additionalProperties: type: string + AppVersionData: + type: object + properties: + app_code: + type: string + platform: + type: string + enum: [android, ios] + version: + type: string + description: 最新版本号,例如 1.2.0。 + build_number: + type: integer + format: int64 + description: 最新编译版本号,App 使用它和本地 build number 比较。 + force_update: + type: boolean + description: 当前客户端落后且后台最新版本要求强更时为 true。 + download_url: + type: string + description: + type: string + has_update: + type: boolean + current_build_number: + type: integer + format: int64 + updated_at_ms: + type: integer + format: int64 + server_time_ms: + type: integer + format: int64 CompleteOnboardingRequest: type: object required: @@ -3156,7 +3238,7 @@ definitions: type: string resource_type: type: string - enum: [avatar_frame, coin, vehicle, chat_bubble, badge, floating_screen, gift] + enum: [avatar_frame, profile_card, coin, vehicle, chat_bubble, badge, floating_screen, gift] name: type: string status: @@ -3209,7 +3291,7 @@ definitions: description: 资源 ID;按字符串返回避免 64 位整数在客户端丢精度。 resource_type: type: string - enum: [avatar_frame, coin, vehicle, chat_bubble, badge, floating_screen, gift] + enum: [avatar_frame, profile_card, coin, vehicle, chat_bubble, badge, floating_screen, gift] name: type: string asset_url: @@ -3490,6 +3572,67 @@ definitions: entitlement_id: type: string description: 可选;不传时服务端自动选择当前用户该资源最新有效权益。 + RechargeProductData: + type: object + properties: + product_id: + type: integer + format: int64 + product_code: + type: string + product_name: + type: string + description: + type: string + platform: + type: string + enum: [android, ios] + channel: + type: string + enum: [google, apple] + currency_code: + type: string + example: USDT + coin_amount: + type: integer + format: int64 + amount_minor: + type: integer + format: int64 + amount_micro: + type: integer + format: int64 + description: USDT 微单位金额,1 USDT = 1000000。 + policy_version: + type: string + region_ids: + type: array + items: + type: integer + format: int64 + resource_asset_type: + type: string + example: COIN + status: + type: string + enum: [active, disabled] + enabled: + type: boolean + sort_order: + type: integer + format: int32 + RechargeProductListData: + type: object + properties: + channels: + type: array + description: 当前结果涉及的充值渠道,例如 google、apple。 + items: + type: string + products: + type: array + items: + $ref: "#/definitions/RechargeProductData" CoinSellerTransferRequest: type: object required: @@ -3749,17 +3892,6 @@ definitions: format: int64 enabled: type: boolean - TransferRoomHostRequest: - type: object - properties: - room_id: - type: string - command_id: - type: string - description: 房间命令幂等键;客户端按用户动作生成,同一动作的 HTTP 重试必须复用。 - target_user_id: - type: integer - format: int64 MuteUserRequest: type: object properties: @@ -3892,9 +4024,6 @@ definitions: owner_user_id: type: integer format: int64 - host_user_id: - type: integer - format: int64 mode: type: string status: @@ -3952,8 +4081,6 @@ definitions: description: 腾讯 IM 房间群 ID。当前等于 `room_id`,只代表目标群,不代表入群授权。 owner_user_id: type: string - host_user_id: - type: string title: type: string cover_url: @@ -4027,8 +4154,6 @@ definitions: type: string owner_user_id: type: string - host_user_id: - type: string mode: type: string status: @@ -4218,7 +4343,7 @@ definitions: $ref: "#/definitions/RoomRankItemData" profiles: type: array - description: 只包含房主、主持人、当前用户、麦位用户和首屏贡献榜用户的展示资料。 + description: 只包含房主、当前用户、麦位用户和首屏贡献榜用户的展示资料。 items: $ref: "#/definitions/RoomUserProfileData" im: @@ -4326,13 +4451,6 @@ definitions: $ref: "#/definitions/CommandResult" room: $ref: "#/definitions/RoomSnapshot" - TransferRoomHostResponse: - type: object - properties: - result: - $ref: "#/definitions/CommandResult" - room: - $ref: "#/definitions/RoomSnapshot" MuteUserResponse: type: object properties: @@ -4517,6 +4635,13 @@ definitions: properties: data: $ref: "#/definitions/AppBootstrapData" + AppVersionEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/AppVersionData" H5LinkListEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" @@ -4692,13 +4817,6 @@ definitions: properties: data: $ref: "#/definitions/SetRoomAdminResponse" - TransferRoomHostEnvelope: - allOf: - - $ref: "#/definitions/GatewayOKEnvelopeBase" - - type: object - properties: - data: - $ref: "#/definitions/TransferRoomHostResponse" MuteUserEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" @@ -4727,6 +4845,13 @@ definitions: properties: data: $ref: "#/definitions/SendGiftResponse" + RechargeProductListEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/RechargeProductListData" CoinSellerTransferEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" diff --git a/docs/openapi/room.swagger.yaml b/docs/openapi/room.swagger.yaml index 027b33ee..dff9606e 100644 --- a/docs/openapi/room.swagger.yaml +++ b/docs/openapi/room.swagger.yaml @@ -249,26 +249,6 @@ paths: $ref: "#/definitions/SetRoomAdminResponse" default: $ref: "#/responses/GRPCError" - /hyapp.room.v1.RoomCommandService/TransferRoomHost: - post: - tags: - - room-command - summary: 转移主持人 - operationId: roomTransferRoomHost - x-grpc-full-method: /hyapp.room.v1.RoomCommandService/TransferRoomHost - parameters: - - name: body - in: body - required: true - schema: - $ref: "#/definitions/TransferRoomHostRequest" - responses: - "200": - description: 主持人转移成功。 - schema: - $ref: "#/definitions/TransferRoomHostResponse" - default: - $ref: "#/responses/GRPCError" /hyapp.room.v1.RoomCommandService/MuteUser: post: tags: @@ -583,9 +563,6 @@ definitions: owner_user_id: type: integer format: int64 - host_user_id: - type: integer - format: int64 mode: type: string status: @@ -880,21 +857,6 @@ definitions: $ref: "#/definitions/CommandResult" room: $ref: "#/definitions/RoomSnapshot" - TransferRoomHostRequest: - type: object - properties: - meta: - $ref: "#/definitions/RequestMeta" - target_user_id: - type: integer - format: int64 - TransferRoomHostResponse: - type: object - properties: - result: - $ref: "#/definitions/CommandResult" - room: - $ref: "#/definitions/RoomSnapshot" MuteUserRequest: type: object properties: @@ -1107,7 +1069,6 @@ definitions: - room_mic_seat_locked - room_chat_enabled_changed - room_admin_changed - - room_host_transferred - room_user_muted - room_user_kicked - room_user_unbanned diff --git a/docs/接口清单.md b/docs/接口清单.md index 97193ea6..0c433dea 100644 --- a/docs/接口清单.md +++ b/docs/接口清单.md @@ -73,7 +73,6 @@ | POST | `/api/v1/rooms/mic/lock` | rooms | `setMicSeatLock` | 锁定或解锁麦位 | | POST | `/api/v1/rooms/chat/enabled` | rooms | `setChatEnabled` | 开启或关闭房间公屏 | | POST | `/api/v1/rooms/admin/set` | rooms | `setRoomAdmin` | 添加或移除房间管理员 | -| POST | `/api/v1/rooms/host/transfer` | rooms | `transferRoomHost` | 转移房间主持人 | | POST | `/api/v1/rooms/user/mute` | rooms | `muteUser` | 设置房间内禁言 | | POST | `/api/v1/rooms/user/kick` | rooms | `kickUser` | 踢出房间用户 | | POST | `/api/v1/rooms/user/unban` | rooms | `unbanUser` | 解除房间 ban | @@ -93,6 +92,7 @@ | GET | `/api/v1/wallet/recharge/products` | wallet | `listRechargeProducts` | 查询充值商品和渠道 | | GET | `/api/v1/wallet/diamond-exchange/config` | wallet | `getDiamondExchangeConfig` | 查询钻石兑换配置 | | POST | `/api/v1/wallet/withdrawals/apply` | wallet | `applyWithdrawal` | 提交美元余额提现申请 | +| GET | `/api/v1/wallet/coin-transactions` | wallet | `listCoinTransactions` | 分页查询当前用户金币流水 | | GET | `/api/v1/wallet/transactions` | wallet | `listWalletTransactions` | 分页查询钱包流水 | | POST | `/api/v1/wallet/coin-seller/transfer` | wallet | `transferCoinFromSeller` | 币商给玩家转金币 | | GET | `/api/v1/vip/me` | vip | `getMyVIP` | 查询当前 VIP 状态 | @@ -150,6 +150,7 @@ | PATCH | `/api/v1/admin/game/games/{game_id}` | admin | `updateCatalog` | 更新游戏目录 | | PATCH | `/api/v1/admin/game/games/{game_id}/status` | admin | `setGameStatus` | 设置游戏状态 | | GET | `/api/v1/admin/hosts` | admin | `listHosts` | listHosts | +| GET | `/api/v1/admin/operations/coin-ledger` | admin | `listCoinLedger` | listCoinLedger | | GET | `/api/v1/admin/payment/recharge-bills` | admin | `listRechargeBills` | listRechargeBills | | GET | `/api/v1/admin/regions` | admin | `listRegions` | listRegions | | POST | `/api/v1/admin/regions` | admin | `createRegion` | createRegion | @@ -290,7 +291,6 @@ | POST | `/hyapp.room.v1.RoomCommandService/SetMicSeatLock` | room-command | `roomSetMicSeatLock` | 锁定或解锁麦位 | | POST | `/hyapp.room.v1.RoomCommandService/SetChatEnabled` | room-command | `roomSetChatEnabled` | 开启或关闭公屏 | | POST | `/hyapp.room.v1.RoomCommandService/SetRoomAdmin` | room-command | `roomSetRoomAdmin` | 添加或移除房间管理员 | -| POST | `/hyapp.room.v1.RoomCommandService/TransferRoomHost` | room-command | `roomTransferRoomHost` | 转移主持人 | | POST | `/hyapp.room.v1.RoomCommandService/MuteUser` | room-command | `roomMuteUser` | 设置房间内禁言 | | POST | `/hyapp.room.v1.RoomCommandService/KickUser` | room-command | `roomKickUser` | 踢出房间用户 | | POST | `/hyapp.room.v1.RoomCommandService/UnbanUser` | room-command | `roomUnbanUser` | 解除房间 ban | diff --git a/docs/注册奖励Flutter对接.md b/docs/注册奖励Flutter对接.md new file mode 100644 index 00000000..4547e7af --- /dev/null +++ b/docs/注册奖励Flutter对接.md @@ -0,0 +1,124 @@ +# 注册奖励 Flutter 对接 + +## 边界 + +注册奖励由服务端在三方注册成功后自动发放。Flutter 端不需要、也不能主动发放奖励,只需要在登录态下查询当前用户是否仍满足领取条件,用于展示入口、提示或埋点。 + +服务端判断条件: + +- 用户没有成功领取过注册奖励。 +- 注册奖励配置已开启且奖励配置有效。 +- UTC 当天每日限制份数未用完;`daily_limit=0` 表示不限量。 + +## 查询接口 + +`GET /api/v1/activities/registration-reward/eligibility` + +请求头: + +```http +Authorization: Bearer +X-App-Code: lalu +``` + +响应仍使用 gateway 统一 envelope: + +```json +{ + "code": 0, + "message": "ok", + "request_id": "req_xxx", + "data": { + "can_receive": false, + "reason": "already_claimed", + "enabled": true, + "reward_type": "coin", + "coin_amount": 100, + "resource_group_id": 0, + "daily_limit": 1000, + "daily_used": 328, + "daily_remaining": 672, + "reward_day": "2026-05-12", + "server_time_ms": 1778563200000 + } +} +``` + +`reason` 取值: + +- `eligible`: 当前用户符合条件。 +- `already_claimed`: 用户已经领取或正在发放中。 +- `daily_limit_reached`: UTC 当天份数已用完。 +- `disabled`: 后台关闭注册奖励。 +- `not_configured`: 后台还没有配置注册奖励。 +- `invalid_config`: 后台配置不完整,例如金币数量为 0 或资源组为空。 + +## Dart DTO + +```dart +class RegistrationRewardEligibility { + const RegistrationRewardEligibility({ + required this.canReceive, + required this.reason, + required this.enabled, + required this.rewardType, + required this.coinAmount, + required this.resourceGroupId, + required this.dailyLimit, + required this.dailyUsed, + required this.dailyRemaining, + required this.rewardDay, + required this.serverTimeMs, + }); + + final bool canReceive; + final String reason; + final bool enabled; + final String rewardType; + final int coinAmount; + final int resourceGroupId; + final int dailyLimit; + final int dailyUsed; + final int dailyRemaining; + final String rewardDay; + final int serverTimeMs; + + factory RegistrationRewardEligibility.fromJson(Map json) { + return RegistrationRewardEligibility( + canReceive: json['can_receive'] == true, + reason: json['reason'] as String? ?? '', + enabled: json['enabled'] == true, + rewardType: json['reward_type'] as String? ?? '', + coinAmount: (json['coin_amount'] as num? ?? 0).toInt(), + resourceGroupId: (json['resource_group_id'] as num? ?? 0).toInt(), + dailyLimit: (json['daily_limit'] as num? ?? 0).toInt(), + dailyUsed: (json['daily_used'] as num? ?? 0).toInt(), + dailyRemaining: (json['daily_remaining'] as num? ?? 0).toInt(), + rewardDay: json['reward_day'] as String? ?? '', + serverTimeMs: (json['server_time_ms'] as num? ?? 0).toInt(), + ); + } +} +``` + +## 调用示例 + +```dart +Future fetchRegistrationRewardEligibility( + ApiClient api, +) async { + final envelope = await api.get('/api/v1/activities/registration-reward/eligibility'); + if (envelope.code != 0) { + throw ApiException(envelope.code, envelope.message); + } + return RegistrationRewardEligibility.fromJson( + envelope.data as Map, + ); +} +``` + +## 客户端使用建议 + +新用户登录成功后可以调用一次该接口刷新展示状态;如果 `can_receive=false` 且 `reason=already_claimed`,说明服务端已经成功发放或发放中,不要重复提示用户手动领取。 + +`reward_day` 按 UTC 日期返回,不使用设备时区;客户端只做展示,不要用本地日期自行判断每日份数。 diff --git a/docs/资源组与礼物架构.md b/docs/资源组与礼物架构.md index 355eb4bd..b8fd2ace 100644 --- a/docs/资源组与礼物架构.md +++ b/docs/资源组与礼物架构.md @@ -35,7 +35,7 @@ | Concept | Meaning | | --- | --- | -| `resource` | 可配置、可引用、可赠送的最小资源。头像框、金币、座驾、气泡、徽章、飘屏、礼物都属于资源。 | +| `resource` | 可配置、可引用、可赠送的最小资源。头像框、资料卡、金币、座驾、气泡、徽章、飘屏、礼物都属于资源。 | | `resource_group` | 一组资源和钱包资产项的集合。赠送资源组时展开为组内每个资源或资产赠送项。 | | `resource_group_item` | 资源组成员。`item_type=resource` 引用资源库资源;`item_type=wallet_asset` 直接配置 `COIN` 或 `DIAMOND` 数量。 | | `gift_config` | 礼物配置是一个绑定了 `resource_type=gift` 资源的业务配置,并额外拥有礼物类型、有效期、特效、价格、收费资产、热度和主播积分规则。 | @@ -48,6 +48,7 @@ | Type | Example | Grant Result | | --- | --- | --- | | `avatar_frame` | 头像框 | 写入 `user_resource_entitlements` | +| `profile_card` | 资料卡 | 写入 `user_resource_entitlements` | | `coin` | 金币包 | `wallet_accounts.asset_type=COIN` 入账 | | `vehicle` | 座驾 | 写入 `user_resource_entitlements` | | `chat_bubble` | 气泡 | 写入 `user_resource_entitlements` | @@ -424,7 +425,7 @@ POST /api/v1/users/me/resources/{resource_id}/equip 装备资源的边界: -- `equip` 只适用于头像框、座驾、气泡、徽章等可装备资源。 +- `equip` 只适用于头像框、资料卡、座驾、气泡、徽章等可装备资源。 - `floating_screen`、`gift` 和 `coin` 不能走 `equip`;金币只落钱包账本,礼物和飘屏后续通过使用命令扣减 `remaining_quantity`。 - `user-service.users.avatar` 仍然只是头像 URL,不承载头像框。 - 当前装备状态放在 `wallet-service` resource domain 的 `user_resource_equipment` 表,避免污染用户主数据。 diff --git a/pkg/tencentim/rest_client.go b/pkg/tencentim/rest_client.go index 6aba6219..e08fc16d 100644 --- a/pkg/tencentim/rest_client.go +++ b/pkg/tencentim/rest_client.go @@ -28,6 +28,8 @@ const ( destroyGroupCommand = "v4/group_open_http_svc/destroy_group" // deleteGroupMemberCommand 用于把已离房用户从腾讯群里移除,防止 IM 群成员残留扩大消息面。 deleteGroupMemberCommand = "v4/group_open_http_svc/delete_group_member" + // kickUserCommand 让指定账号现有 IM 登录态失效;被封禁用户需要立即从腾讯 IM SDK 下线。 + kickUserCommand = "v4/im_open_login_svc/kick" ) // RESTConfig 保存服务端调用腾讯云 IM REST API 所需配置。 @@ -278,6 +280,22 @@ func (c *RESTClient) DeleteRoomGroupMember(ctx context.Context, roomID string, u return c.DeleteGroupMember(ctx, roomID, userID) } +// KickUser 失效指定用户的腾讯云 IM 登录态。 +// 该接口不会禁止未来用新 UserSig 登录,因此调用方必须先在业务状态和 token denylist 上完成封禁。 +func (c *RESTClient) KickUser(ctx context.Context, userID int64) error { + if userID <= 0 { + return fmt.Errorf("kick user is incomplete") + } + + request := kickUserRequest{UserID: FormatUserID(userID)} + var response restResponse + if err := c.post(ctx, kickUserCommand, request, &response); err != nil { + return err + } + + return response.err() +} + // FormatUserID 把内部不可变 user_id 映射成腾讯云账号字符串。 func FormatUserID(userID int64) string { // 十进制 user_id 跨服务稳定,也避免把可变 display_user_id 暴露给 IM 账号体系。 @@ -389,6 +407,10 @@ type deleteGroupMemberRequest struct { Reason string `json:"Reason,omitempty"` } +type kickUserRequest struct { + UserID string `json:"UserID"` +} + type messageElement struct { MsgType string `json:"MsgType"` MsgContent customMsgContent `json:"MsgContent"` diff --git a/pkg/tencentim/rest_client_test.go b/pkg/tencentim/rest_client_test.go index 18550de2..015f6824 100644 --- a/pkg/tencentim/rest_client_test.go +++ b/pkg/tencentim/rest_client_test.go @@ -176,6 +176,31 @@ func TestRESTClientDeleteRoomGroupMemberBuildsTencentRequest(t *testing.T) { } } +// TestRESTClientKickUserBuildsTencentRequest 锁定封禁链路使用腾讯云 IM 失效账号登录态接口。 +func TestRESTClientKickUserBuildsTencentRequest(t *testing.T) { + var capturedPath string + var capturedBody map[string]any + client := newTestRESTClient(t, func(request *http.Request) (*http.Response, error) { + capturedPath = request.URL.Path + if err := json.NewDecoder(request.Body).Decode(&capturedBody); err != nil { + t.Fatalf("decode request body failed: %v", err) + } + + return okRESTResponse(), nil + }) + + if err := client.KickUser(context.Background(), 10002); err != nil { + t.Fatalf("KickUser failed: %v", err) + } + + if capturedPath != "/"+kickUserCommand { + t.Fatalf("path mismatch: got %q", capturedPath) + } + if capturedBody["UserID"] != "10002" { + t.Fatalf("unexpected kick body: %+v", capturedBody) + } +} + func newTestRESTClient(t *testing.T, roundTrip roundTripFunc) *RESTClient { t.Helper() diff --git a/pkg/tencentrtc/rest_client.go b/pkg/tencentrtc/rest_client.go new file mode 100644 index 00000000..3fe08192 --- /dev/null +++ b/pkg/tencentrtc/rest_client.go @@ -0,0 +1,211 @@ +// Package tencentrtc contains Tencent RTC token and server-side room APIs. +package tencentrtc + +import ( + "bytes" + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" +) + +const ( + // DefaultRESTEndpoint is the Tencent Cloud API endpoint for TRTC room management. + DefaultRESTEndpoint = "trtc.tencentcloudapi.com" + // DefaultRESTRegion is accepted by TRTC room management APIs and keeps local config explicit. + DefaultRESTRegion = "ap-guangzhou" + + trtcServiceName = "trtc" + trtcAPIVersion = "2019-07-22" + removeUserByStrRoomAction = "RemoveUserByStrRoomId" + tencentCloudTC3Algorithm = "TC3-HMAC-SHA256" + tencentCloudTC3RequestType = "tc3_request" +) + +// RESTConfig describes the Tencent Cloud API credentials used for RTC room management. +type RESTConfig struct { + Enabled bool + // SDKAppID is the TRTC application ID that owns the room. + SDKAppID int64 + // SecretID/SecretKey are Tencent Cloud API credentials with permission on the TRTC SDKAppID. + SecretID string + SecretKey string + // Region is required by Tencent Cloud API even though room IDs remain application-global. + Region string + // Endpoint defaults to trtc.tencentcloudapi.com. + Endpoint string + // HTTPClient lets tests inject a fake transport and lets services bound public network latency. + HTTPClient *http.Client + // Now is injectable so signature tests do not depend on wall clock time. + Now func() time.Time +} + +// RESTClient wraps Tencent Cloud API 3.0 calls needed by room-service. +type RESTClient struct { + cfg RESTConfig + httpClient *http.Client + now func() time.Time +} + +// NewRESTClient validates the API credential boundary and returns a reusable client. +func NewRESTClient(cfg RESTConfig) (*RESTClient, error) { + cfg.SecretID = strings.TrimSpace(cfg.SecretID) + cfg.SecretKey = strings.TrimSpace(cfg.SecretKey) + cfg.Region = strings.TrimSpace(cfg.Region) + cfg.Endpoint = strings.TrimSpace(cfg.Endpoint) + if cfg.SDKAppID <= 0 || cfg.SecretID == "" || cfg.SecretKey == "" { + return nil, fmt.Errorf("tencent rtc rest config is incomplete") + } + if cfg.Region == "" { + cfg.Region = DefaultRESTRegion + } + if cfg.Endpoint == "" { + cfg.Endpoint = DefaultRESTEndpoint + } + if cfg.HTTPClient == nil { + cfg.HTTPClient = &http.Client{Timeout: 5 * time.Second} + } + if cfg.Now == nil { + cfg.Now = func() time.Time { return time.Now().UTC() } + } + + return &RESTClient{cfg: cfg, httpClient: cfg.HTTPClient, now: cfg.Now}, nil +} + +// RemoveUserByStrRoomID removes a user from a string-ID TRTC room. +// It only affects the live RTC room; room-service must update Room Cell state before calling this. +func (c *RESTClient) RemoveUserByStrRoomID(ctx context.Context, roomID string, userID int64) error { + roomID = strings.TrimSpace(roomID) + if roomID == "" || userID <= 0 { + return fmt.Errorf("rtc remove user is incomplete") + } + + payload := removeUserByStrRoomRequest{ + SDKAppID: c.cfg.SDKAppID, + RoomID: roomID, + UserIDs: []string{strconv.FormatInt(userID, 10)}, + } + return c.post(ctx, removeUserByStrRoomAction, payload) +} + +func (c *RESTClient) post(ctx context.Context, action string, payload any) error { + body, err := json.Marshal(payload) + if err != nil { + return err + } + + request, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://"+strings.TrimSuffix(c.cfg.Endpoint, "/"), bytes.NewReader(body)) + if err != nil { + return err + } + request.Header.Set("Content-Type", "application/json; charset=utf-8") + request.Header.Set("Host", c.cfg.Endpoint) + request.Header.Set("X-TC-Action", action) + request.Header.Set("X-TC-Version", trtcAPIVersion) + request.Header.Set("X-TC-Region", c.cfg.Region) + c.sign(request, body, action) + + response, err := c.httpClient.Do(request) + if err != nil { + return err + } + defer response.Body.Close() + + responseBody, err := io.ReadAll(response.Body) + if err != nil { + return err + } + if response.StatusCode < 200 || response.StatusCode >= 300 { + return fmt.Errorf("tencent rtc http status %d: %s", response.StatusCode, string(responseBody)) + } + + var cloudResp cloudAPIResponse + if err := json.Unmarshal(responseBody, &cloudResp); err != nil { + return err + } + if cloudResp.Response.Error != nil { + return fmt.Errorf("tencent rtc rest failed: code=%s message=%s", cloudResp.Response.Error.Code, cloudResp.Response.Error.Message) + } + return nil +} + +func (c *RESTClient) sign(request *http.Request, body []byte, action string) { + now := c.now().UTC() + timestamp := now.Unix() + date := now.Format("2006-01-02") + request.Header.Set("X-TC-Timestamp", strconv.FormatInt(timestamp, 10)) + + hashedPayload := sha256Hex(body) + canonicalHeaders := "content-type:" + strings.ToLower(request.Header.Get("Content-Type")) + "\n" + "host:" + c.cfg.Endpoint + "\n" + signedHeaders := "content-type;host" + canonicalRequest := strings.Join([]string{ + http.MethodPost, + "/", + "", + canonicalHeaders, + signedHeaders, + hashedPayload, + }, "\n") + + credentialScope := date + "/" + trtcServiceName + "/" + tencentCloudTC3RequestType + stringToSign := strings.Join([]string{ + tencentCloudTC3Algorithm, + strconv.FormatInt(timestamp, 10), + credentialScope, + sha256Hex([]byte(canonicalRequest)), + }, "\n") + signature := hex.EncodeToString(hmacSHA256(tc3SigningKey(c.cfg.SecretKey, date), stringToSign)) + + authorization := fmt.Sprintf( + "%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", + tencentCloudTC3Algorithm, + c.cfg.SecretID, + credentialScope, + signedHeaders, + signature, + ) + request.Header.Set("Authorization", authorization) + _ = action +} + +func tc3SigningKey(secretKey string, date string) []byte { + secretDate := hmacSHA256([]byte("TC3"+secretKey), date) + secretService := hmacSHA256(secretDate, trtcServiceName) + return hmacSHA256(secretService, tencentCloudTC3RequestType) +} + +func hmacSHA256(key []byte, value string) []byte { + mac := hmac.New(sha256.New, key) + _, _ = mac.Write([]byte(value)) + return mac.Sum(nil) +} + +func sha256Hex(value []byte) string { + sum := sha256.Sum256(value) + return hex.EncodeToString(sum[:]) +} + +type removeUserByStrRoomRequest struct { + SDKAppID int64 `json:"SdkAppId"` + RoomID string `json:"RoomId"` + UserIDs []string `json:"UserIds"` +} + +type cloudAPIResponse struct { + Response struct { + RequestID string `json:"RequestId"` + Error *cloudAPIError `json:"Error,omitempty"` + } `json:"Response"` +} + +type cloudAPIError struct { + Code string `json:"Code"` + Message string `json:"Message"` +} diff --git a/pkg/tencentrtc/rest_client_test.go b/pkg/tencentrtc/rest_client_test.go new file mode 100644 index 00000000..e7116e01 --- /dev/null +++ b/pkg/tencentrtc/rest_client_test.go @@ -0,0 +1,63 @@ +package tencentrtc + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/http" + "strings" + "testing" + "time" +) + +// TestRESTClientRemoveUserByStrRoomIDBuildsTencentCloudRequest 锁定 TRTC 字符串房间踢人的 API 3.0 请求形态。 +func TestRESTClientRemoveUserByStrRoomIDBuildsTencentCloudRequest(t *testing.T) { + var capturedBody map[string]any + var capturedHeader http.Header + client, err := NewRESTClient(RESTConfig{ + SDKAppID: 1400000001, + SecretID: "AKIDEXAMPLE", + SecretKey: "secret", + Region: "ap-guangzhou", + HTTPClient: &http.Client{Transport: roundTripFunc(func(request *http.Request) (*http.Response, error) { + capturedHeader = request.Header.Clone() + if err := json.NewDecoder(request.Body).Decode(&capturedBody); err != nil { + t.Fatalf("decode request body failed: %v", err) + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(`{"Response":{"RequestId":"req-1"}}`))), + Header: make(http.Header), + }, nil + })}, + Now: func() time.Time { return time.Unix(1_700_000_000, 0).UTC() }, + }) + if err != nil { + t.Fatalf("NewRESTClient failed: %v", err) + } + + if err := client.RemoveUserByStrRoomID(context.Background(), "room_1001", 10002); err != nil { + t.Fatalf("RemoveUserByStrRoomID failed: %v", err) + } + + if capturedBody["SdkAppId"].(float64) != 1400000001 || capturedBody["RoomId"] != "room_1001" { + t.Fatalf("unexpected remove user body: %+v", capturedBody) + } + users, ok := capturedBody["UserIds"].([]any) + if !ok || len(users) != 1 || users[0] != "10002" { + t.Fatalf("unexpected user ids: %+v", capturedBody) + } + if capturedHeader.Get("X-TC-Action") != removeUserByStrRoomAction || capturedHeader.Get("X-TC-Version") != trtcAPIVersion { + t.Fatalf("unexpected tencent cloud headers: %+v", capturedHeader) + } + if !strings.HasPrefix(capturedHeader.Get("Authorization"), tencentCloudTC3Algorithm+" Credential=AKIDEXAMPLE/") { + t.Fatalf("authorization header missing TC3 credential: %s", capturedHeader.Get("Authorization")) + } +} + +type roundTripFunc func(*http.Request) (*http.Response, error) + +func (f roundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) { + return f(request) +} diff --git a/server/admin/cmd/server/main.go b/server/admin/cmd/server/main.go index 887a3446..4ee70123 100644 --- a/server/admin/cmd/server/main.go +++ b/server/admin/cmd/server/main.go @@ -28,6 +28,7 @@ import ( appusermodule "hyapp-admin-server/internal/modules/appuser" auditmodule "hyapp-admin-server/internal/modules/audit" authmodule "hyapp-admin-server/internal/modules/auth" + coinledgermodule "hyapp-admin-server/internal/modules/coinledger" countryregionmodule "hyapp-admin-server/internal/modules/countryregion" dailytaskmodule "hyapp-admin-server/internal/modules/dailytask" dashboardmodule "hyapp-admin-server/internal/modules/dashboard" @@ -39,6 +40,7 @@ import ( notificationmodule "hyapp-admin-server/internal/modules/notification" paymentmodule "hyapp-admin-server/internal/modules/payment" rbacmodule "hyapp-admin-server/internal/modules/rbac" + registrationrewardmodule "hyapp-admin-server/internal/modules/registrationreward" resourcemodule "hyapp-admin-server/internal/modules/resource" roomadminmodule "hyapp-admin-server/internal/modules/roomadmin" searchmodule "hyapp-admin-server/internal/modules/search" @@ -201,27 +203,29 @@ func main() { objectUploader = uploader } handlers := router.Handlers{ - Audit: auditHandler, - Auth: authmodule.New(store, auth, auditHandler, cfg), - AdminUser: adminusermodule.New(store, cfg, auditHandler), - AppConfig: appconfigmodule.New(store, auditHandler), - AppRegistry: appregistrymodule.New(userDB), - AppUser: appusermodule.New(userclient.NewGRPC(userConn), activityclient.NewGRPC(activityConn), userDB, walletDB, cfg, auditHandler), - CountryRegion: countryregionmodule.New(userclient.NewGRPC(userConn), userDB, cfg, auditHandler), - DailyTask: dailytaskmodule.New(activityclient.NewGRPC(activityConn), auditHandler), - Dashboard: dashboardmodule.New(store), - Game: gamemanagementmodule.New(gameclient.NewGRPC(gameConn), auditHandler), - Health: healthmodule.New(store, redisClient, jobStatus), - HostOrg: hostorgmodule.New(userclient.NewGRPC(userConn), walletclient.NewGRPC(walletConn), userDB, walletDB, sqlDB, auditHandler), - Job: jobmodule.New(store, cfg, auditHandler), - Menu: menumodule.New(store, auditHandler), - Notification: notificationmodule.New(store, auditHandler), - Payment: paymentmodule.New(walletclient.NewGRPC(walletConn)), - RBAC: rbacmodule.New(store, auditHandler), - Resource: resourcemodule.New(walletclient.NewGRPC(walletConn), auditHandler), - RoomAdmin: roomadminmodule.New(roomDB, userDB, auditHandler), - Search: searchmodule.New(store), - Upload: uploadmodule.New(objectUploader, cfg.TencentCOS.ObjectPrefix, auditHandler), + Audit: auditHandler, + Auth: authmodule.New(store, auth, auditHandler, cfg), + AdminUser: adminusermodule.New(store, cfg, auditHandler), + AppConfig: appconfigmodule.New(store, auditHandler), + AppRegistry: appregistrymodule.New(userDB), + AppUser: appusermodule.New(userclient.NewGRPC(userConn), activityclient.NewGRPC(activityConn), sqlDB, userDB, walletDB, cfg, auditHandler), + CoinLedger: coinledgermodule.New(userDB, walletDB), + CountryRegion: countryregionmodule.New(userclient.NewGRPC(userConn), userDB, cfg, auditHandler), + DailyTask: dailytaskmodule.New(activityclient.NewGRPC(activityConn), auditHandler), + Dashboard: dashboardmodule.New(store), + Game: gamemanagementmodule.New(gameclient.NewGRPC(gameConn), auditHandler), + Health: healthmodule.New(store, redisClient, jobStatus), + HostOrg: hostorgmodule.New(userclient.NewGRPC(userConn), walletclient.NewGRPC(walletConn), userDB, walletDB, sqlDB, auditHandler), + Job: jobmodule.New(store, cfg, auditHandler), + Menu: menumodule.New(store, auditHandler), + Notification: notificationmodule.New(store, auditHandler), + Payment: paymentmodule.New(walletclient.NewGRPC(walletConn), auditHandler), + RBAC: rbacmodule.New(store, auditHandler), + RegistrationReward: registrationrewardmodule.New(activityclient.NewGRPC(activityConn), userDB, auditHandler), + Resource: resourcemodule.New(walletclient.NewGRPC(walletConn), store, userDB, auditHandler), + RoomAdmin: roomadminmodule.New(roomDB, userDB, auditHandler), + Search: searchmodule.New(store), + Upload: uploadmodule.New(objectUploader, cfg.TencentCOS.ObjectPrefix, auditHandler), } engine := router.New(cfg, auth, handlers) diff --git a/server/admin/docs/权限管理.md b/server/admin/docs/权限管理.md index 968933a4..82a5a1b9 100644 --- a/server/admin/docs/权限管理.md +++ b/server/admin/docs/权限管理.md @@ -267,7 +267,6 @@ | `room:mic` | `button` | 上下麦、换麦、锁麦 | | `room:chat` | `button` | 公屏开关 | | `room:admin` | `button` | 设置房间管理员 | -| `room:host-transfer` | `button` | 转移主持 | | `room:mute` | `button` | 禁言、解除禁言 | | `room:kick` | `button` | 踢出房间 | | `room:unban` | `button` | 房间解封用户 | diff --git a/server/admin/internal/integration/activityclient/client.go b/server/admin/internal/integration/activityclient/client.go index 1254f89c..a1d92ea2 100644 --- a/server/admin/internal/integration/activityclient/client.go +++ b/server/admin/internal/integration/activityclient/client.go @@ -13,18 +13,23 @@ type Client interface { ListTaskDefinitions(ctx context.Context, req *activityv1.ListTaskDefinitionsRequest) (*activityv1.ListTaskDefinitionsResponse, error) UpsertTaskDefinition(ctx context.Context, req *activityv1.UpsertTaskDefinitionRequest) (*activityv1.UpsertTaskDefinitionResponse, error) SetTaskDefinitionStatus(ctx context.Context, req *activityv1.SetTaskDefinitionStatusRequest) (*activityv1.SetTaskDefinitionStatusResponse, error) + GetRegistrationRewardConfig(ctx context.Context, req *activityv1.GetRegistrationRewardConfigRequest) (*activityv1.GetRegistrationRewardConfigResponse, error) + UpdateRegistrationRewardConfig(ctx context.Context, req *activityv1.UpdateRegistrationRewardConfigRequest) (*activityv1.UpdateRegistrationRewardConfigResponse, error) + ListRegistrationRewardClaims(ctx context.Context, req *activityv1.ListRegistrationRewardClaimsRequest) (*activityv1.ListRegistrationRewardClaimsResponse, error) RemoveRegionBroadcastMember(ctx context.Context, req *activityv1.RemoveRegionBroadcastMemberRequest) (*activityv1.RemoveRegionBroadcastMemberResponse, error) } type GRPCClient struct { - taskClient activityv1.AdminTaskServiceClient - broadcastClient activityv1.BroadcastServiceClient + taskClient activityv1.AdminTaskServiceClient + registrationRewardClient activityv1.AdminRegistrationRewardServiceClient + broadcastClient activityv1.BroadcastServiceClient } func NewGRPC(conn grpc.ClientConnInterface) *GRPCClient { return &GRPCClient{ - taskClient: activityv1.NewAdminTaskServiceClient(conn), - broadcastClient: activityv1.NewBroadcastServiceClient(conn), + taskClient: activityv1.NewAdminTaskServiceClient(conn), + registrationRewardClient: activityv1.NewAdminRegistrationRewardServiceClient(conn), + broadcastClient: activityv1.NewBroadcastServiceClient(conn), } } @@ -40,6 +45,18 @@ func (c *GRPCClient) SetTaskDefinitionStatus(ctx context.Context, req *activityv return c.taskClient.SetTaskDefinitionStatus(ctx, req) } +func (c *GRPCClient) GetRegistrationRewardConfig(ctx context.Context, req *activityv1.GetRegistrationRewardConfigRequest) (*activityv1.GetRegistrationRewardConfigResponse, error) { + return c.registrationRewardClient.GetRegistrationRewardConfig(ctx, req) +} + +func (c *GRPCClient) UpdateRegistrationRewardConfig(ctx context.Context, req *activityv1.UpdateRegistrationRewardConfigRequest) (*activityv1.UpdateRegistrationRewardConfigResponse, error) { + return c.registrationRewardClient.UpdateRegistrationRewardConfig(ctx, req) +} + +func (c *GRPCClient) ListRegistrationRewardClaims(ctx context.Context, req *activityv1.ListRegistrationRewardClaimsRequest) (*activityv1.ListRegistrationRewardClaimsResponse, error) { + return c.registrationRewardClient.ListRegistrationRewardClaims(ctx, req) +} + func (c *GRPCClient) RemoveRegionBroadcastMember(ctx context.Context, req *activityv1.RemoveRegionBroadcastMemberRequest) (*activityv1.RemoveRegionBroadcastMemberResponse, error) { return c.broadcastClient.RemoveRegionBroadcastMember(ctx, req) } diff --git a/server/admin/internal/integration/userclient/client.go b/server/admin/internal/integration/userclient/client.go index 3e916a51..7a295a76 100644 --- a/server/admin/internal/integration/userclient/client.go +++ b/server/admin/internal/integration/userclient/client.go @@ -12,6 +12,7 @@ import ( type Client interface { GetUser(ctx context.Context, req GetUserRequest) (*User, error) + SetUserStatus(ctx context.Context, req SetUserStatusRequest) (*SetUserStatusResult, error) ResolveDisplayUserID(ctx context.Context, req ResolveDisplayUserIDRequest) (*UserIdentity, error) ListCountries(ctx context.Context, req ListCountriesRequest) ([]*Country, error) UpdateCountry(ctx context.Context, req UpdateCountryRequest) (*Country, error) @@ -36,6 +37,30 @@ type GetUserRequest struct { UserID int64 } +type SetUserStatusRequest struct { + RequestID string + Caller string + TargetUserID int64 + Status string + OperatorType string + OperatorUserID int64 + Reason string +} + +type SetUserStatusResult struct { + User *User `json:"user"` + RevokedSessionCount int64 `json:"revokedSessionCount"` + AccessTokenRevoked bool `json:"accessTokenRevoked"` + AccessTokenError string `json:"accessTokenRevokeError,omitempty"` + IMKicked bool `json:"imKicked"` + IMKickError string `json:"imKickError,omitempty"` + RoomEvicted bool `json:"roomEvicted"` + RoomID string `json:"roomId,omitempty"` + RTCKicked bool `json:"rtcKicked"` + RTCKickError string `json:"rtcKickError,omitempty"` + RoomEvictError string `json:"roomEvictError,omitempty"` +} + type ResolveDisplayUserIDRequest struct { RequestID string Caller string @@ -117,6 +142,46 @@ func (c *GRPCClient) GetUser(ctx context.Context, req GetUserRequest) (*User, er return fromProtoUser(resp.GetUser()), nil } +func (c *GRPCClient) SetUserStatus(ctx context.Context, req SetUserStatusRequest) (*SetUserStatusResult, error) { + resp, err := c.client.SetUserStatus(ctx, &userv1.SetUserStatusRequest{ + Meta: requestMeta(ctx, req.RequestID, req.Caller), + TargetUserId: req.TargetUserID, + Status: userStatusToProto(req.Status), + OperatorType: req.OperatorType, + OperatorUserId: req.OperatorUserID, + Reason: req.Reason, + }) + if err != nil { + return nil, err + } + return &SetUserStatusResult{ + User: fromProtoUser(resp.GetUser()), + RevokedSessionCount: resp.GetRevokedSessionCount(), + AccessTokenRevoked: resp.GetAccessTokenRevoked(), + AccessTokenError: resp.GetAccessTokenRevokeError(), + IMKicked: resp.GetImKicked(), + IMKickError: resp.GetImKickError(), + RoomEvicted: resp.GetRoomEvicted(), + RoomID: resp.GetRoomId(), + RTCKicked: resp.GetRtcKicked(), + RTCKickError: resp.GetRtcKickError(), + RoomEvictError: resp.GetRoomEvictError(), + }, nil +} + +func userStatusToProto(status string) userv1.UserStatus { + switch status { + case "active": + return userv1.UserStatus_USER_STATUS_ACTIVE + case "disabled": + return userv1.UserStatus_USER_STATUS_DISABLED + case "banned": + return userv1.UserStatus_USER_STATUS_BANNED + default: + return userv1.UserStatus_USER_STATUS_UNSPECIFIED + } +} + func (c *GRPCClient) ResolveDisplayUserID(ctx context.Context, req ResolveDisplayUserIDRequest) (*UserIdentity, error) { resp, err := c.identityClient.ResolveDisplayUserID(ctx, &userv1.ResolveDisplayUserIDRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), @@ -134,7 +199,7 @@ func fromProtoUser(user *userv1.User) *User { } return &User{ UserID: user.GetUserId(), - Status: user.GetStatus().String(), + Status: fromProtoStatus(user.GetStatus()), CreatedAtMs: user.GetCreatedAtMs(), UpdatedAtMs: user.GetUpdatedAtMs(), DisplayUserID: user.GetDisplayUserId(), @@ -162,6 +227,19 @@ func fromProtoUser(user *userv1.User) *User { } } +func fromProtoStatus(status userv1.UserStatus) string { + switch status { + case userv1.UserStatus_USER_STATUS_ACTIVE: + return "active" + case userv1.UserStatus_USER_STATUS_DISABLED: + return "disabled" + case userv1.UserStatus_USER_STATUS_BANNED: + return "banned" + default: + return "" + } +} + func fromProtoUserIdentity(identity *userv1.UserIdentity) *UserIdentity { if identity == nil { return nil diff --git a/server/admin/internal/integration/walletclient/client.go b/server/admin/internal/integration/walletclient/client.go index bc15cabb..71134c37 100644 --- a/server/admin/internal/integration/walletclient/client.go +++ b/server/admin/internal/integration/walletclient/client.go @@ -29,6 +29,10 @@ type Client interface { ListResourceGrants(ctx context.Context, req *walletv1.ListResourceGrantsRequest) (*walletv1.ListResourceGrantsResponse, error) AdminCreditCoinSellerStock(ctx context.Context, req *walletv1.AdminCreditCoinSellerStockRequest) (*walletv1.AdminCreditCoinSellerStockResponse, error) ListRechargeBills(ctx context.Context, req *walletv1.ListRechargeBillsRequest) (*walletv1.ListRechargeBillsResponse, error) + ListAdminRechargeProducts(ctx context.Context, req *walletv1.ListAdminRechargeProductsRequest) (*walletv1.ListAdminRechargeProductsResponse, error) + CreateRechargeProduct(ctx context.Context, req *walletv1.CreateRechargeProductRequest) (*walletv1.RechargeProductResponse, error) + UpdateRechargeProduct(ctx context.Context, req *walletv1.UpdateRechargeProductRequest) (*walletv1.RechargeProductResponse, error) + DeleteRechargeProduct(ctx context.Context, req *walletv1.DeleteRechargeProductRequest) (*walletv1.DeleteRechargeProductResponse, error) } type GRPCClient struct { @@ -114,3 +118,19 @@ func (c *GRPCClient) AdminCreditCoinSellerStock(ctx context.Context, req *wallet func (c *GRPCClient) ListRechargeBills(ctx context.Context, req *walletv1.ListRechargeBillsRequest) (*walletv1.ListRechargeBillsResponse, error) { return c.client.ListRechargeBills(ctx, req) } + +func (c *GRPCClient) ListAdminRechargeProducts(ctx context.Context, req *walletv1.ListAdminRechargeProductsRequest) (*walletv1.ListAdminRechargeProductsResponse, error) { + return c.client.ListAdminRechargeProducts(ctx, req) +} + +func (c *GRPCClient) CreateRechargeProduct(ctx context.Context, req *walletv1.CreateRechargeProductRequest) (*walletv1.RechargeProductResponse, error) { + return c.client.CreateRechargeProduct(ctx, req) +} + +func (c *GRPCClient) UpdateRechargeProduct(ctx context.Context, req *walletv1.UpdateRechargeProductRequest) (*walletv1.RechargeProductResponse, error) { + return c.client.UpdateRechargeProduct(ctx, req) +} + +func (c *GRPCClient) DeleteRechargeProduct(ctx context.Context, req *walletv1.DeleteRechargeProductRequest) (*walletv1.DeleteRechargeProductResponse, error) { + return c.client.DeleteRechargeProduct(ctx, req) +} diff --git a/server/admin/internal/model/models.go b/server/admin/internal/model/models.go index ebbf228f..5db99f9f 100644 --- a/server/admin/internal/model/models.go +++ b/server/admin/internal/model/models.go @@ -111,6 +111,23 @@ func (AppBanner) TableName() string { return "admin_app_banners" } +type AppVersion struct { + ID uint `gorm:"primaryKey" json:"id"` + AppCode string `gorm:"size:32;uniqueIndex:uk_admin_app_versions_build,not null;default:lalu" json:"appCode"` + Platform string `gorm:"size:24;uniqueIndex:uk_admin_app_versions_build;index:idx_admin_app_versions_latest,not null" json:"platform"` + Version string `gorm:"size:40;not null" json:"version"` + BuildNumber int64 `gorm:"uniqueIndex:uk_admin_app_versions_build;index:idx_admin_app_versions_latest,not null" json:"buildNumber"` + ForceUpdate bool `gorm:"not null;default:false" json:"forceUpdate"` + DownloadURL string `gorm:"size:2048;not null" json:"downloadUrl"` + Description string `gorm:"type:text" json:"description"` + CreatedAtMS int64 `gorm:"column:created_at_ms;autoCreateTime:milli" json:"createdAtMs"` + UpdatedAtMS int64 `gorm:"column:updated_at_ms;autoUpdateTime:milli" json:"updatedAtMs"` +} + +func (AppVersion) TableName() string { + return "admin_app_versions" +} + type RefreshToken struct { ID uint `gorm:"primaryKey" json:"id"` UserID uint `gorm:"index;not null" json:"userId"` diff --git a/server/admin/internal/modules/appconfig/handler.go b/server/admin/internal/modules/appconfig/handler.go index 5a741812..b9eb164a 100644 --- a/server/admin/internal/modules/appconfig/handler.go +++ b/server/admin/internal/modules/appconfig/handler.go @@ -110,6 +110,65 @@ func (h *Handler) DeleteBanner(c *gin.Context) { response.OK(c, gin.H{"deleted": true}) } +func (h *Handler) ListAppVersions(c *gin.Context) { + items, err := h.service.ListAppVersions(appctx.FromContext(c.Request.Context()), repository.AppVersionListOptions{ + Keyword: strings.TrimSpace(c.Query("keyword")), + Platform: strings.TrimSpace(c.Query("platform")), + }) + if err != nil { + response.ServerError(c, "获取版本配置失败") + return + } + response.OK(c, gin.H{"items": items, "total": len(items)}) +} + +func (h *Handler) CreateAppVersion(c *gin.Context) { + var request appVersionRequest + if err := c.ShouldBindJSON(&request); err != nil { + response.BadRequest(c, "参数不正确") + return + } + item, err := h.service.CreateAppVersion(appctx.FromContext(c.Request.Context()), request) + if err != nil { + response.BadRequest(c, err.Error()) + return + } + shared.OperationLog(c, h.audit, "create-app-version", "admin_app_versions", "success", fmt.Sprintf("version_id=%d", item.ID)) + response.Created(c, item) +} + +func (h *Handler) UpdateAppVersion(c *gin.Context) { + id, ok := appVersionID(c) + if !ok { + return + } + var request appVersionRequest + if err := c.ShouldBindJSON(&request); err != nil { + response.BadRequest(c, "参数不正确") + return + } + item, err := h.service.UpdateAppVersion(appctx.FromContext(c.Request.Context()), id, request) + if err != nil { + response.BadRequest(c, err.Error()) + return + } + shared.OperationLog(c, h.audit, "update-app-version", "admin_app_versions", "success", fmt.Sprintf("version_id=%d", item.ID)) + response.OK(c, item) +} + +func (h *Handler) DeleteAppVersion(c *gin.Context) { + id, ok := appVersionID(c) + if !ok { + return + } + if err := h.service.DeleteAppVersion(appctx.FromContext(c.Request.Context()), id); err != nil { + response.BadRequest(c, err.Error()) + return + } + shared.OperationLog(c, h.audit, "delete-app-version", "admin_app_versions", "success", fmt.Sprintf("version_id=%d", id)) + response.OK(c, gin.H{"deleted": true}) +} + func bannerID(c *gin.Context) (uint, bool) { value, err := strconv.ParseUint(c.Param("banner_id"), 10, 64) if err != nil || value == 0 { @@ -119,6 +178,15 @@ func bannerID(c *gin.Context) (uint, bool) { return uint(value), true } +func appVersionID(c *gin.Context) (uint, bool) { + value, err := strconv.ParseUint(c.Param("version_id"), 10, 64) + if err != nil || value == 0 { + response.BadRequest(c, "version id is invalid") + return 0, false + } + return uint(value), true +} + func parseOptionalInt64(values ...string) int64 { for _, value := range values { value = strings.TrimSpace(value) diff --git a/server/admin/internal/modules/appconfig/request.go b/server/admin/internal/modules/appconfig/request.go index 01fb6b20..1dd35827 100644 --- a/server/admin/internal/modules/appconfig/request.go +++ b/server/admin/internal/modules/appconfig/request.go @@ -20,3 +20,12 @@ type bannerRequest struct { CountryCode string `json:"countryCode"` Description string `json:"description"` } + +type appVersionRequest struct { + Platform string `json:"platform" binding:"required"` + Version string `json:"version" binding:"required"` + BuildNumber int64 `json:"buildNumber" binding:"required"` + ForceUpdate bool `json:"forceUpdate"` + DownloadURL string `json:"downloadUrl" binding:"required"` + Description string `json:"description"` +} diff --git a/server/admin/internal/modules/appconfig/routes.go b/server/admin/internal/modules/appconfig/routes.go index 704ea3bf..8426fc8c 100644 --- a/server/admin/internal/modules/appconfig/routes.go +++ b/server/admin/internal/modules/appconfig/routes.go @@ -18,4 +18,9 @@ func RegisterRoutes(protected *gin.RouterGroup, h *Handler) { protected.POST("/admin/app-config/banners", middleware.RequirePermission("app-config:update"), h.CreateBanner) protected.PUT("/admin/app-config/banners/:banner_id", middleware.RequirePermission("app-config:update"), h.UpdateBanner) protected.DELETE("/admin/app-config/banners/:banner_id", middleware.RequirePermission("app-config:update"), h.DeleteBanner) + + protected.GET("/admin/app-config/versions", middleware.RequirePermission("app-version:view"), h.ListAppVersions) + protected.POST("/admin/app-config/versions", middleware.RequirePermission("app-version:create"), h.CreateAppVersion) + protected.PUT("/admin/app-config/versions/:version_id", middleware.RequirePermission("app-version:update"), h.UpdateAppVersion) + protected.DELETE("/admin/app-config/versions/:version_id", middleware.RequirePermission("app-version:delete"), h.DeleteAppVersion) } diff --git a/server/admin/internal/modules/appconfig/service.go b/server/admin/internal/modules/appconfig/service.go index 3ead6ce5..b74c3d49 100644 --- a/server/admin/internal/modules/appconfig/service.go +++ b/server/admin/internal/modules/appconfig/service.go @@ -54,6 +54,19 @@ type AppBanner struct { UpdatedAtMs int64 `json:"updatedAtMs"` } +type AppVersion struct { + ID uint `json:"id"` + AppCode string `json:"appCode"` + Platform string `json:"platform"` + Version string `json:"version"` + BuildNumber int64 `json:"buildNumber"` + ForceUpdate bool `json:"forceUpdate"` + DownloadURL string `json:"downloadUrl"` + Description string `json:"description"` + CreatedAtMs int64 `json:"createdAtMs"` + UpdatedAtMs int64 `json:"updatedAtMs"` +} + func NewService(store *repository.Store) *AppConfigService { return &AppConfigService{store: store} } @@ -176,6 +189,57 @@ func (s *AppConfigService) DeleteBanner(appCode string, id uint) error { return s.store.DeleteAppBanner(appctx.Normalize(appCode), id) } +func (s *AppConfigService) ListAppVersions(appCode string, options repository.AppVersionListOptions) ([]AppVersion, error) { + options.AppCode = appctx.Normalize(appCode) + options.Platform = normalizeAppPlatform(options.Platform) + options.Keyword = strings.TrimSpace(options.Keyword) + items, err := s.store.ListAppVersions(options) + if err != nil { + return nil, err + } + out := make([]AppVersion, 0, len(items)) + for _, item := range items { + out = append(out, appVersionFromModel(item)) + } + return out, nil +} + +func (s *AppConfigService) CreateAppVersion(appCode string, req appVersionRequest) (AppVersion, error) { + item, err := appVersionModelFromRequest(appctx.Normalize(appCode), req) + if err != nil { + return AppVersion{}, err + } + if err := s.store.CreateAppVersion(&item); err != nil { + return AppVersion{}, err + } + return appVersionFromModel(item), nil +} + +func (s *AppConfigService) UpdateAppVersion(appCode string, id uint, req appVersionRequest) (AppVersion, error) { + item, err := s.store.GetAppVersion(appctx.Normalize(appCode), id) + if err != nil { + return AppVersion{}, err + } + updated, err := appVersionModelFromRequest(item.AppCode, req) + if err != nil { + return AppVersion{}, err + } + item.Platform = updated.Platform + item.Version = updated.Version + item.BuildNumber = updated.BuildNumber + item.ForceUpdate = updated.ForceUpdate + item.DownloadURL = updated.DownloadURL + item.Description = updated.Description + if err := s.store.UpdateAppVersion(&item); err != nil { + return AppVersion{}, err + } + return appVersionFromModel(item), nil +} + +func (s *AppConfigService) DeleteAppVersion(appCode string, id uint) error { + return s.store.DeleteAppVersion(appctx.Normalize(appCode), id) +} + func h5LinkDefinitionSet() map[string]string { out := make(map[string]string, len(h5LinkDefinitions)) for _, definition := range h5LinkDefinitions { @@ -265,6 +329,54 @@ func appBannerFromModel(item model.AppBanner) AppBanner { } } +func appVersionModelFromRequest(appCode string, req appVersionRequest) (model.AppVersion, error) { + item := model.AppVersion{ + AppCode: appctx.Normalize(appCode), + Platform: normalizeAppPlatform(req.Platform), + Version: strings.TrimSpace(req.Version), + BuildNumber: req.BuildNumber, + ForceUpdate: req.ForceUpdate, + DownloadURL: strings.TrimSpace(req.DownloadURL), + Description: strings.TrimSpace(req.Description), + } + if item.Platform != "android" && item.Platform != "ios" { + return model.AppVersion{}, errors.New("app version platform is invalid") + } + if item.Version == "" || utf8.RuneCountInString(item.Version) > 40 { + return model.AppVersion{}, errors.New("app version is invalid") + } + if item.BuildNumber <= 0 { + return model.AppVersion{}, errors.New("app build number is invalid") + } + if item.DownloadURL == "" || len(item.DownloadURL) > 2048 { + return model.AppVersion{}, errors.New("app download url is invalid") + } + for _, char := range item.DownloadURL { + if unicode.IsSpace(char) { + return model.AppVersion{}, errors.New("app download url cannot contain whitespace") + } + } + if utf8.RuneCountInString(item.Description) > 1000 { + return model.AppVersion{}, errors.New("app version description is too long") + } + return item, nil +} + +func appVersionFromModel(item model.AppVersion) AppVersion { + return AppVersion{ + ID: item.ID, + AppCode: item.AppCode, + Platform: item.Platform, + Version: item.Version, + BuildNumber: item.BuildNumber, + ForceUpdate: item.ForceUpdate, + DownloadURL: item.DownloadURL, + Description: item.Description, + CreatedAtMs: item.CreatedAtMS, + UpdatedAtMs: item.UpdatedAtMS, + } +} + func normalizeBannerType(value string) string { return strings.ToLower(strings.TrimSpace(value)) } @@ -281,6 +393,10 @@ func normalizeBannerPlatform(value string) string { return strings.ToLower(strings.TrimSpace(value)) } +func normalizeAppPlatform(value string) string { + return strings.ToLower(strings.TrimSpace(value)) +} + func normalizeCountryCode(value string) string { return strings.ToUpper(strings.TrimSpace(value)) } diff --git a/server/admin/internal/modules/appuser/ban_list.go b/server/admin/internal/modules/appuser/ban_list.go new file mode 100644 index 00000000..3d12a795 --- /dev/null +++ b/server/admin/internal/modules/appuser/ban_list.go @@ -0,0 +1,301 @@ +package appuser + +import ( + "context" + "database/sql" + "fmt" + "strconv" + "strings" + + "hyapp-admin-server/internal/appctx" +) + +type AppUserBanRecord struct { + ID int64 `json:"id"` + Target AppUserBrief `json:"target"` + Operator BanOperator `json:"operator"` + OldStatus string `json:"oldStatus"` + NewStatus string `json:"newStatus"` + Reason string `json:"reason"` + RequestID string `json:"requestId"` + CreatedAtMs int64 `json:"createdAtMs"` +} + +type AppUserBrief struct { + Avatar string `json:"avatar"` + DisplayUserID string `json:"displayUserId"` + UserID string `json:"userId"` + Username string `json:"username"` +} + +type BanOperator struct { + Type string `json:"type"` + AdminID string `json:"adminId,omitempty"` + Account string `json:"account,omitempty"` + Avatar string `json:"avatar,omitempty"` + DisplayUserID string `json:"displayUserId,omitempty"` + Name string `json:"name,omitempty"` + UserID string `json:"userId,omitempty"` +} + +type adminOperatorProfile struct { + Account string + Name string +} + +func (s *Service) ListBannedUsers(ctx context.Context, query banListQuery) ([]AppUserBanRecord, int64, error) { + if s.userDB == nil { + return nil, 0, fmt.Errorf("user mysql is not configured") + } + query = normalizeBanListQuery(query) + adminIDs, err := s.lookupAdminOperatorIDs(ctx, query.OperatorKeyword) + if err != nil { + return nil, 0, err + } + whereSQL, args := banListWhereSQL(ctx, query, adminIDs) + total, err := countRows(ctx, s.userDB, whereSQL, args...) + if err != nil { + return nil, 0, err + } + rows, err := s.userDB.QueryContext(ctx, fmt.Sprintf(` + SELECT l.id, + l.target_user_id, + target.current_display_user_id, + COALESCE(target.username, ''), + COALESCE(target.avatar, ''), + l.old_status, + l.new_status, + l.operator_type, + l.operator_user_id, + COALESCE(operator_user.current_display_user_id, ''), + COALESCE(operator_user.username, ''), + COALESCE(operator_user.avatar, ''), + l.reason, + l.request_id, + l.created_at_ms + %s + ORDER BY l.created_at_ms DESC, l.id DESC + LIMIT ? OFFSET ? + `, whereSQL), append(args, query.PageSize, offset(query.Page, query.PageSize))...) + if err != nil { + return nil, 0, err + } + defer rows.Close() + + items := make([]AppUserBanRecord, 0, query.PageSize) + adminOperatorIDs := make([]int64, 0) + for rows.Next() { + item, adminOperatorID, err := scanBanRecord(rows) + if err != nil { + return nil, 0, err + } + if adminOperatorID > 0 { + adminOperatorIDs = append(adminOperatorIDs, adminOperatorID) + } + items = append(items, item) + } + if err := rows.Err(); err != nil { + return nil, 0, err + } + if err := s.fillAdminOperators(ctx, items, adminOperatorIDs); err != nil { + return nil, 0, err + } + return items, total, nil +} + +func banListWhereSQL(ctx context.Context, query banListQuery, adminIDs []int64) (string, []any) { + appCode := appctx.FromContext(ctx) + whereSQL := ` + FROM user_status_change_logs l + INNER JOIN ( + SELECT app_code, target_user_id, MAX(id) AS latest_id + FROM user_status_change_logs + WHERE app_code = ? AND new_status IN ('banned', 'disabled') + GROUP BY app_code, target_user_id + ) latest ON latest.app_code = l.app_code AND latest.latest_id = l.id + INNER JOIN users target ON target.app_code = l.app_code AND target.user_id = l.target_user_id + LEFT JOIN users operator_user ON l.operator_type = 'app_user' AND operator_user.app_code = l.app_code AND operator_user.user_id = l.operator_user_id + WHERE l.app_code = ? AND target.status IN ('banned', 'disabled')` + args := []any{appCode, appCode} + if query.TargetKeyword != "" { + like := "%" + query.TargetKeyword + "%" + whereSQL += " AND (CAST(target.user_id AS CHAR) LIKE ? OR target.current_display_user_id LIKE ? OR target.username LIKE ?)" + args = append(args, like, like, like) + } + if query.OperatorKeyword != "" { + like := "%" + query.OperatorKeyword + "%" + operatorClauses := []string{"(l.operator_type = 'app_user' AND (CAST(operator_user.user_id AS CHAR) LIKE ? OR operator_user.current_display_user_id LIKE ? OR operator_user.username LIKE ?))"} + args = append(args, like, like, like) + if len(adminIDs) > 0 { + operatorClauses = append(operatorClauses, "(l.operator_type = 'admin' AND l.operator_user_id IN ("+placeholders(len(adminIDs))+"))") + for _, id := range adminIDs { + args = append(args, id) + } + } + whereSQL += " AND (" + strings.Join(operatorClauses, " OR ") + ")" + } + if query.StartMs > 0 { + whereSQL += " AND l.created_at_ms >= ?" + args = append(args, query.StartMs) + } + if query.EndMs > 0 { + whereSQL += " AND l.created_at_ms < ?" + args = append(args, query.EndMs) + } + return whereSQL, args +} + +func scanBanRecord(rows *sql.Rows) (AppUserBanRecord, int64, error) { + var item AppUserBanRecord + var targetUserID int64 + var operatorType string + var operatorUserID int64 + var operatorDisplayUserID string + var operatorUsername string + var operatorAvatar string + if err := rows.Scan( + &item.ID, + &targetUserID, + &item.Target.DisplayUserID, + &item.Target.Username, + &item.Target.Avatar, + &item.OldStatus, + &item.NewStatus, + &operatorType, + &operatorUserID, + &operatorDisplayUserID, + &operatorUsername, + &operatorAvatar, + &item.Reason, + &item.RequestID, + &item.CreatedAtMs, + ); err != nil { + return AppUserBanRecord{}, 0, err + } + item.Target.UserID = strconv.FormatInt(targetUserID, 10) + item.Operator.Type = operatorType + if operatorType == "admin" { + item.Operator.AdminID = strconv.FormatInt(operatorUserID, 10) + item.Operator.Account = item.Operator.AdminID + return item, operatorUserID, nil + } + if operatorType == "app_user" && operatorUserID > 0 { + item.Operator.UserID = strconv.FormatInt(operatorUserID, 10) + item.Operator.DisplayUserID = operatorDisplayUserID + item.Operator.Name = operatorUsername + item.Operator.Avatar = operatorAvatar + } + return item, 0, nil +} + +func (s *Service) lookupAdminOperatorIDs(ctx context.Context, keyword string) ([]int64, error) { + if s.adminDB == nil || strings.TrimSpace(keyword) == "" { + return nil, nil + } + like := "%" + strings.TrimSpace(keyword) + "%" + rows, err := s.adminDB.QueryContext(ctx, ` + SELECT id + FROM admin_users + WHERE CAST(id AS CHAR) LIKE ? OR username LIKE ? OR name LIKE ? + LIMIT 200 + `, like, like, like) + if err != nil { + return nil, err + } + defer rows.Close() + ids := make([]int64, 0) + for rows.Next() { + var id int64 + if err := rows.Scan(&id); err != nil { + return nil, err + } + ids = append(ids, id) + } + return ids, rows.Err() +} + +func (s *Service) fillAdminOperators(ctx context.Context, items []AppUserBanRecord, adminIDs []int64) error { + if s.adminDB == nil || len(adminIDs) == 0 { + return nil + } + ids := uniquePositiveInt64s(adminIDs) + if len(ids) == 0 { + return nil + } + args := make([]any, 0, len(ids)) + for _, id := range ids { + args = append(args, id) + } + rows, err := s.adminDB.QueryContext(ctx, fmt.Sprintf(` + SELECT id, username, name + FROM admin_users + WHERE id IN (%s) + `, placeholders(len(ids))), args...) + if err != nil { + return err + } + defer rows.Close() + profiles := make(map[int64]adminOperatorProfile, len(ids)) + for rows.Next() { + var id int64 + var profile adminOperatorProfile + if err := rows.Scan(&id, &profile.Account, &profile.Name); err != nil { + return err + } + profiles[id] = profile + } + if err := rows.Err(); err != nil { + return err + } + for index := range items { + if items[index].Operator.Type != "admin" { + continue + } + adminID, _ := strconv.ParseInt(items[index].Operator.AdminID, 10, 64) + profile, ok := profiles[adminID] + if !ok { + continue + } + items[index].Operator.Account = profile.Account + items[index].Operator.Name = profile.Name + } + return nil +} + +func normalizeBanListQuery(query banListQuery) banListQuery { + if query.Page < 1 { + query.Page = 1 + } + if query.PageSize < 1 { + query.PageSize = 20 + } + if query.PageSize > 100 { + query.PageSize = 100 + } + query.TargetKeyword = strings.TrimSpace(query.TargetKeyword) + query.OperatorKeyword = strings.TrimSpace(query.OperatorKeyword) + return query +} + +func uniquePositiveInt64s(values []int64) []int64 { + seen := make(map[int64]struct{}, len(values)) + out := make([]int64, 0, len(values)) + for _, value := range values { + if value <= 0 { + continue + } + if _, ok := seen[value]; ok { + continue + } + seen[value] = struct{}{} + out = append(out, value) + } + return out +} + +func placeholders(count int) string { + if count <= 0 { + return "" + } + return strings.TrimRight(strings.Repeat("?,", count), ",") +} diff --git a/server/admin/internal/modules/appuser/ban_list_test.go b/server/admin/internal/modules/appuser/ban_list_test.go new file mode 100644 index 00000000..4ad946a7 --- /dev/null +++ b/server/admin/internal/modules/appuser/ban_list_test.go @@ -0,0 +1,61 @@ +package appuser + +import ( + "context" + "strings" + "testing" +) + +func TestBanListWhereSQLBuildsTargetKeywordFilter(t *testing.T) { + whereSQL, args := banListWhereSQL(context.Background(), banListQuery{ + TargetKeyword: "10086", + }, nil) + + for _, fragment := range []string{ + "target.status IN ('banned', 'disabled')", + "CAST(target.user_id AS CHAR) LIKE ?", + "target.current_display_user_id LIKE ?", + "target.username LIKE ?", + } { + if !strings.Contains(whereSQL, fragment) { + t.Fatalf("where sql missing %q: %s", fragment, whereSQL) + } + } + if len(args) != 5 { + t.Fatalf("args length = %d, want 5: %#v", len(args), args) + } + for index := 2; index < len(args); index++ { + if args[index] != "%10086%" { + t.Fatalf("target keyword arg[%d] = %#v, want %%10086%%", index, args[index]) + } + } +} + +func TestBanListWhereSQLBuildsOperatorKeywordFilter(t *testing.T) { + whereSQL, args := banListWhereSQL(context.Background(), banListQuery{ + OperatorKeyword: "admin", + StartMs: 1000, + EndMs: 2000, + }, []int64{7, 9}) + + for _, fragment := range []string{ + "l.operator_type = 'app_user'", + "operator_user.current_display_user_id LIKE ?", + "(l.operator_type = 'admin' AND l.operator_user_id IN (?,?))", + "l.created_at_ms >= ?", + "l.created_at_ms < ?", + } { + if !strings.Contains(whereSQL, fragment) { + t.Fatalf("where sql missing %q: %s", fragment, whereSQL) + } + } + wantArgs := []any{"lalu", "lalu", "%admin%", "%admin%", "%admin%", int64(7), int64(9), int64(1000), int64(2000)} + if len(args) != len(wantArgs) { + t.Fatalf("args length = %d, want %d: %#v", len(args), len(wantArgs), args) + } + for index := range wantArgs { + if args[index] != wantArgs[index] { + t.Fatalf("arg[%d] = %#v, want %#v", index, args[index], wantArgs[index]) + } + } +} diff --git a/server/admin/internal/modules/appuser/handler.go b/server/admin/internal/modules/appuser/handler.go index b4f9dac9..c95873e2 100644 --- a/server/admin/internal/modules/appuser/handler.go +++ b/server/admin/internal/modules/appuser/handler.go @@ -23,9 +23,9 @@ type Handler struct { audit shared.OperationLogger } -func New(userClient userclient.Client, activityClient activityclient.Client, userDB *sql.DB, walletDB *sql.DB, cfg config.Config, audit shared.OperationLogger) *Handler { +func New(userClient userclient.Client, activityClient activityclient.Client, adminDB *sql.DB, userDB *sql.DB, walletDB *sql.DB, cfg config.Config, audit shared.OperationLogger) *Handler { return &Handler{ - service: NewService(userClient, activityClient, userDB, walletDB), + service: NewService(userClient, activityClient, adminDB, userDB, walletDB), cfg: cfg, audit: audit, } @@ -51,6 +51,16 @@ func (h *Handler) ListLoginLogs(c *gin.Context) { response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total}) } +func (h *Handler) ListBannedUsers(c *gin.Context) { + query := parseBanListQuery(c) + items, total, err := h.service.ListBannedUsers(c.Request.Context(), query) + if err != nil { + response.ServerError(c, "获取封禁列表失败") + return + } + response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total}) +} + func (h *Handler) ListUserLoginLogs(c *gin.Context) { userID, ok := parseInt64ID(c, "id") if !ok { @@ -133,13 +143,13 @@ func (h *Handler) setUserStatus(c *gin.Context, status string, action string, su if !ok { return } - user, err := h.service.SetUserStatus(c.Request.Context(), userID, status) + result, err := h.service.SetUserStatus(c.Request.Context(), userID, status, int64(middleware.CurrentUserID(c)), middleware.CurrentRequestID(c)) if err != nil { writeMutationError(c, err, successMessage+"失败") return } writeAppUserAuditLog(c, h.audit, action, "app_users", userID, "success", fmt.Sprintf("status=%s", status)) - response.OK(c, user) + response.OK(c, result) } func parseListQuery(c *gin.Context) listQuery { @@ -174,6 +184,18 @@ func parseLoginLogQuery(c *gin.Context) loginLogQuery { }) } +func parseBanListQuery(c *gin.Context) banListQuery { + options := shared.ListOptions(c) + return normalizeBanListQuery(banListQuery{ + Page: options.Page, + PageSize: options.PageSize, + TargetKeyword: firstQuery(c, "target_keyword", "targetKeyword", "keyword"), + OperatorKeyword: firstQuery(c, "operator_keyword", "operatorKeyword"), + StartMs: queryInt64(c, "start_ms", "startMs"), + EndMs: queryInt64(c, "end_ms", "endMs"), + }) +} + func firstQuery(c *gin.Context, names ...string) string { for _, name := range names { if value := strings.TrimSpace(c.Query(name)); value != "" { diff --git a/server/admin/internal/modules/appuser/request.go b/server/admin/internal/modules/appuser/request.go index 7669f430..5fec41ce 100644 --- a/server/admin/internal/modules/appuser/request.go +++ b/server/admin/internal/modules/appuser/request.go @@ -25,6 +25,15 @@ type loginLogQuery struct { EndMs int64 } +type banListQuery struct { + Page int + PageSize int + TargetKeyword string + OperatorKeyword string + StartMs int64 + EndMs int64 +} + type updateUserRequest struct { Avatar *string `json:"avatar"` Country *string `json:"country"` diff --git a/server/admin/internal/modules/appuser/routes.go b/server/admin/internal/modules/appuser/routes.go index fc954be7..da18e152 100644 --- a/server/admin/internal/modules/appuser/routes.go +++ b/server/admin/internal/modules/appuser/routes.go @@ -12,6 +12,7 @@ func RegisterRoutes(protected *gin.RouterGroup, h *Handler) { } protected.GET("/app/users", middleware.RequirePermission("app-user:view"), h.ListUsers) + protected.GET("/app/users/bans", middleware.RequirePermission("app-user:view"), h.ListBannedUsers) protected.GET("/app/users/login-logs", middleware.RequirePermission("app-user:view"), h.ListLoginLogs) protected.GET("/app/users/:id/login-logs", middleware.RequirePermission("app-user:view"), h.ListUserLoginLogs) protected.GET("/app/users/:id", middleware.RequirePermission("app-user:view"), h.GetUser) diff --git a/server/admin/internal/modules/appuser/service.go b/server/admin/internal/modules/appuser/service.go index 1f80d320..b4d19cf6 100644 --- a/server/admin/internal/modules/appuser/service.go +++ b/server/admin/internal/modules/appuser/service.go @@ -25,6 +25,7 @@ var ( type Service struct { userClient userclient.Client activityClient activityclient.Client + adminDB *sql.DB userDB *sql.DB walletDB *sql.DB } @@ -48,8 +49,22 @@ type AppUser struct { Username string `json:"username"` } -func NewService(userClient userclient.Client, activityClient activityclient.Client, userDB *sql.DB, walletDB *sql.DB) *Service { - return &Service{userClient: userClient, activityClient: activityClient, userDB: userDB, walletDB: walletDB} +type SetUserStatusResult struct { + User AppUser `json:"user"` + RevokedSessionCount int64 `json:"revokedSessionCount"` + AccessTokenRevoked bool `json:"accessTokenRevoked"` + AccessTokenError string `json:"accessTokenRevokeError,omitempty"` + IMKicked bool `json:"imKicked"` + IMKickError string `json:"imKickError,omitempty"` + RoomEvicted bool `json:"roomEvicted"` + RoomID string `json:"roomId,omitempty"` + RTCKicked bool `json:"rtcKicked"` + RTCKickError string `json:"rtcKickError,omitempty"` + RoomEvictError string `json:"roomEvictError,omitempty"` +} + +func NewService(userClient userclient.Client, activityClient activityclient.Client, adminDB *sql.DB, userDB *sql.DB, walletDB *sql.DB) *Service { + return &Service{userClient: userClient, activityClient: activityClient, adminDB: adminDB, userDB: userDB, walletDB: walletDB} } func (s *Service) ListUsers(ctx context.Context, query listQuery) ([]AppUser, int64, error) { @@ -336,46 +351,44 @@ func (s *Service) removeOldRegionBroadcastMemberBestEffort(ctx context.Context, } } -func (s *Service) SetUserStatus(ctx context.Context, userID int64, status string) (AppUser, error) { - if s.userDB == nil { - return AppUser{}, fmt.Errorf("user mysql is not configured") - } +func (s *Service) SetUserStatus(ctx context.Context, userID int64, status string, operatorUserID int64, requestID string) (SetUserStatusResult, error) { status = strings.ToLower(strings.TrimSpace(status)) if status != "active" && status != "banned" && status != "disabled" { - return AppUser{}, fmt.Errorf("%w: 状态不正确", ErrInvalidArgument) + return SetUserStatusResult{}, fmt.Errorf("%w: 状态不正确", ErrInvalidArgument) } - tx, err := s.userDB.BeginTx(ctx, nil) + if s.userClient == nil { + return SetUserStatusResult{}, fmt.Errorf("user service client is not configured") + } + result, err := s.userClient.SetUserStatus(ctx, userclient.SetUserStatusRequest{ + RequestID: strings.TrimSpace(requestID), + Caller: "hyapp-admin-server", + TargetUserID: userID, + Status: status, + OperatorType: "admin", + OperatorUserID: operatorUserID, + Reason: "admin_app_user_status", + }) if err != nil { - return AppUser{}, err + return SetUserStatusResult{}, err } - defer rollbackIfOpen(tx) - - now := nowMillis() - appCode := appctx.FromContext(ctx) - result, err := tx.ExecContext(ctx, `UPDATE users SET status = ?, updated_at_ms = ? WHERE app_code = ? AND user_id = ?`, status, now, appCode, userID) + user, err := s.GetUser(ctx, userID) if err != nil { - return AppUser{}, err + return SetUserStatusResult{}, err } - affected, err := result.RowsAffected() - if err != nil { - return AppUser{}, err + output := SetUserStatusResult{User: user} + if result != nil { + output.RevokedSessionCount = result.RevokedSessionCount + output.AccessTokenRevoked = result.AccessTokenRevoked + output.AccessTokenError = result.AccessTokenError + output.IMKicked = result.IMKicked + output.IMKickError = result.IMKickError + output.RoomEvicted = result.RoomEvicted + output.RoomID = result.RoomID + output.RTCKicked = result.RTCKicked + output.RTCKickError = result.RTCKickError + output.RoomEvictError = result.RoomEvictError } - if affected == 0 { - return AppUser{}, ErrNotFound - } - if status == "banned" || status == "disabled" { - if _, err := tx.ExecContext(ctx, ` - UPDATE auth_sessions - SET revoked_at_ms = ?, revoked_reason = ?, revoked_request_id = '', revoked_by = ?, updated_at_ms = ? - WHERE app_code = ? AND user_id = ? AND revoked_at_ms IS NULL - `, now, "ADMIN_USER_STATUS", "admin", now, appCode, userID); err != nil { - return AppUser{}, err - } - } - if err := tx.Commit(); err != nil { - return AppUser{}, err - } - return s.GetUser(ctx, userID) + return output, nil } func (s *Service) SetPassword(ctx context.Context, userID int64, password string) error { diff --git a/server/admin/internal/modules/coinledger/dto.go b/server/admin/internal/modules/coinledger/dto.go new file mode 100644 index 00000000..8870b334 --- /dev/null +++ b/server/admin/internal/modules/coinledger/dto.go @@ -0,0 +1,23 @@ +package coinledger + +type coinLedgerUserDTO struct { + UserID string `json:"userId"` + DisplayUserID string `json:"displayUserId"` + Username string `json:"username"` + Avatar string `json:"avatar"` +} + +type coinLedgerEntryDTO struct { + EntryID int64 `json:"entryId"` + TransactionID string `json:"transactionId"` + UserID string `json:"userId"` + User coinLedgerUserDTO `json:"user"` + BizType string `json:"bizType"` + Direction string `json:"direction"` + Amount int64 `json:"amount"` + AvailableDelta int64 `json:"availableDelta"` + AvailableAfter int64 `json:"availableAfter"` + CounterpartyUserID string `json:"counterpartyUserId"` + RoomID string `json:"roomId"` + CreatedAtMS int64 `json:"createdAtMs"` +} diff --git a/server/admin/internal/modules/coinledger/handler.go b/server/admin/internal/modules/coinledger/handler.go new file mode 100644 index 00000000..d7e09ed2 --- /dev/null +++ b/server/admin/internal/modules/coinledger/handler.go @@ -0,0 +1,80 @@ +package coinledger + +import ( + "database/sql" + "strconv" + "strings" + + "hyapp-admin-server/internal/appctx" + "hyapp-admin-server/internal/modules/shared" + "hyapp-admin-server/internal/response" + + "github.com/gin-gonic/gin" +) + +type Handler struct { + service *Service +} + +func New(userDB *sql.DB, walletDB *sql.DB) *Handler { + return &Handler{service: NewService(userDB, walletDB)} +} + +func (h *Handler) ListCoinLedger(c *gin.Context) { + query, ok := parseListQuery(c) + if !ok { + return + } + items, total, err := h.service.ListCoinLedger(c.Request.Context(), appctx.FromContext(c.Request.Context()), query) + if err != nil { + response.ServerError(c, "获取金币流水失败") + return + } + response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total}) +} + +func parseListQuery(c *gin.Context) (listQuery, bool) { + options := shared.ListOptions(c) + startAtMS, ok := optionalInt64(c, "start_at_ms", "startAtMs") + if !ok { + response.BadRequest(c, "开始时间不正确") + return listQuery{}, false + } + endAtMS, ok := optionalInt64(c, "end_at_ms", "endAtMs") + if !ok { + response.BadRequest(c, "结束时间不正确") + return listQuery{}, false + } + if startAtMS > 0 && endAtMS > 0 && startAtMS >= endAtMS { + response.BadRequest(c, "时间区间不正确") + return listQuery{}, false + } + return normalizeListQuery(listQuery{ + Page: options.Page, + PageSize: options.PageSize, + UserKeyword: strings.TrimSpace(firstQuery(c, "user_keyword", "userKeyword", "user_id", "userId", "keyword")), + StartAtMS: startAtMS, + EndAtMS: endAtMS, + }), true +} + +func optionalInt64(c *gin.Context, keys ...string) (int64, bool) { + value := strings.TrimSpace(firstQuery(c, keys...)) + if value == "" { + return 0, true + } + parsed, err := strconv.ParseInt(value, 10, 64) + if err != nil || parsed < 0 { + return 0, false + } + return parsed, true +} + +func firstQuery(c *gin.Context, keys ...string) string { + for _, key := range keys { + if value := c.Query(key); value != "" { + return value + } + } + return "" +} diff --git a/server/admin/internal/modules/coinledger/request.go b/server/admin/internal/modules/coinledger/request.go new file mode 100644 index 00000000..125d20b9 --- /dev/null +++ b/server/admin/internal/modules/coinledger/request.go @@ -0,0 +1,9 @@ +package coinledger + +type listQuery struct { + Page int + PageSize int + UserKeyword string + StartAtMS int64 + EndAtMS int64 +} diff --git a/server/admin/internal/modules/coinledger/routes.go b/server/admin/internal/modules/coinledger/routes.go new file mode 100644 index 00000000..1f117022 --- /dev/null +++ b/server/admin/internal/modules/coinledger/routes.go @@ -0,0 +1,15 @@ +package coinledger + +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/operations/coin-ledger", middleware.RequirePermission("coin-ledger:view"), h.ListCoinLedger) +} diff --git a/server/admin/internal/modules/coinledger/service.go b/server/admin/internal/modules/coinledger/service.go new file mode 100644 index 00000000..fb06587c --- /dev/null +++ b/server/admin/internal/modules/coinledger/service.go @@ -0,0 +1,294 @@ +package coinledger + +import ( + "context" + "database/sql" + "fmt" + "strconv" + "strings" +) + +const ( + coinAssetType = "COIN" + directionIn = "income" + directionOut = "expense" +) + +type Service struct { + userDB *sql.DB + walletDB *sql.DB +} + +type userProfile struct { + UserID int64 + DisplayUserID string + Username string + Avatar string +} + +func NewService(userDB *sql.DB, walletDB *sql.DB) *Service { + return &Service{userDB: userDB, walletDB: walletDB} +} + +func (s *Service) ListCoinLedger(ctx context.Context, appCode string, query listQuery) ([]coinLedgerEntryDTO, int64, error) { + query = normalizeListQuery(query) + if s == nil || s.walletDB == nil { + return nil, 0, fmt.Errorf("wallet mysql is not configured") + } + + userIDs, userFiltered, err := s.resolveUserFilter(ctx, appCode, query.UserKeyword) + if err != nil { + return nil, 0, err + } + if userFiltered && len(userIDs) == 0 { + return []coinLedgerEntryDTO{}, 0, nil + } + + // 后台只做只读查询:金币流水事实仍以 wallet_entries 追加分录为准,不在 admin 库冗余账务状态。 + whereSQL, args := coinLedgerWhere(appCode, query, userIDs) + var total int64 + if err := s.walletDB.QueryRowContext(ctx, ` + SELECT COUNT(*) + FROM wallet_entries e + JOIN wallet_transactions wt ON wt.app_code = e.app_code AND wt.transaction_id = e.transaction_id + `+whereSQL, + args..., + ).Scan(&total); err != nil { + return nil, 0, err + } + + rows, err := s.walletDB.QueryContext(ctx, ` + SELECT e.entry_id, e.transaction_id, e.user_id, wt.biz_type, + e.available_delta, e.available_after, e.counterparty_user_id, + e.room_id, e.created_at_ms + FROM wallet_entries e + JOIN wallet_transactions wt ON wt.app_code = e.app_code AND wt.transaction_id = e.transaction_id + `+whereSQL+` + ORDER BY e.created_at_ms DESC, e.entry_id DESC + LIMIT ? OFFSET ?`, + append(args, query.PageSize, offset(query.Page, query.PageSize))..., + ) + if err != nil { + return nil, 0, err + } + defer rows.Close() + + items := make([]coinLedgerEntryDTO, 0, query.PageSize) + itemUserIDs := make([]int64, 0, query.PageSize) + for rows.Next() { + var item coinLedgerEntryDTO + var userID int64 + var counterpartyUserID int64 + if err := rows.Scan( + &item.EntryID, + &item.TransactionID, + &userID, + &item.BizType, + &item.AvailableDelta, + &item.AvailableAfter, + &counterpartyUserID, + &item.RoomID, + &item.CreatedAtMS, + ); err != nil { + return nil, 0, err + } + item.UserID = strconv.FormatInt(userID, 10) + item.User = coinLedgerUserDTO{UserID: item.UserID} + item.CounterpartyUserID = formatOptionalID(counterpartyUserID) + item.Direction = directionForDelta(item.AvailableDelta) + item.Amount = absInt64(item.AvailableDelta) + items = append(items, item) + itemUserIDs = append(itemUserIDs, userID) + } + if err := rows.Err(); err != nil { + return nil, 0, err + } + + profiles, err := s.userProfiles(ctx, appCode, itemUserIDs) + if err != nil { + return nil, 0, err + } + for i := range items { + userID, _ := strconv.ParseInt(items[i].UserID, 10, 64) + if profile, ok := profiles[userID]; ok { + items[i].User = coinLedgerUserDTO{ + UserID: strconv.FormatInt(profile.UserID, 10), + DisplayUserID: profile.DisplayUserID, + Username: profile.Username, + Avatar: profile.Avatar, + } + } + } + return items, total, nil +} + +func (s *Service) resolveUserFilter(ctx context.Context, appCode string, keyword string) ([]int64, bool, error) { + keyword = strings.TrimSpace(keyword) + if keyword == "" { + return nil, false, nil + } + directUserIDs := make([]int64, 0, 1) + if numeric, err := strconv.ParseInt(keyword, 10, 64); err == nil && numeric > 0 { + directUserIDs = append(directUserIDs, numeric) + } + if s == nil || s.userDB == nil { + if len(directUserIDs) > 0 { + return directUserIDs, true, nil + } + return nil, true, fmt.Errorf("user mysql is not configured") + } + + // 用户列筛选同时支持长 ID、当前短 ID 和昵称;数字关键字直接加入 user_id,避免用户资料缺失时查不到账务事实。 + args := []any{appCode} + where := "WHERE app_code = ? AND (current_display_user_id = ?" + args = append(args, keyword) + if numeric, err := strconv.ParseInt(keyword, 10, 64); err == nil && numeric > 0 { + where += " OR user_id = ?" + args = append(args, numeric) + } + where += " OR username LIKE ? ESCAPE '\\\\')" + args = append(args, "%"+escapeLike(keyword)+"%") + + rows, err := s.userDB.QueryContext(ctx, ` + SELECT user_id + FROM users + `+where+` + ORDER BY updated_at_ms DESC, user_id DESC + LIMIT 1000`, + args..., + ) + if err != nil { + return nil, true, err + } + defer rows.Close() + + userIDs := append([]int64(nil), directUserIDs...) + for rows.Next() { + var userID int64 + if err := rows.Scan(&userID); err != nil { + return nil, true, err + } + userIDs = append(userIDs, userID) + } + return uniqueInt64s(userIDs), true, rows.Err() +} + +func (s *Service) userProfiles(ctx context.Context, appCode string, userIDs []int64) (map[int64]userProfile, error) { + result := make(map[int64]userProfile, len(userIDs)) + if s == nil || s.userDB == nil || len(userIDs) == 0 { + return result, nil + } + userIDs = uniqueInt64s(userIDs) + args := make([]any, 0, len(userIDs)+1) + args = append(args, appCode) + for _, id := range userIDs { + args = append(args, id) + } + rows, err := s.userDB.QueryContext(ctx, fmt.Sprintf(` + SELECT user_id, current_display_user_id, COALESCE(username, ''), COALESCE(avatar, '') + FROM users + WHERE app_code = ? AND user_id IN (%s) + `, placeholders(len(userIDs))), args...) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var profile userProfile + if err := rows.Scan(&profile.UserID, &profile.DisplayUserID, &profile.Username, &profile.Avatar); err != nil { + return nil, err + } + result[profile.UserID] = profile + } + return result, rows.Err() +} + +func coinLedgerWhere(appCode string, query listQuery, userIDs []int64) (string, []any) { + where := "WHERE e.app_code = ? AND e.asset_type = ?" + args := []any{appCode, coinAssetType} + if query.StartAtMS > 0 { + where += " AND e.created_at_ms >= ?" + args = append(args, query.StartAtMS) + } + if query.EndAtMS > 0 { + where += " AND e.created_at_ms < ?" + args = append(args, query.EndAtMS) + } + if len(userIDs) > 0 { + where += fmt.Sprintf(" AND e.user_id IN (%s)", placeholders(len(userIDs))) + for _, id := range userIDs { + args = append(args, id) + } + } + return where, args +} + +func normalizeListQuery(query listQuery) listQuery { + if query.Page < 1 { + query.Page = 1 + } + if query.PageSize < 1 { + query.PageSize = 20 + } + if query.PageSize > 100 { + query.PageSize = 100 + } + query.UserKeyword = strings.TrimSpace(query.UserKeyword) + return query +} + +func directionForDelta(delta int64) string { + if delta < 0 { + return directionOut + } + return directionIn +} + +func absInt64(value int64) int64 { + if value < 0 { + return -value + } + return value +} + +func formatOptionalID(value int64) string { + if value <= 0 { + return "" + } + return strconv.FormatInt(value, 10) +} + +func offset(page int, pageSize int) int { + if page < 1 { + page = 1 + } + return (page - 1) * pageSize +} + +func placeholders(count int) string { + if count <= 0 { + return "" + } + return strings.TrimRight(strings.Repeat("?,", count), ",") +} + +func uniqueInt64s(values []int64) []int64 { + seen := make(map[int64]struct{}, len(values)) + result := make([]int64, 0, len(values)) + for _, value := range values { + if _, ok := seen[value]; ok { + continue + } + seen[value] = struct{}{} + result = append(result, value) + } + return result +} + +func escapeLike(value string) string { + value = strings.ReplaceAll(value, `\`, `\\`) + value = strings.ReplaceAll(value, `%`, `\%`) + value = strings.ReplaceAll(value, `_`, `\_`) + return value +} diff --git a/server/admin/internal/modules/coinledger/service_test.go b/server/admin/internal/modules/coinledger/service_test.go new file mode 100644 index 00000000..4c12b2ed --- /dev/null +++ b/server/admin/internal/modules/coinledger/service_test.go @@ -0,0 +1,30 @@ +package coinledger + +import "testing" + +func TestNormalizeListQueryCapsPageSize(t *testing.T) { + query := normalizeListQuery(listQuery{Page: -1, PageSize: 1000, UserKeyword: " 10001 "}) + if query.Page != 1 || query.PageSize != 100 || query.UserKeyword != "10001" { + t.Fatalf("normalized query mismatch: %+v", query) + } +} + +func TestCoinLedgerWhereUsesTimeWindowAndUserFilter(t *testing.T) { + query := listQuery{StartAtMS: 100, EndAtMS: 200} + where, args := coinLedgerWhere("lalu", query, []int64{11, 22}) + if want := "WHERE e.app_code = ? AND e.asset_type = ? AND e.created_at_ms >= ? AND e.created_at_ms < ? AND e.user_id IN (?,?)"; where != want { + t.Fatalf("where mismatch:\nwant %s\n got %s", want, where) + } + if len(args) != 6 || args[0] != "lalu" || args[1] != coinAssetType || args[2] != int64(100) || args[3] != int64(200) || args[4] != int64(11) || args[5] != int64(22) { + t.Fatalf("args mismatch: %#v", args) + } +} + +func TestDirectionAndAmountForDelta(t *testing.T) { + if directionForDelta(-9) != directionOut || absInt64(-9) != 9 { + t.Fatalf("expense projection mismatch") + } + if directionForDelta(12) != directionIn || absInt64(12) != 12 { + t.Fatalf("income projection mismatch") + } +} diff --git a/server/admin/internal/modules/payment/dto.go b/server/admin/internal/modules/payment/dto.go index 888c5436..d6fd1387 100644 --- a/server/admin/internal/modules/payment/dto.go +++ b/server/admin/internal/modules/payment/dto.go @@ -1,6 +1,12 @@ package payment -import walletv1 "hyapp.local/api/proto/wallet/v1" +import ( + "fmt" + "strconv" + "strings" + + walletv1 "hyapp.local/api/proto/wallet/v1" +) type rechargeBillDTO struct { AppCode string `json:"appCode"` @@ -23,6 +29,32 @@ type rechargeBillDTO struct { CreatedAtMS int64 `json:"createdAtMs"` } +type rechargeProductDTO struct { + AppCode string `json:"appCode"` + ProductID int64 `json:"productId"` + ProductCode string `json:"productCode"` + ProductName string `json:"productName"` + Description string `json:"description"` + Platform string `json:"platform"` + Channel string `json:"channel"` + CurrencyCode string `json:"currencyCode"` + AmountUSDT string `json:"amountUsdt"` + AmountUSDTMicro int64 `json:"amountUsdtMicro"` + AmountMicro int64 `json:"amountMicro"` + AmountMinor int64 `json:"amountMinor"` + CoinAmount int64 `json:"coinAmount"` + PolicyVersion string `json:"policyVersion"` + RegionIDs []int64 `json:"regionIds"` + ResourceAssetType string `json:"resourceAssetType"` + Status string `json:"status"` + Enabled bool `json:"enabled"` + SortOrder int32 `json:"sortOrder"` + CreatedByUserID int64 `json:"createdByUserId"` + UpdatedByUserID int64 `json:"updatedByUserId"` + CreatedAtMS int64 `json:"createdAtMs"` + UpdatedAtMS int64 `json:"updatedAtMs"` +} + func rechargeBillFromProto(item *walletv1.RechargeBill) rechargeBillDTO { if item == nil { return rechargeBillDTO{} @@ -48,3 +80,46 @@ func rechargeBillFromProto(item *walletv1.RechargeBill) rechargeBillDTO { CreatedAtMS: item.GetCreatedAtMs(), } } + +func rechargeProductFromProto(item *walletv1.RechargeProduct) rechargeProductDTO { + if item == nil { + return rechargeProductDTO{} + } + return rechargeProductDTO{ + AppCode: item.GetAppCode(), + ProductID: item.GetProductId(), + ProductCode: item.GetProductCode(), + ProductName: item.GetProductName(), + Description: item.GetDescription(), + Platform: item.GetPlatform(), + Channel: item.GetChannel(), + CurrencyCode: item.GetCurrencyCode(), + AmountUSDT: formatUSDTMicro(item.GetAmountMicro()), + AmountUSDTMicro: item.GetAmountMicro(), + AmountMicro: item.GetAmountMicro(), + AmountMinor: item.GetAmountMinor(), + CoinAmount: item.GetCoinAmount(), + PolicyVersion: item.GetPolicyVersion(), + RegionIDs: append([]int64(nil), item.GetRegionIds()...), + ResourceAssetType: item.GetResourceAssetType(), + Status: item.GetStatus(), + Enabled: item.GetEnabled(), + SortOrder: item.GetSortOrder(), + CreatedByUserID: item.GetCreatedByUserId(), + UpdatedByUserID: item.GetUpdatedByUserId(), + CreatedAtMS: item.GetCreatedAtMs(), + UpdatedAtMS: item.GetUpdatedAtMs(), + } +} + +func formatUSDTMicro(amount int64) string { + if amount <= 0 { + return "0" + } + whole := amount / usdtMicroUnit + fraction := amount % usdtMicroUnit + if fraction == 0 { + return strconv.FormatInt(whole, 10) + } + return fmt.Sprintf("%d.%s", whole, strings.TrimRight(fmt.Sprintf("%06d", fraction), "0")) +} diff --git a/server/admin/internal/modules/payment/handler.go b/server/admin/internal/modules/payment/handler.go index 8afac36a..d7ce37e4 100644 --- a/server/admin/internal/modules/payment/handler.go +++ b/server/admin/internal/modules/payment/handler.go @@ -1,6 +1,8 @@ package payment import ( + "errors" + "math" "strconv" "strings" @@ -12,14 +14,19 @@ import ( walletv1 "hyapp.local/api/proto/wallet/v1" "github.com/gin-gonic/gin" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) +const usdtMicroUnit int64 = 1_000_000 + type Handler struct { wallet walletclient.Client + audit shared.OperationLogger } -func New(wallet walletclient.Client) *Handler { - return &Handler{wallet: wallet} +func New(wallet walletclient.Client, audit shared.OperationLogger) *Handler { + return &Handler{wallet: wallet, audit: audit} } func (h *Handler) ListRechargeBills(c *gin.Context) { @@ -50,6 +57,128 @@ func (h *Handler) ListRechargeBills(c *gin.Context) { response.OK(c, response.Page{Items: items, Page: options.Page, PageSize: options.PageSize, Total: resp.GetTotal()}) } +func (h *Handler) ListRechargeProducts(c *gin.Context) { + options := shared.ListOptions(c) + resp, err := h.wallet.ListAdminRechargeProducts(c.Request.Context(), &walletv1.ListAdminRechargeProductsRequest{ + RequestId: middleware.CurrentRequestID(c), + AppCode: appctx.FromContext(c.Request.Context()), + Status: strings.TrimSpace(firstQuery(c, "status")), + Platform: strings.TrimSpace(firstQuery(c, "platform")), + RegionId: queryInt64(c, "region_id", "regionId"), + Keyword: options.Keyword, + Page: int32(options.Page), + PageSize: int32(options.PageSize), + }) + if err != nil { + writeWalletError(c, err, "获取内购配置失败") + return + } + items := make([]rechargeProductDTO, 0, len(resp.GetProducts())) + for _, item := range resp.GetProducts() { + items = append(items, rechargeProductFromProto(item)) + } + response.OK(c, response.Page{Items: items, Page: options.Page, PageSize: options.PageSize, Total: resp.GetTotal()}) +} + +func (h *Handler) CreateRechargeProduct(c *gin.Context) { + var request rechargeProductRequest + if err := c.ShouldBindJSON(&request); err != nil { + response.BadRequest(c, "内购配置参数不正确") + return + } + amountMicro, err := parseUSDTMicro(request.AmountUSDT, request.AmountUSDTMicro) + if err != nil { + response.BadRequest(c, "金额USDT不正确") + return + } + resp, err := h.wallet.CreateRechargeProduct(c.Request.Context(), &walletv1.CreateRechargeProductRequest{ + RequestId: middleware.CurrentRequestID(c), + AppCode: appctx.FromContext(c.Request.Context()), + AmountMicro: amountMicro, + CoinAmount: request.CoinAmount, + ProductName: strings.TrimSpace(request.ProductName), + Description: strings.TrimSpace(request.Description), + Platform: strings.TrimSpace(request.Platform), + RegionIds: request.RegionIDs, + Enabled: request.Enabled, + OperatorUserId: actorID(c), + }) + if err != nil { + writeWalletError(c, err, "创建内购配置失败") + return + } + item := rechargeProductFromProto(resp.GetProduct()) + shared.OperationLogWithResourceID(c, h.audit, "create-recharge-product", "wallet_recharge_products", strconv.FormatInt(item.ProductID, 10), "success", item.ProductCode) + response.Created(c, item) +} + +func (h *Handler) UpdateRechargeProduct(c *gin.Context) { + productID, ok := productID(c) + if !ok { + return + } + var request rechargeProductRequest + if err := c.ShouldBindJSON(&request); err != nil { + response.BadRequest(c, "内购配置参数不正确") + return + } + amountMicro, err := parseUSDTMicro(request.AmountUSDT, request.AmountUSDTMicro) + if err != nil { + response.BadRequest(c, "金额USDT不正确") + return + } + resp, err := h.wallet.UpdateRechargeProduct(c.Request.Context(), &walletv1.UpdateRechargeProductRequest{ + RequestId: middleware.CurrentRequestID(c), + AppCode: appctx.FromContext(c.Request.Context()), + ProductId: productID, + AmountMicro: amountMicro, + CoinAmount: request.CoinAmount, + ProductName: strings.TrimSpace(request.ProductName), + Description: strings.TrimSpace(request.Description), + Platform: strings.TrimSpace(request.Platform), + RegionIds: request.RegionIDs, + Enabled: request.Enabled, + OperatorUserId: actorID(c), + }) + if err != nil { + writeWalletError(c, err, "修改内购配置失败") + return + } + item := rechargeProductFromProto(resp.GetProduct()) + shared.OperationLogWithResourceID(c, h.audit, "update-recharge-product", "wallet_recharge_products", strconv.FormatInt(item.ProductID, 10), "success", item.ProductCode) + response.OK(c, item) +} + +func (h *Handler) DeleteRechargeProduct(c *gin.Context) { + productID, ok := productID(c) + if !ok { + return + } + _, err := h.wallet.DeleteRechargeProduct(c.Request.Context(), &walletv1.DeleteRechargeProductRequest{ + RequestId: middleware.CurrentRequestID(c), + AppCode: appctx.FromContext(c.Request.Context()), + ProductId: productID, + OperatorUserId: actorID(c), + }) + if err != nil { + writeWalletError(c, err, "删除内购配置失败") + return + } + shared.OperationLogWithResourceID(c, h.audit, "delete-recharge-product", "wallet_recharge_products", strconv.FormatInt(productID, 10), "success", "") + response.OK(c, gin.H{"deleted": true}) +} + +type rechargeProductRequest struct { + AmountUSDT string `json:"amountUsdt"` + AmountUSDTMicro int64 `json:"amountUsdtMicro"` + CoinAmount int64 `json:"coinAmount"` + ProductName string `json:"productName"` + Description string `json:"description"` + Platform string `json:"platform"` + RegionIDs []int64 `json:"regionIds"` + Enabled bool `json:"enabled"` +} + func queryInt64(c *gin.Context, keys ...string) int64 { value := strings.TrimSpace(firstQuery(c, keys...)) if value == "" { @@ -70,3 +199,84 @@ func firstQuery(c *gin.Context, keys ...string) string { } return "" } + +func productID(c *gin.Context) (int64, bool) { + value := strings.TrimSpace(c.Param("product_id")) + parsed, err := strconv.ParseInt(value, 10, 64) + if err != nil || parsed <= 0 { + response.BadRequest(c, "内购配置 ID 不正确") + return 0, false + } + return parsed, true +} + +func actorID(c *gin.Context) int64 { + return int64(shared.ActorFromContext(c).UserID) +} + +func parseUSDTMicro(amountText string, amountMicro int64) (int64, error) { + if amountMicro > 0 { + return amountMicro, nil + } + raw := strings.TrimSpace(amountText) + if raw == "" { + return 0, errors.New("amount is required") + } + if strings.HasPrefix(raw, "+") { + raw = strings.TrimPrefix(raw, "+") + } + parts := strings.Split(raw, ".") + if len(parts) > 2 || parts[0] == "" { + return 0, errors.New("amount format is invalid") + } + if !allDigits(parts[0]) { + return 0, errors.New("amount integer part is invalid") + } + whole, err := strconv.ParseInt(parts[0], 10, 64) + if err != nil || whole > math.MaxInt64/usdtMicroUnit { + return 0, errors.New("amount is too large") + } + var fraction int64 + if len(parts) == 2 { + if parts[1] == "" || len(parts[1]) > 6 || !allDigits(parts[1]) { + return 0, errors.New("amount fraction part is invalid") + } + padded := parts[1] + strings.Repeat("0", 6-len(parts[1])) + fraction, err = strconv.ParseInt(padded, 10, 64) + if err != nil { + return 0, errors.New("amount fraction part is invalid") + } + } + if whole > (math.MaxInt64-fraction)/usdtMicroUnit { + return 0, errors.New("amount is too large") + } + value := whole*usdtMicroUnit + fraction + if value <= 0 { + return 0, errors.New("amount must be positive") + } + return value, nil +} + +func allDigits(value string) bool { + for _, char := range value { + if char < '0' || char > '9' { + return false + } + } + return value != "" +} + +func writeWalletError(c *gin.Context, err error, fallback string) { + message := fallback + if st, ok := status.FromError(err); ok && strings.TrimSpace(st.Message()) != "" { + message = st.Message() + } + switch status.Code(err) { + case codes.InvalidArgument, codes.AlreadyExists, codes.FailedPrecondition, codes.Aborted: + response.BadRequest(c, message) + case codes.NotFound: + response.NotFound(c, message) + default: + response.ServerError(c, fallback) + } +} diff --git a/server/admin/internal/modules/payment/routes.go b/server/admin/internal/modules/payment/routes.go index 06e1e247..0a20785e 100644 --- a/server/admin/internal/modules/payment/routes.go +++ b/server/admin/internal/modules/payment/routes.go @@ -12,4 +12,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/recharge-products", middleware.RequirePermission("payment-product:view"), h.ListRechargeProducts) + protected.POST("/admin/payment/recharge-products", middleware.RequirePermission("payment-product:create"), h.CreateRechargeProduct) + protected.PUT("/admin/payment/recharge-products/:product_id", middleware.RequirePermission("payment-product:update"), h.UpdateRechargeProduct) + protected.DELETE("/admin/payment/recharge-products/:product_id", middleware.RequirePermission("payment-product:delete"), h.DeleteRechargeProduct) } diff --git a/server/admin/internal/modules/registrationreward/handler.go b/server/admin/internal/modules/registrationreward/handler.go new file mode 100644 index 00000000..34e50931 --- /dev/null +++ b/server/admin/internal/modules/registrationreward/handler.go @@ -0,0 +1,305 @@ +package registrationreward + +import ( + "context" + "database/sql" + "strings" + "time" + + "hyapp-admin-server/internal/appctx" + "hyapp-admin-server/internal/integration/activityclient" + "hyapp-admin-server/internal/middleware" + "hyapp-admin-server/internal/modules/shared" + "hyapp-admin-server/internal/response" + activityv1 "hyapp.local/api/proto/activity/v1" + + "github.com/gin-gonic/gin" +) + +type Handler struct { + activity activityclient.Client + userDB *sql.DB + audit shared.OperationLogger +} + +func New(activity activityclient.Client, userDB *sql.DB, audit shared.OperationLogger) *Handler { + return &Handler{activity: activity, userDB: userDB, audit: audit} +} + +type configRequest struct { + Enabled bool `json:"enabled"` + RewardType string `json:"reward_type"` + CoinAmount int64 `json:"coin_amount"` + ResourceGroupID int64 `json:"resource_group_id"` + DailyLimit int64 `json:"daily_limit"` +} + +type configDTO struct { + AppCode string `json:"app_code"` + Enabled bool `json:"enabled"` + RewardType string `json:"reward_type"` + CoinAmount int64 `json:"coin_amount"` + ResourceGroupID int64 `json:"resource_group_id"` + DailyLimit int64 `json:"daily_limit"` + UpdatedByAdminID int64 `json:"updated_by_admin_id"` + CreatedAtMS int64 `json:"created_at_ms"` + UpdatedAtMS int64 `json:"updated_at_ms"` +} + +type claimDTO struct { + ClaimID string `json:"claim_id"` + CommandID string `json:"command_id"` + UserID int64 `json:"user_id"` + User *userDTO `json:"user,omitempty"` + RewardDay string `json:"reward_day"` + RewardType string `json:"reward_type"` + CoinAmount int64 `json:"coin_amount"` + ResourceGroupID int64 `json:"resource_group_id"` + Status string `json:"status"` + WalletCommandID string `json:"wallet_command_id"` + WalletTransactionID string `json:"wallet_transaction_id"` + ResourceGrantID string `json:"resource_grant_id"` + FailureReason string `json:"failure_reason"` + ClaimedAtMS int64 `json:"claimed_at_ms"` + CreatedAtMS int64 `json:"created_at_ms"` + UpdatedAtMS int64 `json:"updated_at_ms"` +} + +type userDTO struct { + UserID int64 `json:"user_id"` + DisplayUserID string `json:"display_user_id"` + Username string `json:"username"` + Avatar string `json:"avatar"` +} + +func (h *Handler) GetRegistrationRewardConfig(c *gin.Context) { + resp, err := h.activity.GetRegistrationRewardConfig(c.Request.Context(), &activityv1.GetRegistrationRewardConfigRequest{Meta: h.meta(c)}) + if err != nil { + response.ServerError(c, "获取注册奖励配置失败") + return + } + response.OK(c, configFromProto(resp.GetConfig())) +} + +func (h *Handler) UpdateRegistrationRewardConfig(c *gin.Context) { + var req configRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.BadRequest(c, "注册奖励配置参数不正确") + return + } + resp, err := h.activity.UpdateRegistrationRewardConfig(c.Request.Context(), &activityv1.UpdateRegistrationRewardConfigRequest{ + Meta: h.meta(c), + Enabled: req.Enabled, + RewardType: strings.TrimSpace(req.RewardType), + CoinAmount: req.CoinAmount, + ResourceGroupId: req.ResourceGroupID, + DailyLimit: req.DailyLimit, + OperatorAdminId: int64(middleware.CurrentUserID(c)), + }) + if err != nil { + response.BadRequest(c, err.Error()) + return + } + item := configFromProto(resp.GetConfig()) + shared.OperationLogWithResourceID(c, h.audit, "update-registration-reward", "registration_reward_configs", item.AppCode, "success", item.RewardType) + response.OK(c, item) +} + +func (h *Handler) ListRegistrationRewardClaims(c *gin.Context) { + options := shared.ListOptions(c) + userID, matched, ok := h.resolveClaimUserID(c.Request.Context(), strings.TrimSpace(options.Keyword)) + if !ok { + response.ServerError(c, "查询用户信息失败") + return + } + if options.Keyword != "" && !matched { + response.OK(c, response.Page{Items: []claimDTO{}, Page: options.Page, PageSize: options.PageSize, Total: 0}) + return + } + resp, err := h.activity.ListRegistrationRewardClaims(c.Request.Context(), &activityv1.ListRegistrationRewardClaimsRequest{ + Meta: h.meta(c), + Status: strings.TrimSpace(options.Status), + UserId: userID, + Page: int32(options.Page), + PageSize: int32(options.PageSize), + }) + if err != nil { + response.ServerError(c, "获取注册奖励领取记录失败") + return + } + items := make([]claimDTO, 0, len(resp.GetClaims())) + for _, item := range resp.GetClaims() { + items = append(items, claimFromProto(item)) + } + if err := h.fillClaimUsers(c.Request.Context(), items); err != nil { + response.ServerError(c, "补全用户信息失败") + return + } + response.OK(c, response.Page{Items: items, Page: options.Page, PageSize: options.PageSize, Total: resp.GetTotal()}) +} + +func (h *Handler) meta(c *gin.Context) *activityv1.RequestMeta { + return &activityv1.RequestMeta{ + RequestId: middleware.CurrentRequestID(c), + Caller: "admin-server", + AppCode: appctx.FromContext(c.Request.Context()), + SentAtMs: time.Now().UnixMilli(), + } +} + +func (h *Handler) resolveClaimUserID(ctx context.Context, keyword string) (int64, bool, bool) { + if keyword == "" { + return 0, false, true + } + if h.userDB == nil { + return 0, false, true + } + appCode := appctx.FromContext(ctx) + rows, err := h.userDB.QueryContext(ctx, ` + SELECT user_id + FROM users + WHERE app_code = ? + AND ( + CAST(user_id AS CHAR) = ? + OR current_display_user_id = ? + OR username LIKE ? + ) + ORDER BY + CASE + WHEN CAST(user_id AS CHAR) = ? THEN 0 + WHEN current_display_user_id = ? THEN 1 + ELSE 2 + END, + user_id DESC + LIMIT 1`, + appCode, keyword, keyword, "%"+keyword+"%", keyword, keyword, + ) + if err != nil { + return 0, false, false + } + defer rows.Close() + if !rows.Next() { + return 0, false, rows.Err() == nil + } + var userID int64 + if err := rows.Scan(&userID); err != nil { + return 0, false, false + } + return userID, true, rows.Err() == nil +} + +func (h *Handler) fillClaimUsers(ctx context.Context, claims []claimDTO) error { + if h.userDB == nil || len(claims) == 0 { + return nil + } + ids := collectClaimUserIDs(claims) + if len(ids) == 0 { + return nil + } + args := append([]any{appctx.FromContext(ctx)}, int64Args(ids)...) + rows, err := h.userDB.QueryContext(ctx, ` + SELECT user_id, current_display_user_id, COALESCE(username, ''), COALESCE(avatar, '') + FROM users + WHERE app_code = ? AND user_id IN (`+placeholders(len(ids))+`)`, + args..., + ) + if err != nil { + return err + } + defer rows.Close() + users := make(map[int64]userDTO, len(ids)) + for rows.Next() { + var user userDTO + if err := rows.Scan(&user.UserID, &user.DisplayUserID, &user.Username, &user.Avatar); err != nil { + return err + } + users[user.UserID] = user + } + if err := rows.Err(); err != nil { + return err + } + for index := range claims { + if user, ok := users[claims[index].UserID]; ok { + claims[index].User = &user + continue + } + // 领取事实必须可追踪;用户资料缺失时仍返回 user_id 让后台能定位数据问题。 + claims[index].User = &userDTO{UserID: claims[index].UserID} + } + return nil +} + +func configFromProto(item *activityv1.RegistrationRewardConfig) configDTO { + if item == nil { + return configDTO{RewardType: "coin"} + } + return configDTO{ + AppCode: item.GetAppCode(), + Enabled: item.GetEnabled(), + RewardType: item.GetRewardType(), + CoinAmount: item.GetCoinAmount(), + ResourceGroupID: item.GetResourceGroupId(), + DailyLimit: item.GetDailyLimit(), + UpdatedByAdminID: item.GetUpdatedByAdminId(), + CreatedAtMS: item.GetCreatedAtMs(), + UpdatedAtMS: item.GetUpdatedAtMs(), + } +} + +func claimFromProto(item *activityv1.RegistrationRewardClaim) claimDTO { + if item == nil { + return claimDTO{} + } + return claimDTO{ + ClaimID: item.GetClaimId(), + CommandID: item.GetCommandId(), + UserID: item.GetUserId(), + RewardDay: item.GetRewardDay(), + RewardType: item.GetRewardType(), + CoinAmount: item.GetCoinAmount(), + ResourceGroupID: item.GetResourceGroupId(), + Status: item.GetStatus(), + WalletCommandID: item.GetWalletCommandId(), + WalletTransactionID: item.GetWalletTransactionId(), + ResourceGrantID: item.GetResourceGrantId(), + FailureReason: item.GetFailureReason(), + ClaimedAtMS: item.GetClaimedAtMs(), + CreatedAtMS: item.GetCreatedAtMs(), + UpdatedAtMS: item.GetUpdatedAtMs(), + } +} + +func collectClaimUserIDs(claims []claimDTO) []int64 { + seen := make(map[int64]struct{}, len(claims)) + ids := make([]int64, 0, len(claims)) + for _, claim := range claims { + if claim.UserID <= 0 { + continue + } + if _, ok := seen[claim.UserID]; ok { + continue + } + seen[claim.UserID] = struct{}{} + ids = append(ids, claim.UserID) + } + return ids +} + +func placeholders(count int) string { + if count <= 0 { + return "" + } + items := make([]string, count) + for index := range items { + items[index] = "?" + } + return strings.Join(items, ",") +} + +func int64Args(values []int64) []any { + args := make([]any, 0, len(values)) + for _, value := range values { + args = append(args, value) + } + return args +} diff --git a/server/admin/internal/modules/registrationreward/routes.go b/server/admin/internal/modules/registrationreward/routes.go new file mode 100644 index 00000000..48ee0ab3 --- /dev/null +++ b/server/admin/internal/modules/registrationreward/routes.go @@ -0,0 +1,17 @@ +package registrationreward + +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/activity/registration-reward/config", middleware.RequirePermission("registration-reward:view"), h.GetRegistrationRewardConfig) + protected.PUT("/admin/activity/registration-reward/config", middleware.RequirePermission("registration-reward:update"), h.UpdateRegistrationRewardConfig) + protected.GET("/admin/activity/registration-reward/claims", middleware.RequirePermission("registration-reward:view"), h.ListRegistrationRewardClaims) +} diff --git a/server/admin/internal/modules/resource/dto.go b/server/admin/internal/modules/resource/dto.go index 9930b545..1a39e886 100644 --- a/server/admin/internal/modules/resource/dto.go +++ b/server/admin/internal/modules/resource/dto.go @@ -104,11 +104,21 @@ type grantDTO struct { Status string `json:"status"` Reason string `json:"reason"` OperatorUserID int64 `json:"operatorUserId"` + Operator *operatorDTO `json:"operator,omitempty"` Items []grantItemDTO `json:"items"` CreatedAtMS int64 `json:"createdAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } +type operatorDTO struct { + Source string `json:"source"` + UserID int64 `json:"userId,string,omitempty"` + DisplayUserID string `json:"displayUserId,omitempty"` + Username string `json:"username,omitempty"` + Name string `json:"name,omitempty"` + Avatar string `json:"avatar,omitempty"` +} + func resourceFromProto(item *walletv1.Resource) resourceDTO { if item == nil { return resourceDTO{} diff --git a/server/admin/internal/modules/resource/handler.go b/server/admin/internal/modules/resource/handler.go index 63a1a7f0..2942cd96 100644 --- a/server/admin/internal/modules/resource/handler.go +++ b/server/admin/internal/modules/resource/handler.go @@ -1,6 +1,7 @@ package resource import ( + "database/sql" "fmt" "strconv" "strings" @@ -9,6 +10,7 @@ import ( "hyapp-admin-server/internal/integration/walletclient" "hyapp-admin-server/internal/middleware" "hyapp-admin-server/internal/modules/shared" + "hyapp-admin-server/internal/repository" "hyapp-admin-server/internal/response" walletv1 "hyapp.local/api/proto/wallet/v1" @@ -17,11 +19,13 @@ import ( type Handler struct { wallet walletclient.Client + store *repository.Store + userDB *sql.DB audit shared.OperationLogger } -func New(wallet walletclient.Client, audit shared.OperationLogger) *Handler { - return &Handler{wallet: wallet, audit: audit} +func New(wallet walletclient.Client, store *repository.Store, userDB *sql.DB, audit shared.OperationLogger) *Handler { + return &Handler{wallet: wallet, store: store, userDB: userDB, audit: audit} } func (h *Handler) ListResources(c *gin.Context) { @@ -334,6 +338,10 @@ func (h *Handler) ListResourceGrants(c *gin.Context) { for _, item := range resp.GetGrants() { items = append(items, grantFromProto(item)) } + if err := h.enrichGrantOperators(c.Request.Context(), items); err != nil { + response.ServerError(c, "获取资源赠送操作人失败") + return + } response.OK(c, response.Page{Items: items, Page: options.Page, PageSize: options.PageSize, Total: resp.GetTotal()}) } diff --git a/server/admin/internal/modules/resource/operator.go b/server/admin/internal/modules/resource/operator.go new file mode 100644 index 00000000..0623de29 --- /dev/null +++ b/server/admin/internal/modules/resource/operator.go @@ -0,0 +1,172 @@ +package resource + +import ( + "context" + "strings" + + "hyapp-admin-server/internal/appctx" + "hyapp-admin-server/internal/model" +) + +const ( + grantSourceAdmin = "admin" + grantSourceManagerCenter = "manager_center" +) + +type adminOperator struct { + UserID uint + Username string + Name string +} + +type managerOperator struct { + UserID int64 + DisplayUserID string + Username string + Avatar string +} + +func (h *Handler) enrichGrantOperators(ctx context.Context, grants []grantDTO) error { + // operator_user_id 在 wallet 发放事实里只保存稳定 ID;后台列表按来源补展示资料,避免把 admin 用户和 app 用户混成同一张表。 + adminIDs, managerIDs := collectGrantOperatorIDs(grants) + admins, err := h.queryAdminOperators(adminIDs) + if err != nil { + return err + } + managers, err := h.queryManagerOperators(ctx, managerIDs) + if err != nil { + return err + } + applyGrantOperators(grants, admins, managers) + return nil +} + +func (h *Handler) queryAdminOperators(ids []uint) (map[uint]adminOperator, error) { + out := make(map[uint]adminOperator, len(ids)) + if len(ids) == 0 || h.store == nil { + return out, nil + } + users, err := h.store.UsersByIDs(ids) + if err != nil { + return nil, err + } + for id, user := range users { + out[id] = adminOperatorFromModel(user) + } + return out, nil +} + +func (h *Handler) queryManagerOperators(ctx context.Context, ids []int64) (map[int64]managerOperator, error) { + out := make(map[int64]managerOperator, len(ids)) + if len(ids) == 0 || h.userDB == nil { + return out, nil + } + // 经理中心发放人是 app 用户,只读 user-service 的用户库投影;资源发放事实仍然以 wallet-service 返回为准。 + args := append([]any{appctx.FromContext(ctx)}, int64Args(ids)...) + rows, err := h.userDB.QueryContext(ctx, ` + SELECT user_id, + current_display_user_id, + COALESCE(username, ''), + COALESCE(avatar, '') + FROM users + WHERE app_code = ? AND user_id IN (`+placeholders(len(ids))+`) + `, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var operator managerOperator + if err := rows.Scan(&operator.UserID, &operator.DisplayUserID, &operator.Username, &operator.Avatar); err != nil { + return nil, err + } + out[operator.UserID] = operator + } + return out, rows.Err() +} + +func applyGrantOperators(grants []grantDTO, admins map[uint]adminOperator, managers map[int64]managerOperator) { + for index := range grants { + source := normalizeGrantSource(grants[index].GrantSource) + operatorID := grants[index].OperatorUserID + if operatorID <= 0 { + continue + } + // 即使资料缺失也返回 source + user_id,前端仍能展示可追溯的操作人线索。 + operator := &operatorDTO{ + Source: source, + UserID: operatorID, + } + switch source { + case grantSourceAdmin: + if admin, ok := admins[uint(operatorID)]; ok { + operator.Username = admin.Username + operator.Name = admin.Name + } + case grantSourceManagerCenter: + if manager, ok := managers[operatorID]; ok { + operator.DisplayUserID = manager.DisplayUserID + operator.Username = manager.Username + operator.Avatar = manager.Avatar + } + } + grants[index].Operator = operator + } +} + +func collectGrantOperatorIDs(grants []grantDTO) ([]uint, []int64) { + adminSet := make(map[uint]struct{}) + managerSet := make(map[int64]struct{}) + for _, grant := range grants { + if grant.OperatorUserID <= 0 { + continue + } + switch normalizeGrantSource(grant.GrantSource) { + case grantSourceAdmin: + adminSet[uint(grant.OperatorUserID)] = struct{}{} + case grantSourceManagerCenter: + managerSet[grant.OperatorUserID] = struct{}{} + } + } + adminIDs := make([]uint, 0, len(adminSet)) + for id := range adminSet { + adminIDs = append(adminIDs, id) + } + managerIDs := make([]int64, 0, len(managerSet)) + for id := range managerSet { + managerIDs = append(managerIDs, id) + } + return adminIDs, managerIDs +} + +func adminOperatorFromModel(user model.User) adminOperator { + return adminOperator{ + UserID: user.ID, + Username: user.Username, + Name: user.Name, + } +} + +func normalizeGrantSource(source string) string { + return strings.ToLower(strings.TrimSpace(source)) +} + +func placeholders(count int) string { + if count <= 0 { + return "" + } + items := make([]string, count) + for index := range items { + items[index] = "?" + } + return strings.Join(items, ",") +} + +func int64Args(values []int64) []any { + args := make([]any, 0, len(values)) + for _, value := range values { + args = append(args, value) + } + return args +} diff --git a/server/admin/internal/modules/resource/operator_test.go b/server/admin/internal/modules/resource/operator_test.go new file mode 100644 index 00000000..53632de0 --- /dev/null +++ b/server/admin/internal/modules/resource/operator_test.go @@ -0,0 +1,23 @@ +package resource + +import "testing" + +func TestApplyGrantOperatorsUsesSourceSpecificProfiles(t *testing.T) { + grants := []grantDTO{ + {GrantID: "grant-admin", GrantSource: "admin", OperatorUserID: 7}, + {GrantID: "grant-manager", GrantSource: "manager_center", OperatorUserID: 9001}, + } + + applyGrantOperators(grants, map[uint]adminOperator{ + 7: {UserID: 7, Username: "admin", Name: "后台管理员"}, + }, map[int64]managerOperator{ + 9001: {UserID: 9001, DisplayUserID: "10086", Username: "经理 A", Avatar: "https://cdn.example/avatar.png"}, + }) + + if grants[0].Operator == nil || grants[0].Operator.Source != "admin" || grants[0].Operator.Name != "后台管理员" || grants[0].Operator.Username != "admin" { + t.Fatalf("admin operator mismatch: %+v", grants[0].Operator) + } + if grants[1].Operator == nil || grants[1].Operator.Source != "manager_center" || grants[1].Operator.DisplayUserID != "10086" || grants[1].Operator.Avatar == "" || grants[1].Operator.Username != "经理 A" { + t.Fatalf("manager operator mismatch: %+v", grants[1].Operator) + } +} diff --git a/server/admin/internal/modules/resource/request.go b/server/admin/internal/modules/resource/request.go index b01138b4..5847b981 100644 --- a/server/admin/internal/modules/resource/request.go +++ b/server/admin/internal/modules/resource/request.go @@ -256,7 +256,7 @@ func resourceGrantStrategy(resourceType string) string { switch resourceType { case "coin": return "wallet_credit" - case "avatar_frame", "vehicle", "chat_bubble": + case "avatar_frame", "profile_card", "vehicle", "chat_bubble": return "extend_expiry" case "badge": return "set_active_flag" diff --git a/server/admin/internal/modules/roomadmin/handler.go b/server/admin/internal/modules/roomadmin/handler.go index b1b76ba0..a0a8147d 100644 --- a/server/admin/internal/modules/roomadmin/handler.go +++ b/server/admin/internal/modules/roomadmin/handler.go @@ -93,10 +93,12 @@ func (h *Handler) DeleteRoom(c *gin.Context) { func parseListQuery(c *gin.Context) (listQuery, bool) { options := shared.ListOptions(c) query := listQuery{ - Page: options.Page, - PageSize: options.PageSize, - Keyword: options.Keyword, - Status: options.Status, + Page: options.Page, + PageSize: options.PageSize, + Keyword: options.Keyword, + Status: options.Status, + SortBy: firstQueryValue(c, "sortBy", "sort_by"), + SortDirection: firstQueryValue(c, "sortDirection", "sort_direction", "order"), } regionID, ok := parseOptionalInt64Query(c, "regionId", "region_id") if !ok { @@ -106,6 +108,15 @@ func parseListQuery(c *gin.Context) (listQuery, bool) { return normalizeListQuery(query), true } +func firstQueryValue(c *gin.Context, names ...string) string { + for _, name := range names { + if value := strings.TrimSpace(c.Query(name)); value != "" { + return value + } + } + return "" +} + func parseOptionalInt64Query(c *gin.Context, primary string, fallback string) (int64, bool) { raw := strings.TrimSpace(c.Query(primary)) if raw == "" { diff --git a/server/admin/internal/modules/roomadmin/request.go b/server/admin/internal/modules/roomadmin/request.go index e714ef80..67ad51dc 100644 --- a/server/admin/internal/modules/roomadmin/request.go +++ b/server/admin/internal/modules/roomadmin/request.go @@ -1,11 +1,13 @@ package roomadmin type listQuery struct { - Page int - PageSize int - Keyword string - Status string - RegionID int64 + Page int + PageSize int + Keyword string + Status string + RegionID int64 + SortBy string + SortDirection string } type updateRoomRequest struct { diff --git a/server/admin/internal/modules/roomadmin/service.go b/server/admin/internal/modules/roomadmin/service.go index 1e6a4872..52c0f6bc 100644 --- a/server/admin/internal/modules/roomadmin/service.go +++ b/server/admin/internal/modules/roomadmin/service.go @@ -35,7 +35,6 @@ type Room struct { CoverURL string `json:"coverUrl"` CreatedAtMs int64 `json:"createdAtMs"` Heat int64 `json:"heat"` - HostUserID string `json:"hostUserId"` Mode string `json:"mode"` OccupiedSeatCount int32 `json:"occupiedSeatCount"` OnlineCount int32 `json:"onlineCount"` @@ -43,6 +42,7 @@ type Room struct { OwnerUserID string `json:"ownerUserId"` RegionName string `json:"regionName"` RoomID string `json:"roomId"` + RoomContribution int64 `json:"roomContribution"` SeatCount int32 `json:"seatCount"` SortScore int64 `json:"sortScore"` Status string `json:"status"` @@ -76,8 +76,8 @@ func (s *Service) ListRooms(ctx context.Context, query listQuery) ([]Room, int64 } if query.Keyword != "" { like := "%" + query.Keyword + "%" - whereSQL += " AND (rle.room_id LIKE ? OR rle.title LIKE ? OR CAST(rle.owner_user_id AS CHAR) LIKE ? OR CAST(rle.host_user_id AS CHAR) LIKE ?)" - args = append(args, like, like, like, like) + whereSQL += " AND (rle.room_id LIKE ? OR rle.title LIKE ? OR CAST(rle.owner_user_id AS CHAR) LIKE ?)" + args = append(args, like, like, like) } total, err := countRows(ctx, s.db, whereSQL, args...) if err != nil { @@ -87,7 +87,6 @@ func (s *Service) ListRooms(ctx context.Context, query listQuery) ([]Room, int64 SELECT rle.room_id, rle.visible_region_id, rle.owner_user_id, - rle.host_user_id, rle.title, rle.cover_url, rle.mode, @@ -100,9 +99,9 @@ func (s *Service) ListRooms(ctx context.Context, query listQuery) ([]Room, int64 rle.created_at_ms, rle.updated_at_ms %s - ORDER BY rle.created_at_ms DESC, rle.room_id DESC + ORDER BY %s LIMIT ? OFFSET ? - `, whereSQL), append(args, query.PageSize, offset(query.Page, query.PageSize))...) + `, whereSQL, roomListOrderBy(query)), append(args, query.PageSize, offset(query.Page, query.PageSize))...) if err != nil { return nil, 0, err } @@ -134,7 +133,6 @@ func (s *Service) GetRoom(ctx context.Context, roomID string) (Room, error) { SELECT room_id, visible_region_id, owner_user_id, - host_user_id, title, cover_url, mode, @@ -389,12 +387,10 @@ type roomScanner interface { func scanRoom(row roomScanner) (Room, error) { var item Room var ownerUserID int64 - var hostUserID int64 err := row.Scan( &item.RoomID, &item.VisibleRegionID, &ownerUserID, - &hostUserID, &item.Title, &item.CoverURL, &item.Mode, @@ -408,8 +404,8 @@ func scanRoom(row roomScanner) (Room, error) { &item.UpdatedAtMs, ) item.OwnerUserID = strconv.FormatInt(ownerUserID, 10) - item.HostUserID = strconv.FormatInt(hostUserID, 10) item.Owner = RoomOwner{UserID: item.OwnerUserID} + item.RoomContribution = item.Heat if item.Status != "active" { item.Status = "closed" } @@ -431,9 +427,42 @@ func normalizeListQuery(query listQuery) listQuery { if status, ok := normalizeRoomStatus(query.Status); ok { query.Status = status } + query.SortBy = normalizeRoomListSortBy(query.SortBy) + query.SortDirection = normalizeRoomListSortDirection(query.SortDirection) return query } +func roomListOrderBy(query listQuery) string { + // ORDER BY 字段只能来自 normalizeRoomListSortBy 的白名单,避免把 HTTP 查询值拼进 SQL。 + if query.SortBy == "room_contribution" { + if query.SortDirection == "asc" { + return "rle.heat ASC, rle.created_at_ms DESC, rle.room_id DESC" + } + return "rle.heat DESC, rle.created_at_ms DESC, rle.room_id DESC" + } + return "rle.created_at_ms DESC, rle.room_id DESC" +} + +func normalizeRoomListSortBy(sortBy string) string { + switch strings.ToLower(strings.TrimSpace(sortBy)) { + case "", "created_at", "createdat": + return "" + case "room_contribution", "roomcontribution", "contribution", "heat": + return "room_contribution" + default: + return "" + } +} + +func normalizeRoomListSortDirection(direction string) string { + switch strings.ToLower(strings.TrimSpace(direction)) { + case "asc", "ascending": + return "asc" + default: + return "desc" + } +} + func normalizeRoomStatus(status string) (string, bool) { switch strings.ToLower(strings.TrimSpace(status)) { case "": diff --git a/server/admin/internal/modules/roomadmin/service_test.go b/server/admin/internal/modules/roomadmin/service_test.go new file mode 100644 index 00000000..7e1364e3 --- /dev/null +++ b/server/admin/internal/modules/roomadmin/service_test.go @@ -0,0 +1,41 @@ +package roomadmin + +import "testing" + +func TestNormalizeRoomListSortKeepsOnlyContributionSort(t *testing.T) { + tests := []struct { + name string + query listQuery + wantOrder string + }{ + { + name: "default", + query: listQuery{}, + wantOrder: "rle.created_at_ms DESC, rle.room_id DESC", + }, + { + name: "contribution_desc", + query: listQuery{SortBy: "room_contribution", SortDirection: "desc"}, + wantOrder: "rle.heat DESC, rle.created_at_ms DESC, rle.room_id DESC", + }, + { + name: "contribution_asc", + query: listQuery{SortBy: "heat", SortDirection: "asc"}, + wantOrder: "rle.heat ASC, rle.created_at_ms DESC, rle.room_id DESC", + }, + { + name: "unknown_falls_back", + query: listQuery{SortBy: "owner_user_id", SortDirection: "asc"}, + wantOrder: "rle.created_at_ms DESC, rle.room_id DESC", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + query := normalizeListQuery(test.query) + if got := roomListOrderBy(query); got != test.wantOrder { + t.Fatalf("order by mismatch: got %q want %q", got, test.wantOrder) + } + }) + } +} diff --git a/server/admin/internal/repository/admin_user_repository.go b/server/admin/internal/repository/admin_user_repository.go index ea2519c7..1cf4818e 100644 --- a/server/admin/internal/repository/admin_user_repository.go +++ b/server/admin/internal/repository/admin_user_repository.go @@ -13,6 +13,21 @@ func (s *Store) ListUsers(options ListOptions) ([]model.User, int64, error) { return s.ListUsersWithAccess(options, DataAccess{All: true}) } +func (s *Store) UsersByIDs(ids []uint) (map[uint]model.User, error) { + usersByID := make(map[uint]model.User, len(ids)) + if len(ids) == 0 { + return usersByID, nil + } + var users []model.User + if err := s.db.Where("id IN ?", ids).Find(&users).Error; err != nil { + return nil, err + } + for _, user := range users { + usersByID[user.ID] = user + } + return usersByID, nil +} + func (s *Store) ListUsersWithAccess(options ListOptions, access DataAccess) ([]model.User, int64, error) { page, pageSize := normalizePage(options.Page, options.PageSize) query := s.db.Model(&model.User{}).Preload("Roles") diff --git a/server/admin/internal/repository/app_config_repository.go b/server/admin/internal/repository/app_config_repository.go index 1408aec9..738ddcbc 100644 --- a/server/admin/internal/repository/app_config_repository.go +++ b/server/admin/internal/repository/app_config_repository.go @@ -9,6 +9,12 @@ import ( "gorm.io/gorm/clause" ) +type AppVersionListOptions struct { + AppCode string + Platform string + Keyword string +} + func (s *Store) ListAppConfigs(group string) ([]model.AppConfig, error) { var items []model.AppConfig err := s.db.Where("`group` = ?", strings.TrimSpace(group)).Order("`key` ASC").Find(&items).Error @@ -38,3 +44,36 @@ func (s *Store) UpsertAppConfigs(items []model.AppConfig) error { DoUpdates: clause.AssignmentColumns([]string{"value", "description", "updated_at_ms"}), }).Create(&items).Error } + +func (s *Store) ListAppVersions(options AppVersionListOptions) ([]model.AppVersion, error) { + db := s.db.Where("app_code = ?", strings.TrimSpace(options.AppCode)) + if platform := strings.TrimSpace(options.Platform); platform != "" { + db = db.Where("platform = ?", platform) + } + if keyword := strings.TrimSpace(options.Keyword); keyword != "" { + like := "%" + keyword + "%" + db = db.Where("version LIKE ? OR download_url LIKE ? OR description LIKE ?", like, like, like) + } + + var items []model.AppVersion + err := db.Order("platform ASC, build_number DESC, id DESC").Find(&items).Error + return items, err +} + +func (s *Store) GetAppVersion(appCode string, id uint) (model.AppVersion, error) { + var item model.AppVersion + err := s.db.Where("app_code = ? AND id = ?", strings.TrimSpace(appCode), id).First(&item).Error + return item, err +} + +func (s *Store) CreateAppVersion(item *model.AppVersion) error { + return s.db.Create(item).Error +} + +func (s *Store) UpdateAppVersion(item *model.AppVersion) error { + return s.db.Save(item).Error +} + +func (s *Store) DeleteAppVersion(appCode string, id uint) error { + return s.db.Where("app_code = ? AND id = ?", strings.TrimSpace(appCode), id).Delete(&model.AppVersion{}).Error +} diff --git a/server/admin/internal/repository/repository.go b/server/admin/internal/repository/repository.go index d1ad4fba..70b20667 100644 --- a/server/admin/internal/repository/repository.go +++ b/server/admin/internal/repository/repository.go @@ -66,6 +66,7 @@ func (s *Store) AutoMigrate() error { &model.Menu{}, &model.AppConfig{}, &model.AppBanner{}, + &model.AppVersion{}, &model.RefreshToken{}, &model.LoginLog{}, &model.OperationLog{}, diff --git a/server/admin/internal/repository/seed.go b/server/admin/internal/repository/seed.go index efd9cc71..e7a95b78 100644 --- a/server/admin/internal/repository/seed.go +++ b/server/admin/internal/repository/seed.go @@ -27,6 +27,10 @@ var defaultPermissions = []model.Permission{ {Name: "房间配置更新", Code: "room-config:update", Kind: "button"}, {Name: "APP 配置查看", Code: "app-config:view", Kind: "menu"}, {Name: "APP 配置更新", Code: "app-config:update", Kind: "button"}, + {Name: "版本管理查看", Code: "app-version:view", Kind: "menu"}, + {Name: "版本管理创建", Code: "app-version:create", Kind: "button"}, + {Name: "版本管理更新", Code: "app-version:update", Kind: "button"}, + {Name: "版本管理删除", Code: "app-version:delete", Kind: "button"}, {Name: "资源查看", Code: "resource:view", Kind: "menu"}, {Name: "资源创建", Code: "resource:create", Kind: "button"}, {Name: "资源更新", Code: "resource:update", Kind: "button"}, @@ -58,7 +62,12 @@ var defaultPermissions = []model.Permission{ {Name: "币商创建", Code: "coin-seller:create", Kind: "button"}, {Name: "币商更新", Code: "coin-seller:update", Kind: "button"}, {Name: "币商进货", Code: "coin-seller:stock-credit", Kind: "button"}, + {Name: "金币流水查看", Code: "coin-ledger:view", Kind: "menu"}, {Name: "支付账单查看", Code: "payment-bill:view", Kind: "menu"}, + {Name: "内购配置查看", Code: "payment-product:view", Kind: "menu"}, + {Name: "内购配置创建", Code: "payment-product:create", Kind: "button"}, + {Name: "内购配置更新", Code: "payment-product:update", Kind: "button"}, + {Name: "内购配置删除", Code: "payment-product:delete", Kind: "button"}, {Name: "游戏查看", Code: "game:view", Kind: "menu"}, {Name: "游戏创建", Code: "game:create", Kind: "button"}, {Name: "游戏更新", Code: "game:update", Kind: "button"}, @@ -67,6 +76,8 @@ var defaultPermissions = []model.Permission{ {Name: "每日任务创建", Code: "daily-task:create", Kind: "button"}, {Name: "每日任务更新", Code: "daily-task:update", Kind: "button"}, {Name: "每日任务状态", Code: "daily-task:status", Kind: "button"}, + {Name: "注册奖励查看", Code: "registration-reward:view", Kind: "menu"}, + {Name: "注册奖励更新", Code: "registration-reward:update", Kind: "button"}, {Name: "角色查看", Code: "role:view", Kind: "menu"}, {Name: "角色创建", Code: "role:create", Kind: "button"}, {Name: "角色更新", Code: "role:update", Kind: "button"}, @@ -111,6 +122,7 @@ func (s *Store) seedMenus() error { appUsersID := uint(0) appConfigID := uint(0) resourceID := uint(0) + operationsID := uint(0) roomsID := uint(0) paymentID := uint(0) activityID := uint(0) @@ -124,10 +136,11 @@ func (s *Store) seedMenus() error { {Title: "房间管理", Code: "rooms", Path: "", Icon: "room", PermissionCode: "", Sort: 65, Visible: true}, {Title: "APP配置", Code: "app-config", Path: "", Icon: "settings", PermissionCode: "", Sort: 66, Visible: true}, {Title: "资源管理", Code: "resources", Path: "", Icon: "inventory", PermissionCode: "", Sort: 67, Visible: true}, - {Title: "支付管理", Code: "payment", Path: "", Icon: "wallet", PermissionCode: "", Sort: 68, Visible: true}, - {Title: "活动管理", Code: "activities", Path: "", Icon: "campaign", PermissionCode: "", Sort: 69, Visible: true}, - {Title: "游戏管理", Code: "games", Path: "", Icon: "sports_esports", PermissionCode: "", Sort: 70, Visible: true}, - {Title: "地区管理", Code: "geo", Path: "", Icon: "map", PermissionCode: "", Sort: 71, Visible: true}, + {Title: "运营管理", Code: "operations", Path: "", Icon: "operations", PermissionCode: "", Sort: 68, Visible: true}, + {Title: "支付管理", Code: "payment", Path: "", Icon: "wallet", PermissionCode: "", Sort: 69, Visible: true}, + {Title: "活动管理", Code: "activities", Path: "", Icon: "campaign", PermissionCode: "", Sort: 70, Visible: true}, + {Title: "游戏管理", Code: "games", Path: "", Icon: "sports_esports", PermissionCode: "", Sort: 71, Visible: true}, + {Title: "地区管理", Code: "geo", Path: "", Icon: "map", PermissionCode: "", Sort: 72, Visible: true}, {Title: "团队管理", Code: "host-org", Path: "", Icon: "network", PermissionCode: "", Sort: 80, Visible: true}, {Title: "任务中心", Code: "jobs", Path: "/jobs", Icon: "task", PermissionCode: "job:view", Sort: 90, Visible: true}, } @@ -154,6 +167,9 @@ func (s *Store) seedMenus() error { if syncedMenu.Code == "resources" { resourceID = syncedMenu.ID } + if syncedMenu.Code == "operations" { + operationsID = syncedMenu.ID + } if syncedMenu.Code == "rooms" { roomsID = syncedMenu.ID } @@ -175,25 +191,31 @@ func (s *Store) seedMenus() error { {ParentID: &systemID, Title: "登录日志", Code: "logs-login", Path: "/logs/login", Icon: "login", PermissionCode: "log:view", Sort: 34, Visible: true}, {ParentID: &systemID, Title: "操作日志", Code: "logs-operations", Path: "/logs/operations", Icon: "receipt", PermissionCode: "log:view", Sort: 35, Visible: true}, {ParentID: &appUsersID, Title: "用户列表", Code: "app-user-list", Path: "/app/users", Icon: "users", PermissionCode: "app-user:view", Sort: 60, Visible: true}, - {ParentID: &appUsersID, Title: "登录日志", Code: "app-user-login-logs", Path: "/app/users/login-logs", Icon: "login", PermissionCode: "app-user:view", Sort: 61, Visible: true}, + {ParentID: &appUsersID, Title: "封禁列表", Code: "app-user-bans", Path: "/app/users/bans", Icon: "block", PermissionCode: "app-user:view", Sort: 61, Visible: true}, + {ParentID: &appUsersID, Title: "登录日志", Code: "app-user-login-logs", Path: "/app/users/login-logs", Icon: "login", PermissionCode: "app-user:view", Sort: 62, Visible: true}, {ParentID: &roomsID, Title: "房间列表", Code: "room-list", Path: "/rooms", Icon: "room", PermissionCode: "room:view", Sort: 65, Visible: true}, {ParentID: &roomsID, Title: "房间配置", Code: "room-config", Path: "/rooms/config", Icon: "settings", PermissionCode: "room-config:view", Sort: 66, Visible: true}, {ParentID: &appConfigID, Title: "H5配置", Code: "app-config-h5", Path: "/app-config/h5", Icon: "settings", PermissionCode: "app-config:view", Sort: 66, Visible: true}, {ParentID: &appConfigID, Title: "BANNER配置", Code: "app-config-banners", Path: "/app-config/banners", Icon: "image", PermissionCode: "app-config:view", Sort: 67, Visible: true}, + {ParentID: &appConfigID, Title: "内购配置", Code: "payment-recharge-products", Path: "/app-config/recharge-products", Icon: "wallet", PermissionCode: "payment-product:view", Sort: 68, Visible: true}, + {ParentID: &appConfigID, Title: "版本管理", Code: "app-config-versions", Path: "/app-config/versions", Icon: "settings", PermissionCode: "app-version:view", Sort: 69, Visible: true}, {ParentID: &resourceID, Title: "资源列表", Code: "resource-list", Path: "/resources", Icon: "inventory", PermissionCode: "resource:view", Sort: 67, Visible: true}, {ParentID: &resourceID, Title: "资源组列表", Code: "resource-group-list", Path: "/resource-groups", Icon: "category", PermissionCode: "resource-group:view", Sort: 68, Visible: true}, {ParentID: &resourceID, Title: "礼物列表", Code: "gift-list", Path: "/gifts", Icon: "gift", PermissionCode: "gift:view", Sort: 69, Visible: true}, {ParentID: &resourceID, Title: "资源赠送", Code: "resource-grant-list", Path: "/resource-grants", Icon: "send", PermissionCode: "resource-grant:view", Sort: 70, Visible: true}, + {ParentID: &operationsID, Title: "金币流水", Code: "operation-coin-ledger", Path: "/operations/coin-ledger", Icon: "receipt", PermissionCode: "coin-ledger:view", Sort: 68, Visible: true}, {ParentID: &paymentID, Title: "账单列表", Code: "payment-bill-list", Path: "/payment/bills", Icon: "receipt", PermissionCode: "payment-bill:view", Sort: 68, 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: &gameID, Title: "游戏列表", Code: "game-list", Path: "/games", Icon: "sports_esports", PermissionCode: "game:view", Sort: 70, Visible: true}, {ParentID: &geoID, Title: "国家管理", Code: "host-org-countries", Path: "/host/countries", Icon: "public", PermissionCode: "country:view", Sort: 70, Visible: true}, {ParentID: &geoID, Title: "区域管理", Code: "host-org-regions", Path: "/host/regions", Icon: "map", PermissionCode: "region:view", Sort: 71, Visible: true}, - {ParentID: &hostOrgID, Title: "Agency 管理", Code: "host-org-agencies", Path: "/host/agencies", Icon: "apartment", PermissionCode: "agency:view", Sort: 80, Visible: true}, - {ParentID: &hostOrgID, Title: "BD Leader 管理", Code: "host-org-bd-leaders", Path: "/host/bd-leaders", Icon: "shield", PermissionCode: "bd:view", Sort: 81, Visible: true}, - {ParentID: &hostOrgID, Title: "BD 管理", Code: "host-org-bds", Path: "/host/bds", Icon: "team", PermissionCode: "bd:view", Sort: 82, Visible: true}, - {ParentID: &hostOrgID, Title: "主播管理", Code: "host-org-hosts", Path: "/host/hosts", Icon: "users", PermissionCode: "host:view", Sort: 83, Visible: true}, - {ParentID: &hostOrgID, Title: "币商管理", Code: "host-org-coin-sellers", Path: "/host/coin-sellers", Icon: "wallet", PermissionCode: "coin-seller:view", Sort: 84, Visible: true}, + {ParentID: &hostOrgID, Title: "经理列表", Code: "host-org-managers", Path: "/host/managers", Icon: "users", PermissionCode: "agency:view", Sort: 80, Visible: true}, + {ParentID: &hostOrgID, Title: "Agency 列表", Code: "host-org-agencies", Path: "/host/agencies", Icon: "apartment", PermissionCode: "agency:view", Sort: 81, Visible: true}, + {ParentID: &hostOrgID, Title: "BD Leader 列表", Code: "host-org-bd-leaders", Path: "/host/bd-leaders", Icon: "shield", PermissionCode: "bd:view", Sort: 82, Visible: true}, + {ParentID: &hostOrgID, Title: "BD 列表", Code: "host-org-bds", Path: "/host/bds", Icon: "team", PermissionCode: "bd:view", Sort: 83, Visible: true}, + {ParentID: &hostOrgID, Title: "主播列表", Code: "host-org-hosts", Path: "/host/hosts", Icon: "users", PermissionCode: "host:view", Sort: 84, Visible: true}, + {ParentID: &hostOrgID, Title: "币商列表", Code: "host-org-coin-sellers", Path: "/host/coin-sellers", Icon: "wallet", PermissionCode: "coin-seller:view", Sort: 85, Visible: true}, } for _, menu := range children { if _, err := s.syncDefaultMenu(s.db, menu); err != nil { @@ -421,6 +443,7 @@ func defaultRolePermissionCodes(code string) []string { "app-user:view", "app-user:update", "app-user:status", "app-user:password", "room:view", "room:update", "room:delete", "room-config:view", "room-config:update", "app-config:view", "app-config:update", + "app-version:view", "app-version:create", "app-version:update", "app-version:delete", "resource:view", "resource:create", "resource:update", "resource-group:view", "resource-group:create", "resource-group:update", "resource-grant:view", "resource-grant:create", @@ -431,7 +454,7 @@ func defaultRolePermissionCodes(code string) []string { "agency:view", "agency:create", "agency:status", "bd:view", "bd:create", "bd:update", "coin-seller:view", "coin-seller:create", "coin-seller:update", "coin-seller:stock-credit", - "payment-bill:view", + "coin-ledger:view", "payment-bill:view", "payment-product:view", "payment-product:create", "payment-product:update", "payment-product:delete", "game:view", "game:create", "game:update", "game:status", "daily-task:view", "daily-task:create", "daily-task:update", "daily-task:status", "log:view", @@ -440,7 +463,7 @@ func defaultRolePermissionCodes(code string) []string { "upload:create", } case "auditor": - return []string{"overview:view", "log:view", "user:view", "app-user:view", "room:view", "room-config:view", "app-config:view", "resource:view", "resource-group:view", "resource-grant:view", "gift:view", "payment-bill:view", "game:view", "daily-task:view", "role:view", "permission:view", "job:view"} + return []string{"overview:view", "log:view", "user:view", "app-user:view", "room:view", "room-config:view", "app-config:view", "app-version:view", "resource:view", "resource-group:view", "resource-grant:view", "gift:view", "coin-ledger:view", "payment-bill:view", "payment-product:view", "game:view", "daily-task:view", "role:view", "permission:view", "job:view"} case "readonly": return []string{ "overview:view", @@ -449,6 +472,7 @@ func defaultRolePermissionCodes(code string) []string { "room:view", "room-config:view", "app-config:view", + "app-version:view", "resource:view", "resource-group:view", "resource-grant:view", @@ -459,7 +483,9 @@ func defaultRolePermissionCodes(code string) []string { "agency:view", "bd:view", "coin-seller:view", + "coin-ledger:view", "payment-bill:view", + "payment-product:view", "game:view", "daily-task:view", "role:view", @@ -481,6 +507,7 @@ func defaultRolePermissionMigrationCodes(code string) []string { "app-user:update", "app-user:status", "app-user:password", "room:view", "room:update", "room:delete", "room-config:view", "room-config:update", "app-config:view", "app-config:update", + "app-version:view", "app-version:create", "app-version:update", "app-version:delete", "resource:view", "resource:create", "resource:update", "resource-group:view", "resource-group:create", "resource-group:update", "resource-grant:view", "resource-grant:create", @@ -489,12 +516,12 @@ func defaultRolePermissionMigrationCodes(code string) []string { "country:view", "country:create", "country:update", "country:status", "region:view", "region:create", "region:update", "region:status", "coin-seller:view", "coin-seller:create", "coin-seller:update", "coin-seller:stock-credit", - "payment-bill:view", + "coin-ledger:view", "payment-bill:view", "payment-product:view", "payment-product:create", "payment-product:update", "payment-product:delete", "game:view", "game:create", "game:update", "game:status", "daily-task:view", "daily-task:create", "daily-task:update", "daily-task:status", } case "auditor", "readonly": - return []string{"room:view", "room-config:view", "app-config:view", "resource:view", "resource-group:view", "resource-grant:view", "gift:view", "coin-seller:view", "payment-bill:view", "game:view", "daily-task:view"} + return []string{"room:view", "room-config:view", "app-config:view", "app-version:view", "resource:view", "resource-group:view", "resource-grant:view", "gift:view", "coin-seller:view", "coin-ledger:view", "payment-bill:view", "payment-product:view", "game:view", "daily-task:view"} default: return nil } diff --git a/server/admin/internal/router/router.go b/server/admin/internal/router/router.go index be193d4b..1e0ef2d2 100644 --- a/server/admin/internal/router/router.go +++ b/server/admin/internal/router/router.go @@ -9,6 +9,7 @@ import ( "hyapp-admin-server/internal/modules/appuser" "hyapp-admin-server/internal/modules/audit" authroutes "hyapp-admin-server/internal/modules/auth" + "hyapp-admin-server/internal/modules/coinledger" "hyapp-admin-server/internal/modules/countryregion" "hyapp-admin-server/internal/modules/dailytask" "hyapp-admin-server/internal/modules/dashboard" @@ -20,6 +21,7 @@ import ( "hyapp-admin-server/internal/modules/notification" "hyapp-admin-server/internal/modules/payment" "hyapp-admin-server/internal/modules/rbac" + "hyapp-admin-server/internal/modules/registrationreward" resourcemodule "hyapp-admin-server/internal/modules/resource" "hyapp-admin-server/internal/modules/roomadmin" "hyapp-admin-server/internal/modules/search" @@ -31,27 +33,29 @@ import ( ) type Handlers struct { - AdminUser *adminuser.Handler - AppConfig *appconfig.Handler - AppRegistry *appregistry.Handler - AppUser *appuser.Handler - Audit *audit.Handler - Auth *authroutes.Handler - CountryRegion *countryregion.Handler - DailyTask *dailytask.Handler - Dashboard *dashboard.Handler - Game *gamemanagement.Handler - Health *health.Handler - HostOrg *hostorg.Handler - Job *job.Handler - Menu *menu.Handler - Notification *notification.Handler - Payment *payment.Handler - RBAC *rbac.Handler - Resource *resourcemodule.Handler - RoomAdmin *roomadmin.Handler - Search *search.Handler - Upload *upload.Handler + AdminUser *adminuser.Handler + AppConfig *appconfig.Handler + AppRegistry *appregistry.Handler + AppUser *appuser.Handler + Audit *audit.Handler + Auth *authroutes.Handler + CoinLedger *coinledger.Handler + CountryRegion *countryregion.Handler + DailyTask *dailytask.Handler + Dashboard *dashboard.Handler + Game *gamemanagement.Handler + Health *health.Handler + HostOrg *hostorg.Handler + Job *job.Handler + Menu *menu.Handler + Notification *notification.Handler + Payment *payment.Handler + RBAC *rbac.Handler + RegistrationReward *registrationreward.Handler + Resource *resourcemodule.Handler + RoomAdmin *roomadmin.Handler + Search *search.Handler + Upload *upload.Handler } func New(cfg config.Config, auth *service.AuthService, h Handlers) *gin.Engine { @@ -66,6 +70,7 @@ func New(cfg config.Config, auth *service.AuthService, h Handlers) *gin.Engine { protected.Use(middleware.AuthRequired(auth), middleware.Audit(h.Audit)) authroutes.RegisterRoutes(api, protected, h.Auth) + coinledger.RegisterRoutes(protected, h.CoinLedger) menu.RegisterRoutes(protected, h.Menu) rbac.RegisterRoutes(protected, h.RBAC) resourcemodule.RegisterRoutes(protected, h.Resource) @@ -75,6 +80,7 @@ func New(cfg config.Config, auth *service.AuthService, h Handlers) *gin.Engine { appconfig.RegisterRoutes(protected, h.AppConfig) countryregion.RegisterRoutes(protected, h.CountryRegion) dailytask.RegisterRoutes(protected, h.DailyTask) + registrationreward.RegisterRoutes(protected, h.RegistrationReward) gamemanagement.RegisterRoutes(protected, h.Game) roomadmin.RegisterRoutes(protected, h.RoomAdmin) dashboard.RegisterRoutes(protected, h.Dashboard) diff --git a/server/admin/migrations/007_admin_app_versions.sql b/server/admin/migrations/007_admin_app_versions.sql new file mode 100644 index 00000000..837bbf3a --- /dev/null +++ b/server/admin/migrations/007_admin_app_versions.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS admin_app_versions ( + id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + platform VARCHAR(24) NOT NULL, + version VARCHAR(40) NOT NULL, + build_number BIGINT NOT NULL, + force_update BOOLEAN NOT NULL DEFAULT FALSE, + download_url VARCHAR(2048) NOT NULL, + description TEXT NULL, + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + UNIQUE KEY uk_admin_app_versions_build (app_code, platform, build_number), + INDEX idx_admin_app_versions_latest (app_code, platform, build_number, id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/services/activity-service/deploy/mysql/initdb/001_activity_service.sql b/services/activity-service/deploy/mysql/initdb/001_activity_service.sql index 43503496..712979ae 100644 --- a/services/activity-service/deploy/mysql/initdb/001_activity_service.sql +++ b/services/activity-service/deploy/mysql/initdb/001_activity_service.sql @@ -155,6 +155,54 @@ CREATE TABLE IF NOT EXISTS task_reward_claims ( KEY idx_task_reward_claim_status (app_code, status, updated_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE IF NOT EXISTS registration_reward_configs ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + enabled TINYINT(1) NOT NULL DEFAULT 0, + reward_type VARCHAR(32) NOT NULL DEFAULT 'coin', + coin_amount BIGINT NOT NULL DEFAULT 0, + resource_group_id BIGINT NOT NULL DEFAULT 0, + daily_limit BIGINT NOT NULL DEFAULT 0, + updated_by_admin_id BIGINT NOT NULL DEFAULT 0, + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS registration_reward_claims ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + claim_id VARCHAR(96) NOT NULL, + command_id VARCHAR(128) NOT NULL, + user_id BIGINT NOT NULL, + reward_day VARCHAR(32) NOT NULL, + reward_type VARCHAR(32) NOT NULL, + coin_amount BIGINT NOT NULL DEFAULT 0, + resource_group_id BIGINT NOT NULL DEFAULT 0, + status VARCHAR(32) NOT NULL, + wallet_command_id VARCHAR(128) NOT NULL, + wallet_transaction_id VARCHAR(96) NOT NULL DEFAULT '', + resource_grant_id VARCHAR(96) NOT NULL DEFAULT '', + failure_reason VARCHAR(255) NOT NULL DEFAULT '', + claimed_at_ms BIGINT NOT NULL DEFAULT 0, + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, claim_id), + UNIQUE KEY uk_registration_reward_command (app_code, command_id), + UNIQUE KEY uk_registration_reward_user_once (app_code, user_id), + KEY idx_registration_reward_list (app_code, created_at_ms, claim_id), + KEY idx_registration_reward_status (app_code, status, updated_at_ms), + KEY idx_registration_reward_day (app_code, reward_day, status) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS registration_reward_daily_counters ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + reward_day VARCHAR(32) NOT NULL, + reserved_count BIGINT NOT NULL DEFAULT 0, + granted_count BIGINT NOT NULL DEFAULT 0, + failed_count BIGINT NOT NULL DEFAULT 0, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, reward_day) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CREATE TABLE IF NOT EXISTS message_templates ( app_code VARCHAR(32) NOT NULL, template_id VARCHAR(96) NOT NULL, diff --git a/services/activity-service/internal/app/app.go b/services/activity-service/internal/app/app.go index 65bedd02..61d668d8 100644 --- a/services/activity-service/internal/app/app.go +++ b/services/activity-service/internal/app/app.go @@ -22,6 +22,7 @@ import ( activityservice "hyapp/services/activity-service/internal/service/activity" broadcastservice "hyapp/services/activity-service/internal/service/broadcast" messageservice "hyapp/services/activity-service/internal/service/message" + registrationrewardservice "hyapp/services/activity-service/internal/service/registrationreward" taskservice "hyapp/services/activity-service/internal/service/task" mysqlstorage "hyapp/services/activity-service/internal/storage/mysql" grpcserver "hyapp/services/activity-service/internal/transport/grpc" @@ -78,6 +79,7 @@ func New(cfg config.Config) (*App, error) { svc := activityservice.New(activityservice.Config{NodeID: cfg.NodeID}, repository) messageSvc := messageservice.New(messageservice.Config{NodeID: cfg.NodeID}, repository, messageservice.WithTargetSource(client.NewGRPCUserTargetSource(userConn))) taskSvc := taskservice.New(repository, walletv1.NewWalletServiceClient(walletConn)) + registrationRewardSvc := registrationrewardservice.New(repository, walletv1.NewWalletServiceClient(walletConn)) var broadcastPublisher broadcastservice.Publisher if cfg.TencentIM.Enabled { tencentClient, err := tencentim.NewRESTClient(cfg.TencentIM.RESTConfig()) @@ -111,6 +113,8 @@ func New(cfg config.Config) (*App, error) { activityv1.RegisterActivityCronServiceServer(server, grpcserver.NewCronServer(messageSvc)) activityv1.RegisterTaskServiceServer(server, grpcserver.NewTaskServer(taskSvc)) activityv1.RegisterAdminTaskServiceServer(server, grpcserver.NewAdminTaskServer(taskSvc)) + activityv1.RegisterRegistrationRewardServiceServer(server, grpcserver.NewRegistrationRewardServer(registrationRewardSvc)) + activityv1.RegisterAdminRegistrationRewardServiceServer(server, grpcserver.NewAdminRegistrationRewardServer(registrationRewardSvc)) broadcastServer := grpcserver.NewBroadcastServer(broadcastSvc) activityv1.RegisterBroadcastServiceServer(server, broadcastServer) activityv1.RegisterRoomEventConsumerServiceServer(server, broadcastServer) diff --git a/services/activity-service/internal/domain/registrationreward/registration_reward.go b/services/activity-service/internal/domain/registrationreward/registration_reward.go new file mode 100644 index 00000000..b9ff9393 --- /dev/null +++ b/services/activity-service/internal/domain/registrationreward/registration_reward.go @@ -0,0 +1,86 @@ +package registrationreward + +const ( + RewardTypeCoin = "coin" + RewardTypeResourceGroup = "resource_group" + + StatusPending = "pending" + StatusGranted = "granted" + StatusFailed = "failed" + + ReasonEligible = "eligible" + ReasonNotConfigured = "not_configured" + ReasonDisabled = "disabled" + ReasonInvalidConfig = "invalid_config" + ReasonAlreadyClaimed = "already_claimed" + ReasonDailyLimitReached = "daily_limit_reached" +) + +// Config 是注册奖励配置的 owner-side 快照;daily_limit=0 表达 UTC 当天不限份数。 +type Config struct { + AppCode string + Enabled bool + RewardType string + CoinAmount int64 + ResourceGroupID int64 + DailyLimit int64 + UpdatedByAdminID int64 + CreatedAtMS int64 + UpdatedAtMS int64 +} + +// Claim 是注册奖励领取事实;每个 app_code + user_id 只允许一个有效事实。 +type Claim struct { + ClaimID string + CommandID string + UserID int64 + RewardDay string + RewardType string + CoinAmount int64 + ResourceGroupID int64 + Status string + WalletCommandID string + WalletTransactionID string + ResourceGrantID string + FailureReason string + ClaimedAtMS int64 + CreatedAtMS int64 + UpdatedAtMS int64 +} + +// Eligibility 是 App 查询使用的稳定结果;reason 让客户端能区分未配置、关闭、已领取和当日超额。 +type Eligibility struct { + CanReceive bool + Reason string + Enabled bool + RewardType string + CoinAmount int64 + ResourceGroupID int64 + DailyLimit int64 + DailyUsed int64 + DailyRemaining int64 + RewardDay string + ServerTimeMS int64 +} + +// IssueCommand 是 user-service 注册完成后传入的幂等命令。 +type IssueCommand struct { + UserID int64 + CommandID string +} + +// PrepareResult 表达 activity 事务是否已经成功预留每日份数并创建/复用 pending claim。 +type PrepareResult struct { + Claim Claim + Prepared bool + AlreadyGranted bool + Reason string +} + +// ClaimQuery 是后台领取记录分页查询条件;用户搜索由 admin-server 先解析成 user_id。 +type ClaimQuery struct { + Status string + UserID int64 + Page int32 + PageSize int32 +} diff --git a/services/activity-service/internal/service/registrationreward/service.go b/services/activity-service/internal/service/registrationreward/service.go new file mode 100644 index 00000000..e4d0a256 --- /dev/null +++ b/services/activity-service/internal/service/registrationreward/service.go @@ -0,0 +1,232 @@ +package registrationreward + +import ( + "context" + "strings" + "time" + + "google.golang.org/grpc" + walletv1 "hyapp.local/api/proto/wallet/v1" + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + domain "hyapp/services/activity-service/internal/domain/registrationreward" +) + +const ( + registrationRewardTaskID = "registration_reward" + registrationRewardReason = "registration_reward" +) + +// Repository 是注册奖励的持久化边界;配置、领取事实和每日份数必须同属 activity-service。 +type Repository interface { + GetRegistrationRewardConfig(ctx context.Context) (domain.Config, bool, error) + UpdateRegistrationRewardConfig(ctx context.Context, config domain.Config, nowMS int64) (domain.Config, error) + GetRegistrationRewardEligibility(ctx context.Context, userID int64, rewardDay string, nowMS int64) (domain.Eligibility, error) + PrepareRegistrationRewardClaim(ctx context.Context, command domain.IssueCommand, rewardDay string, nowMS int64) (domain.PrepareResult, error) + MarkRegistrationRewardClaimGranted(ctx context.Context, claimID string, walletTransactionID string, resourceGrantID string, grantedAtMS int64) (domain.Claim, error) + MarkRegistrationRewardClaimFailed(ctx context.Context, claimID string, failureReason string, nowMS int64) error + ListRegistrationRewardClaims(ctx context.Context, query domain.ClaimQuery) ([]domain.Claim, int64, error) +} + +// WalletClient 是注册奖励发放的唯一外部副作用;金币和资源组都依赖 wallet-service 幂等命令。 +type WalletClient interface { + CreditTaskReward(ctx context.Context, req *walletv1.CreditTaskRewardRequest, opts ...grpc.CallOption) (*walletv1.CreditTaskRewardResponse, error) + GrantResourceGroup(ctx context.Context, req *walletv1.GrantResourceGroupRequest, opts ...grpc.CallOption) (*walletv1.ResourceGrantResponse, error) +} + +// Service 承载注册奖励配置、资格判断和注册后自动发放用例。 +type Service struct { + repository Repository + wallet WalletClient + now func() time.Time +} + +func New(repository Repository, wallet WalletClient) *Service { + return &Service{repository: repository, wallet: wallet, now: time.Now} +} + +func (s *Service) SetClock(now func() time.Time) { + if now != nil { + s.now = now + } +} + +// GetConfig 返回当前配置;未配置时返回 disabled 默认值,避免后台首屏把 404 当异常。 +func (s *Service) GetConfig(ctx context.Context) (domain.Config, error) { + if err := s.requireRepository(); err != nil { + return domain.Config{}, err + } + config, exists, err := s.repository.GetRegistrationRewardConfig(ctx) + if err != nil { + return domain.Config{}, err + } + if !exists { + return domain.Config{AppCode: appcode.FromContext(ctx), RewardType: domain.RewardTypeCoin}, nil + } + return config, nil +} + +// UpdateConfig 更新后台配置;关闭状态也校验奖励参数,避免下次打开时发放一个无效配置。 +func (s *Service) UpdateConfig(ctx context.Context, config domain.Config) (domain.Config, error) { + if err := s.requireRepository(); err != nil { + return domain.Config{}, err + } + config.AppCode = appcode.FromContext(ctx) + config.RewardType = normalizeRewardType(config.RewardType) + if err := validateConfig(config); err != nil { + return domain.Config{}, err + } + return s.repository.UpdateRegistrationRewardConfig(ctx, config, s.now().UnixMilli()) +} + +// GetEligibility 判断“没领过且今天还有份数”;日维度严格使用 UTC,不能读取服务器本地时区。 +func (s *Service) GetEligibility(ctx context.Context, userID int64) (domain.Eligibility, error) { + if err := s.requireRepository(); err != nil { + return domain.Eligibility{}, err + } + if userID <= 0 { + return domain.Eligibility{}, xerr.New(xerr.InvalidArgument, "user_id is required") + } + now := s.now() + return s.repository.GetRegistrationRewardEligibility(ctx, userID, rewardDay(now), now.UnixMilli()) +} + +// IssueRegistrationReward 在用户注册事务提交后调用;不可领取不是错误,钱包失败才返回错误以便调用方打日志。 +func (s *Service) IssueRegistrationReward(ctx context.Context, command domain.IssueCommand) (domain.Claim, domain.Eligibility, bool, error) { + if err := s.requireRepository(); err != nil { + return domain.Claim{}, domain.Eligibility{}, false, err + } + command.CommandID = strings.TrimSpace(command.CommandID) + if command.UserID <= 0 || command.CommandID == "" { + return domain.Claim{}, domain.Eligibility{}, false, xerr.New(xerr.InvalidArgument, "registration reward command is incomplete") + } + now := s.now() + day := rewardDay(now) + prepared, err := s.repository.PrepareRegistrationRewardClaim(ctx, command, day, now.UnixMilli()) + if err != nil { + return domain.Claim{}, domain.Eligibility{}, false, err + } + if !prepared.Prepared { + eligibility, eligibilityErr := s.repository.GetRegistrationRewardEligibility(ctx, command.UserID, day, s.now().UnixMilli()) + if eligibilityErr != nil { + return domain.Claim{}, domain.Eligibility{}, false, eligibilityErr + } + if prepared.AlreadyGranted { + return prepared.Claim, eligibility, true, nil + } + return prepared.Claim, eligibility, false, nil + } + if s.wallet == nil { + return domain.Claim{}, domain.Eligibility{}, false, xerr.New(xerr.Unavailable, "wallet client is not configured") + } + + claim := prepared.Claim + var walletTransactionID string + var resourceGrantID string + grantedAtMS := s.now().UnixMilli() + switch claim.RewardType { + case domain.RewardTypeCoin: + resp, err := s.wallet.CreditTaskReward(ctx, &walletv1.CreditTaskRewardRequest{ + CommandId: claim.WalletCommandID, + AppCode: appcode.FromContext(ctx), + TargetUserId: claim.UserID, + Amount: claim.CoinAmount, + TaskType: "exclusive", + TaskId: registrationRewardTaskID, + CycleKey: "lifetime", + Reason: registrationRewardReason, + }) + if err != nil { + _ = s.repository.MarkRegistrationRewardClaimFailed(ctx, claim.ClaimID, xerr.MessageOf(err), s.now().UnixMilli()) + return domain.Claim{}, domain.Eligibility{}, false, err + } + walletTransactionID = resp.GetTransactionId() + if resp.GetGrantedAtMs() > 0 { + grantedAtMS = resp.GetGrantedAtMs() + } + case domain.RewardTypeResourceGroup: + resp, err := s.wallet.GrantResourceGroup(ctx, &walletv1.GrantResourceGroupRequest{ + CommandId: claim.WalletCommandID, + AppCode: appcode.FromContext(ctx), + TargetUserId: claim.UserID, + GroupId: claim.ResourceGroupID, + Reason: registrationRewardReason, + OperatorUserId: claim.UserID, + GrantSource: registrationRewardReason, + }) + if err != nil { + _ = s.repository.MarkRegistrationRewardClaimFailed(ctx, claim.ClaimID, xerr.MessageOf(err), s.now().UnixMilli()) + return domain.Claim{}, domain.Eligibility{}, false, err + } + if resp.GetGrant() != nil { + resourceGrantID = resp.GetGrant().GetGrantId() + } + default: + _ = s.repository.MarkRegistrationRewardClaimFailed(ctx, claim.ClaimID, domain.ReasonInvalidConfig, s.now().UnixMilli()) + return domain.Claim{}, domain.Eligibility{}, false, xerr.New(xerr.InvalidArgument, "reward_type is invalid") + } + claim, err = s.repository.MarkRegistrationRewardClaimGranted(ctx, claim.ClaimID, walletTransactionID, resourceGrantID, grantedAtMS) + if err != nil { + return domain.Claim{}, domain.Eligibility{}, false, err + } + eligibility, err := s.repository.GetRegistrationRewardEligibility(ctx, command.UserID, day, s.now().UnixMilli()) + if err != nil { + return domain.Claim{}, domain.Eligibility{}, false, err + } + return claim, eligibility, true, nil +} + +func (s *Service) ListClaims(ctx context.Context, query domain.ClaimQuery) ([]domain.Claim, int64, error) { + if err := s.requireRepository(); err != nil { + return nil, 0, err + } + query.Status = strings.TrimSpace(query.Status) + if query.Page <= 0 { + query.Page = 1 + } + if query.PageSize <= 0 { + query.PageSize = 20 + } + if query.PageSize > 100 { + query.PageSize = 100 + } + return s.repository.ListRegistrationRewardClaims(ctx, query) +} + +func (s *Service) requireRepository() error { + if s == nil || s.repository == nil { + return xerr.New(xerr.Unavailable, "registration reward repository is not configured") + } + return nil +} + +func normalizeRewardType(value string) string { + return strings.ToLower(strings.TrimSpace(value)) +} + +func validateConfig(config domain.Config) error { + if config.UpdatedByAdminID <= 0 { + return xerr.New(xerr.InvalidArgument, "operator_admin_id is required") + } + if config.DailyLimit < 0 { + return xerr.New(xerr.InvalidArgument, "daily_limit cannot be negative") + } + switch config.RewardType { + case domain.RewardTypeCoin: + if config.CoinAmount <= 0 { + return xerr.New(xerr.InvalidArgument, "coin_amount must be greater than zero") + } + case domain.RewardTypeResourceGroup: + if config.ResourceGroupID <= 0 { + return xerr.New(xerr.InvalidArgument, "resource_group_id is required") + } + default: + return xerr.New(xerr.InvalidArgument, "reward_type is invalid") + } + return nil +} + +func rewardDay(t time.Time) string { + utc := t.UTC() + return time.Date(utc.Year(), utc.Month(), utc.Day(), 0, 0, 0, 0, time.UTC).Format("2006-01-02") +} diff --git a/services/activity-service/internal/storage/mysql/registration_reward_repository.go b/services/activity-service/internal/storage/mysql/registration_reward_repository.go new file mode 100644 index 00000000..6af3bf8f --- /dev/null +++ b/services/activity-service/internal/storage/mysql/registration_reward_repository.go @@ -0,0 +1,628 @@ +package mysql + +import ( + "context" + "database/sql" + "errors" + "fmt" + "strings" + + "hyapp/pkg/appcode" + "hyapp/pkg/idgen" + "hyapp/pkg/xerr" + domain "hyapp/services/activity-service/internal/domain/registrationreward" +) + +// GetRegistrationRewardConfig 读取注册奖励当前配置;未配置是正常后台首屏状态。 +func (r *Repository) GetRegistrationRewardConfig(ctx context.Context) (domain.Config, bool, error) { + if r == nil || r.db == nil { + return domain.Config{}, false, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + row := r.db.QueryRowContext(ctx, registrationRewardConfigSelectSQL()+` + WHERE app_code = ?`, + appcode.FromContext(ctx), + ) + config, err := scanRegistrationRewardConfig(row) + if errors.Is(err, sql.ErrNoRows) { + return domain.Config{}, false, nil + } + return config, err == nil, err +} + +// UpdateRegistrationRewardConfig 原子 upsert 配置;created_at_ms 只在首次创建时写入。 +func (r *Repository) UpdateRegistrationRewardConfig(ctx context.Context, config domain.Config, nowMS int64) (domain.Config, error) { + if r == nil || r.db == nil { + return domain.Config{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + _, err := r.db.ExecContext(ctx, ` + INSERT INTO registration_reward_configs ( + app_code, enabled, reward_type, coin_amount, resource_group_id, daily_limit, + updated_by_admin_id, created_at_ms, updated_at_ms + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + enabled = VALUES(enabled), + reward_type = VALUES(reward_type), + coin_amount = VALUES(coin_amount), + resource_group_id = VALUES(resource_group_id), + daily_limit = VALUES(daily_limit), + updated_by_admin_id = VALUES(updated_by_admin_id), + updated_at_ms = VALUES(updated_at_ms)`, + appcode.FromContext(ctx), config.Enabled, config.RewardType, config.CoinAmount, config.ResourceGroupID, + config.DailyLimit, config.UpdatedByAdminID, nowMS, nowMS, + ) + if err != nil { + return domain.Config{}, err + } + updated, exists, err := r.GetRegistrationRewardConfig(ctx) + if err != nil { + return domain.Config{}, err + } + if !exists { + return domain.Config{}, xerr.New(xerr.NotFound, "registration reward config not found") + } + return updated, nil +} + +// GetRegistrationRewardEligibility 用只读事实判断 App 是否可领取;failed claim 不算“已领过”。 +func (r *Repository) GetRegistrationRewardEligibility(ctx context.Context, userID int64, rewardDay string, nowMS int64) (domain.Eligibility, error) { + if r == nil || r.db == nil { + return domain.Eligibility{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + config, exists, err := r.GetRegistrationRewardConfig(ctx) + if err != nil { + return domain.Eligibility{}, err + } + used, err := r.registrationRewardDailyUsed(ctx, rewardDay) + if err != nil { + return domain.Eligibility{}, err + } + eligibility := eligibilityFromConfig(config, exists, used, rewardDay, nowMS) + if !eligibility.Enabled { + return eligibility, nil + } + status, err := r.registrationRewardUserClaimStatus(ctx, userID) + if err != nil { + return domain.Eligibility{}, err + } + if status == domain.StatusGranted || status == domain.StatusPending { + eligibility.CanReceive = false + eligibility.Reason = domain.ReasonAlreadyClaimed + return eligibility, nil + } + if eligibility.DailyLimit > 0 && eligibility.DailyUsed >= eligibility.DailyLimit { + eligibility.CanReceive = false + eligibility.Reason = domain.ReasonDailyLimitReached + return eligibility, nil + } + if !validRegistrationRewardConfig(config) { + eligibility.CanReceive = false + eligibility.Reason = domain.ReasonInvalidConfig + return eligibility, nil + } + eligibility.CanReceive = true + eligibility.Reason = domain.ReasonEligible + return eligibility, nil +} + +// PrepareRegistrationRewardClaim 在一个 MySQL 事务内完成幂等判断、每日份数预留和 pending claim 写入。 +func (r *Repository) PrepareRegistrationRewardClaim(ctx context.Context, command domain.IssueCommand, rewardDay string, nowMS int64) (domain.PrepareResult, error) { + if r == nil || r.db == nil { + return domain.PrepareResult{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return domain.PrepareResult{}, err + } + defer func() { _ = tx.Rollback() }() + + config, exists, err := r.getRegistrationRewardConfigForUpdate(ctx, tx) + if err != nil { + return domain.PrepareResult{}, err + } + if !exists { + return domain.PrepareResult{Reason: domain.ReasonNotConfigured}, tx.Commit() + } + if !config.Enabled { + return domain.PrepareResult{Reason: domain.ReasonDisabled}, tx.Commit() + } + if !validRegistrationRewardConfig(config) { + return domain.PrepareResult{Reason: domain.ReasonInvalidConfig}, tx.Commit() + } + + if existing, exists, err := r.getRegistrationRewardClaimByCommandForUpdate(ctx, tx, command.CommandID); err != nil || exists { + if err != nil { + return domain.PrepareResult{}, err + } + if existing.UserID != command.UserID { + return domain.PrepareResult{}, xerr.New(xerr.RequestConflict, "registration reward command payload conflicts") + } + if existing.Status == domain.StatusGranted { + if err := tx.Commit(); err != nil { + return domain.PrepareResult{}, err + } + return domain.PrepareResult{Claim: existing, AlreadyGranted: true, Reason: domain.ReasonAlreadyClaimed}, nil + } + if existing.Status == domain.StatusFailed { + ok, reason, err := r.reserveRegistrationRewardDailySlot(ctx, tx, config, rewardDay, nowMS) + if err != nil || !ok { + if err != nil { + return domain.PrepareResult{}, err + } + return domain.PrepareResult{Claim: existing, Reason: reason}, tx.Commit() + } + existing = claimWithConfig(existing, config, rewardDay, nowMS) + if err := r.updateRegistrationRewardClaimPending(ctx, tx, existing); err != nil { + return domain.PrepareResult{}, err + } + } + if err := tx.Commit(); err != nil { + return domain.PrepareResult{}, err + } + return domain.PrepareResult{Claim: existing, Prepared: true}, nil + } + + if existing, exists, err := r.getRegistrationRewardClaimByUserForUpdate(ctx, tx, command.UserID); err != nil || exists { + if err != nil { + return domain.PrepareResult{}, err + } + if existing.Status == domain.StatusGranted { + if err := tx.Commit(); err != nil { + return domain.PrepareResult{}, err + } + return domain.PrepareResult{Claim: existing, AlreadyGranted: true, Reason: domain.ReasonAlreadyClaimed}, nil + } + if existing.Status == domain.StatusPending { + return domain.PrepareResult{Claim: existing, Reason: domain.ReasonAlreadyClaimed}, tx.Commit() + } + ok, reason, err := r.reserveRegistrationRewardDailySlot(ctx, tx, config, rewardDay, nowMS) + if err != nil || !ok { + if err != nil { + return domain.PrepareResult{}, err + } + return domain.PrepareResult{Claim: existing, Reason: reason}, tx.Commit() + } + existing = claimWithConfig(existing, config, rewardDay, nowMS) + existing.CommandID = command.CommandID + existing.WalletCommandID = walletRegistrationRewardCommandID(existing.ClaimID) + if err := r.updateRegistrationRewardClaimPending(ctx, tx, existing); err != nil { + return domain.PrepareResult{}, err + } + if err := tx.Commit(); err != nil { + return domain.PrepareResult{}, err + } + return domain.PrepareResult{Claim: existing, Prepared: true}, nil + } + + ok, reason, err := r.reserveRegistrationRewardDailySlot(ctx, tx, config, rewardDay, nowMS) + if err != nil || !ok { + if err != nil { + return domain.PrepareResult{}, err + } + return domain.PrepareResult{Reason: reason}, tx.Commit() + } + claim := domain.Claim{ + ClaimID: idgen.New("rclaim"), + CommandID: command.CommandID, + UserID: command.UserID, + RewardDay: rewardDay, + RewardType: config.RewardType, + CoinAmount: config.CoinAmount, + ResourceGroupID: config.ResourceGroupID, + Status: domain.StatusPending, + CreatedAtMS: nowMS, + UpdatedAtMS: nowMS, + } + claim.WalletCommandID = walletRegistrationRewardCommandID(claim.ClaimID) + if err := r.insertRegistrationRewardClaim(ctx, tx, claim); err != nil { + return domain.PrepareResult{}, err + } + if err := tx.Commit(); err != nil { + return domain.PrepareResult{}, err + } + return domain.PrepareResult{Claim: claim, Prepared: true}, nil +} + +// MarkRegistrationRewardClaimGranted 把外部钱包回执写回 activity 事实,并递增当天 granted 计数。 +func (r *Repository) MarkRegistrationRewardClaimGranted(ctx context.Context, claimID string, walletTransactionID string, resourceGrantID string, grantedAtMS int64) (domain.Claim, error) { + if r == nil || r.db == nil { + return domain.Claim{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return domain.Claim{}, err + } + defer func() { _ = tx.Rollback() }() + + claim, err := r.getRegistrationRewardClaimByIDForUpdate(ctx, tx, claimID) + if err != nil { + return domain.Claim{}, err + } + if claim.Status == domain.StatusGranted { + if err := tx.Commit(); err != nil { + return domain.Claim{}, err + } + return claim, nil + } + if _, err := tx.ExecContext(ctx, ` + UPDATE registration_reward_claims + SET status = 'granted', + wallet_transaction_id = ?, + resource_grant_id = ?, + failure_reason = '', + claimed_at_ms = ?, + updated_at_ms = ? + WHERE app_code = ? AND claim_id = ?`, + walletTransactionID, resourceGrantID, grantedAtMS, grantedAtMS, appcode.FromContext(ctx), claimID, + ); err != nil { + return domain.Claim{}, err + } + if _, err := tx.ExecContext(ctx, ` + UPDATE registration_reward_daily_counters + SET granted_count = granted_count + 1, updated_at_ms = ? + WHERE app_code = ? AND reward_day = ?`, + grantedAtMS, appcode.FromContext(ctx), claim.RewardDay, + ); err != nil { + return domain.Claim{}, err + } + if err := tx.Commit(); err != nil { + return domain.Claim{}, err + } + claim.Status = domain.StatusGranted + claim.WalletTransactionID = walletTransactionID + claim.ResourceGrantID = resourceGrantID + claim.FailureReason = "" + claim.ClaimedAtMS = grantedAtMS + claim.UpdatedAtMS = grantedAtMS + return claim, nil +} + +// MarkRegistrationRewardClaimFailed 释放 pending 预留份数;这样钱包短暂失败不会永久占用每日额度。 +func (r *Repository) MarkRegistrationRewardClaimFailed(ctx context.Context, claimID string, failureReason string, nowMS int64) error { + if r == nil || r.db == nil { + return xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer func() { _ = tx.Rollback() }() + + claim, err := r.getRegistrationRewardClaimByIDForUpdate(ctx, tx, claimID) + if err != nil { + return err + } + if claim.Status == domain.StatusGranted { + return tx.Commit() + } + if claim.Status == domain.StatusPending { + if _, err := tx.ExecContext(ctx, ` + UPDATE registration_reward_daily_counters + SET reserved_count = IF(reserved_count > 0, reserved_count - 1, 0), + failed_count = failed_count + 1, + updated_at_ms = ? + WHERE app_code = ? AND reward_day = ?`, + nowMS, appcode.FromContext(ctx), claim.RewardDay, + ); err != nil { + return err + } + } + if _, err := tx.ExecContext(ctx, ` + UPDATE registration_reward_claims + SET status = 'failed', failure_reason = ?, updated_at_ms = ? + WHERE app_code = ? AND claim_id = ?`, + truncateTaskFailure(failureReason), nowMS, appcode.FromContext(ctx), claimID, + ); err != nil { + return err + } + return tx.Commit() +} + +// ListRegistrationRewardClaims 返回后台领取事实列表;按领取/创建时间倒序便于运营复核最近发放。 +func (r *Repository) ListRegistrationRewardClaims(ctx context.Context, query domain.ClaimQuery) ([]domain.Claim, int64, error) { + if r == nil || r.db == nil { + return nil, 0, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + where, args := registrationRewardClaimWhere(ctx, query) + var total int64 + if err := r.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM registration_reward_claims `+where, args...).Scan(&total); err != nil { + return nil, 0, err + } + pageSize := normalizePageSize(query.PageSize) + page := query.Page + if page <= 0 { + page = 1 + } + args = append(args, pageSize, (page-1)*pageSize) + rows, err := r.db.QueryContext(ctx, registrationRewardClaimSelectSQL()+` + `+where+` + ORDER BY created_at_ms DESC, claim_id DESC + LIMIT ? OFFSET ?`, args...) + if err != nil { + return nil, 0, err + } + defer rows.Close() + return scanRegistrationRewardClaims(rows, total) +} + +func (r *Repository) getRegistrationRewardConfigForUpdate(ctx context.Context, tx *sql.Tx) (domain.Config, bool, error) { + row := tx.QueryRowContext(ctx, registrationRewardConfigSelectSQL()+` + WHERE app_code = ? + FOR UPDATE`, + appcode.FromContext(ctx), + ) + config, err := scanRegistrationRewardConfig(row) + if errors.Is(err, sql.ErrNoRows) { + return domain.Config{}, false, nil + } + return config, err == nil, err +} + +func (r *Repository) reserveRegistrationRewardDailySlot(ctx context.Context, tx *sql.Tx, config domain.Config, rewardDay string, nowMS int64) (bool, string, error) { + if _, err := tx.ExecContext(ctx, ` + INSERT INTO registration_reward_daily_counters ( + app_code, reward_day, reserved_count, granted_count, failed_count, updated_at_ms + ) VALUES (?, ?, 0, 0, 0, ?) + ON DUPLICATE KEY UPDATE updated_at_ms = updated_at_ms`, + appcode.FromContext(ctx), rewardDay, nowMS, + ); err != nil { + return false, "", err + } + var reserved int64 + if err := tx.QueryRowContext(ctx, ` + SELECT reserved_count + FROM registration_reward_daily_counters + WHERE app_code = ? AND reward_day = ? + FOR UPDATE`, + appcode.FromContext(ctx), rewardDay, + ).Scan(&reserved); err != nil { + return false, "", err + } + if config.DailyLimit > 0 && reserved >= config.DailyLimit { + return false, domain.ReasonDailyLimitReached, nil + } + if _, err := tx.ExecContext(ctx, ` + UPDATE registration_reward_daily_counters + SET reserved_count = reserved_count + 1, updated_at_ms = ? + WHERE app_code = ? AND reward_day = ?`, + nowMS, appcode.FromContext(ctx), rewardDay, + ); err != nil { + return false, "", err + } + return true, "", nil +} + +func (r *Repository) registrationRewardDailyUsed(ctx context.Context, rewardDay string) (int64, error) { + var used int64 + err := r.db.QueryRowContext(ctx, ` + SELECT reserved_count + FROM registration_reward_daily_counters + WHERE app_code = ? AND reward_day = ?`, + appcode.FromContext(ctx), rewardDay, + ).Scan(&used) + if errors.Is(err, sql.ErrNoRows) { + return 0, nil + } + return used, err +} + +func (r *Repository) registrationRewardUserClaimStatus(ctx context.Context, userID int64) (string, error) { + var status string + err := r.db.QueryRowContext(ctx, ` + SELECT status + FROM registration_reward_claims + WHERE app_code = ? AND user_id = ?`, + appcode.FromContext(ctx), userID, + ).Scan(&status) + if errors.Is(err, sql.ErrNoRows) { + return "", nil + } + return status, err +} + +func (r *Repository) getRegistrationRewardClaimByCommandForUpdate(ctx context.Context, tx *sql.Tx, commandID string) (domain.Claim, bool, error) { + row := tx.QueryRowContext(ctx, registrationRewardClaimSelectSQL()+` + WHERE app_code = ? AND command_id = ? + FOR UPDATE`, + appcode.FromContext(ctx), commandID, + ) + claim, err := scanRegistrationRewardClaim(row) + if errors.Is(err, sql.ErrNoRows) { + return domain.Claim{}, false, nil + } + return claim, err == nil, err +} + +func (r *Repository) getRegistrationRewardClaimByUserForUpdate(ctx context.Context, tx *sql.Tx, userID int64) (domain.Claim, bool, error) { + row := tx.QueryRowContext(ctx, registrationRewardClaimSelectSQL()+` + WHERE app_code = ? AND user_id = ? + FOR UPDATE`, + appcode.FromContext(ctx), userID, + ) + claim, err := scanRegistrationRewardClaim(row) + if errors.Is(err, sql.ErrNoRows) { + return domain.Claim{}, false, nil + } + return claim, err == nil, err +} + +func (r *Repository) getRegistrationRewardClaimByIDForUpdate(ctx context.Context, tx *sql.Tx, claimID string) (domain.Claim, error) { + row := tx.QueryRowContext(ctx, registrationRewardClaimSelectSQL()+` + WHERE app_code = ? AND claim_id = ? + FOR UPDATE`, + appcode.FromContext(ctx), claimID, + ) + claim, err := scanRegistrationRewardClaim(row) + if errors.Is(err, sql.ErrNoRows) { + return domain.Claim{}, xerr.New(xerr.NotFound, "registration reward claim not found") + } + return claim, err +} + +func (r *Repository) insertRegistrationRewardClaim(ctx context.Context, tx *sql.Tx, claim domain.Claim) error { + _, err := tx.ExecContext(ctx, ` + INSERT INTO registration_reward_claims ( + app_code, claim_id, command_id, user_id, reward_day, reward_type, + coin_amount, resource_group_id, status, wallet_command_id, + wallet_transaction_id, resource_grant_id, failure_reason, claimed_at_ms, + created_at_ms, updated_at_ms + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '', '', '', 0, ?, ?)`, + appcode.FromContext(ctx), claim.ClaimID, claim.CommandID, claim.UserID, claim.RewardDay, claim.RewardType, + claim.CoinAmount, claim.ResourceGroupID, claim.Status, claim.WalletCommandID, claim.CreatedAtMS, claim.UpdatedAtMS, + ) + return err +} + +func (r *Repository) updateRegistrationRewardClaimPending(ctx context.Context, tx *sql.Tx, claim domain.Claim) error { + _, err := tx.ExecContext(ctx, ` + UPDATE registration_reward_claims + SET command_id = ?, + reward_day = ?, + reward_type = ?, + coin_amount = ?, + resource_group_id = ?, + status = 'pending', + wallet_command_id = ?, + wallet_transaction_id = '', + resource_grant_id = '', + failure_reason = '', + claimed_at_ms = 0, + updated_at_ms = ? + WHERE app_code = ? AND claim_id = ?`, + claim.CommandID, claim.RewardDay, claim.RewardType, claim.CoinAmount, claim.ResourceGroupID, + claim.WalletCommandID, claim.UpdatedAtMS, appcode.FromContext(ctx), claim.ClaimID, + ) + return err +} + +func scanRegistrationRewardClaims(rows *sql.Rows, total int64) ([]domain.Claim, int64, error) { + items := make([]domain.Claim, 0) + for rows.Next() { + item, err := scanRegistrationRewardClaim(rows) + if err != nil { + return nil, 0, err + } + items = append(items, item) + } + if err := rows.Err(); err != nil { + return nil, 0, err + } + return items, total, nil +} + +func scanRegistrationRewardConfig(row rowScanner) (domain.Config, error) { + var config domain.Config + err := row.Scan( + &config.AppCode, + &config.Enabled, + &config.RewardType, + &config.CoinAmount, + &config.ResourceGroupID, + &config.DailyLimit, + &config.UpdatedByAdminID, + &config.CreatedAtMS, + &config.UpdatedAtMS, + ) + return config, err +} + +func scanRegistrationRewardClaim(row rowScanner) (domain.Claim, error) { + var claim domain.Claim + err := row.Scan( + &claim.ClaimID, + &claim.CommandID, + &claim.UserID, + &claim.RewardDay, + &claim.RewardType, + &claim.CoinAmount, + &claim.ResourceGroupID, + &claim.Status, + &claim.WalletCommandID, + &claim.WalletTransactionID, + &claim.ResourceGrantID, + &claim.FailureReason, + &claim.ClaimedAtMS, + &claim.CreatedAtMS, + &claim.UpdatedAtMS, + ) + return claim, err +} + +func registrationRewardConfigSelectSQL() string { + return `SELECT app_code, enabled, reward_type, coin_amount, resource_group_id, daily_limit, + updated_by_admin_id, created_at_ms, updated_at_ms + FROM registration_reward_configs ` +} + +func registrationRewardClaimSelectSQL() string { + return `SELECT claim_id, command_id, user_id, reward_day, reward_type, coin_amount, resource_group_id, + status, wallet_command_id, wallet_transaction_id, resource_grant_id, failure_reason, + claimed_at_ms, created_at_ms, updated_at_ms + FROM registration_reward_claims ` +} + +func registrationRewardClaimWhere(ctx context.Context, query domain.ClaimQuery) (string, []any) { + conditions := []string{"app_code = ?"} + args := []any{appcode.FromContext(ctx)} + if query.Status != "" { + conditions = append(conditions, "status = ?") + args = append(args, query.Status) + } + if query.UserID > 0 { + conditions = append(conditions, "user_id = ?") + args = append(args, query.UserID) + } + return "WHERE " + strings.Join(conditions, " AND "), args +} + +func eligibilityFromConfig(config domain.Config, exists bool, used int64, rewardDay string, nowMS int64) domain.Eligibility { + reason := domain.ReasonEligible + if !exists { + reason = domain.ReasonNotConfigured + } else if !config.Enabled { + reason = domain.ReasonDisabled + } + remaining := int64(0) + if config.DailyLimit > 0 && used < config.DailyLimit { + remaining = config.DailyLimit - used + } + return domain.Eligibility{ + CanReceive: exists && config.Enabled, + Reason: reason, + Enabled: exists && config.Enabled, + RewardType: config.RewardType, + CoinAmount: config.CoinAmount, + ResourceGroupID: config.ResourceGroupID, + DailyLimit: config.DailyLimit, + DailyUsed: used, + DailyRemaining: remaining, + RewardDay: rewardDay, + ServerTimeMS: nowMS, + } +} + +func validRegistrationRewardConfig(config domain.Config) bool { + switch config.RewardType { + case domain.RewardTypeCoin: + return config.CoinAmount > 0 + case domain.RewardTypeResourceGroup: + return config.ResourceGroupID > 0 + default: + return false + } +} + +func claimWithConfig(claim domain.Claim, config domain.Config, rewardDay string, nowMS int64) domain.Claim { + claim.RewardDay = rewardDay + claim.RewardType = config.RewardType + claim.CoinAmount = config.CoinAmount + claim.ResourceGroupID = config.ResourceGroupID + claim.Status = domain.StatusPending + claim.FailureReason = "" + claim.ClaimedAtMS = 0 + claim.UpdatedAtMS = nowMS + return claim +} + +func walletRegistrationRewardCommandID(claimID string) string { + return fmt.Sprintf("wreg_%s", claimID) +} diff --git a/services/activity-service/internal/transport/grpc/registration_reward_server.go b/services/activity-service/internal/transport/grpc/registration_reward_server.go new file mode 100644 index 00000000..88268790 --- /dev/null +++ b/services/activity-service/internal/transport/grpc/registration_reward_server.go @@ -0,0 +1,154 @@ +package grpc + +import ( + "context" + + activityv1 "hyapp.local/api/proto/activity/v1" + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + domain "hyapp/services/activity-service/internal/domain/registrationreward" + service "hyapp/services/activity-service/internal/service/registrationreward" +) + +// RegistrationRewardServer 暴露 App 查询和 user-service 注册后发放接口。 +type RegistrationRewardServer struct { + activityv1.UnimplementedRegistrationRewardServiceServer + + svc *service.Service +} + +func NewRegistrationRewardServer(svc *service.Service) *RegistrationRewardServer { + return &RegistrationRewardServer{svc: svc} +} + +func (s *RegistrationRewardServer) GetRegistrationRewardEligibility(ctx context.Context, req *activityv1.GetRegistrationRewardEligibilityRequest) (*activityv1.GetRegistrationRewardEligibilityResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + eligibility, err := s.svc.GetEligibility(ctx, req.GetUserId()) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.GetRegistrationRewardEligibilityResponse{Eligibility: eligibilityToProto(eligibility)}, nil +} + +func (s *RegistrationRewardServer) IssueRegistrationReward(ctx context.Context, req *activityv1.IssueRegistrationRewardRequest) (*activityv1.IssueRegistrationRewardResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + claim, eligibility, issued, err := s.svc.IssueRegistrationReward(ctx, domain.IssueCommand{ + UserID: req.GetUserId(), + CommandID: req.GetCommandId(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.IssueRegistrationRewardResponse{ + Claim: registrationRewardClaimToProto(claim), + Eligibility: eligibilityToProto(eligibility), + Issued: issued, + }, nil +} + +// AdminRegistrationRewardServer 暴露后台配置和领取记录查询入口。 +type AdminRegistrationRewardServer struct { + activityv1.UnimplementedAdminRegistrationRewardServiceServer + + svc *service.Service +} + +func NewAdminRegistrationRewardServer(svc *service.Service) *AdminRegistrationRewardServer { + return &AdminRegistrationRewardServer{svc: svc} +} + +func (s *AdminRegistrationRewardServer) GetRegistrationRewardConfig(ctx context.Context, req *activityv1.GetRegistrationRewardConfigRequest) (*activityv1.GetRegistrationRewardConfigResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + config, err := s.svc.GetConfig(ctx) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.GetRegistrationRewardConfigResponse{Config: registrationRewardConfigToProto(config)}, nil +} + +func (s *AdminRegistrationRewardServer) UpdateRegistrationRewardConfig(ctx context.Context, req *activityv1.UpdateRegistrationRewardConfigRequest) (*activityv1.UpdateRegistrationRewardConfigResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + config, err := s.svc.UpdateConfig(ctx, domain.Config{ + Enabled: req.GetEnabled(), + RewardType: req.GetRewardType(), + CoinAmount: req.GetCoinAmount(), + ResourceGroupID: req.GetResourceGroupId(), + DailyLimit: req.GetDailyLimit(), + UpdatedByAdminID: req.GetOperatorAdminId(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.UpdateRegistrationRewardConfigResponse{Config: registrationRewardConfigToProto(config)}, nil +} + +func (s *AdminRegistrationRewardServer) ListRegistrationRewardClaims(ctx context.Context, req *activityv1.ListRegistrationRewardClaimsRequest) (*activityv1.ListRegistrationRewardClaimsResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + claims, total, err := s.svc.ListClaims(ctx, domain.ClaimQuery{ + Status: req.GetStatus(), + UserID: req.GetUserId(), + Page: req.GetPage(), + PageSize: req.GetPageSize(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + resp := &activityv1.ListRegistrationRewardClaimsResponse{Claims: make([]*activityv1.RegistrationRewardClaim, 0, len(claims)), Total: total} + for _, claim := range claims { + resp.Claims = append(resp.Claims, registrationRewardClaimToProto(claim)) + } + return resp, nil +} + +func registrationRewardConfigToProto(config domain.Config) *activityv1.RegistrationRewardConfig { + return &activityv1.RegistrationRewardConfig{ + AppCode: config.AppCode, + Enabled: config.Enabled, + RewardType: config.RewardType, + CoinAmount: config.CoinAmount, + ResourceGroupId: config.ResourceGroupID, + DailyLimit: config.DailyLimit, + UpdatedByAdminId: config.UpdatedByAdminID, + CreatedAtMs: config.CreatedAtMS, + UpdatedAtMs: config.UpdatedAtMS, + } +} + +func registrationRewardClaimToProto(claim domain.Claim) *activityv1.RegistrationRewardClaim { + if claim.ClaimID == "" { + return nil + } + return &activityv1.RegistrationRewardClaim{ + ClaimId: claim.ClaimID, + CommandId: claim.CommandID, + UserId: claim.UserID, + RewardDay: claim.RewardDay, + RewardType: claim.RewardType, + CoinAmount: claim.CoinAmount, + ResourceGroupId: claim.ResourceGroupID, + Status: claim.Status, + WalletCommandId: claim.WalletCommandID, + WalletTransactionId: claim.WalletTransactionID, + ResourceGrantId: claim.ResourceGrantID, + FailureReason: claim.FailureReason, + ClaimedAtMs: claim.ClaimedAtMS, + CreatedAtMs: claim.CreatedAtMS, + UpdatedAtMs: claim.UpdatedAtMS, + } +} + +func eligibilityToProto(item domain.Eligibility) *activityv1.RegistrationRewardEligibility { + return &activityv1.RegistrationRewardEligibility{ + CanReceive: item.CanReceive, + Reason: item.Reason, + Enabled: item.Enabled, + RewardType: item.RewardType, + CoinAmount: item.CoinAmount, + ResourceGroupId: item.ResourceGroupID, + DailyLimit: item.DailyLimit, + DailyUsed: item.DailyUsed, + DailyRemaining: item.DailyRemaining, + RewardDay: item.RewardDay, + ServerTimeMs: item.ServerTimeMS, + } +} diff --git a/services/gateway-service/internal/app/app.go b/services/gateway-service/internal/app/app.go index 09c96fe6..b0639e24 100644 --- a/services/gateway-service/internal/app/app.go +++ b/services/gateway-service/internal/app/app.go @@ -91,6 +91,7 @@ func New(cfg config.Config) (*App, error) { var walletClient client.WalletClient = client.NewGRPCWalletClient(walletConn) var messageClient client.MessageInboxClient = client.NewGRPCMessageInboxClient(activityConn) var taskClient client.TaskClient = client.NewGRPCTaskClient(activityConn) + var registrationRewardClient client.RegistrationRewardClient = client.NewGRPCRegistrationRewardClient(activityConn) var broadcastClient client.BroadcastClient = client.NewGRPCBroadcastClient(activityConn) var gameClient client.GameClient = client.NewGRPCGameClient(gameConn) appConfigReader, err := openAppConfigReader(cfg.AppConfig) @@ -118,6 +119,7 @@ func New(cfg config.Config) (*App, error) { handler.SetWalletClient(walletClient) handler.SetMessageInboxClient(messageClient) handler.SetTaskClient(taskClient) + handler.SetRegistrationRewardClient(registrationRewardClient) handler.SetBroadcastClient(broadcastClient) handler.SetGameClient(gameClient) if appConfigReader != nil { diff --git a/services/gateway-service/internal/appconfig/mysql.go b/services/gateway-service/internal/appconfig/mysql.go index f1fc85dd..5a4accd9 100644 --- a/services/gateway-service/internal/appconfig/mysql.go +++ b/services/gateway-service/internal/appconfig/mysql.go @@ -21,6 +21,12 @@ const listAppBannersSQL = ` AND (region_id = 0 OR region_id = ?) AND (country_code = '' OR country_code = ?) ORDER BY sort_order ASC, id DESC` +const latestAppVersionSQL = ` + SELECT id, app_code, platform, version, build_number, force_update, download_url, COALESCE(description, ''), updated_at_ms + FROM admin_app_versions + WHERE app_code = ? AND platform = ? + ORDER BY build_number DESC, id DESC + LIMIT 1` // H5Link 是 gateway 下发给 App 的 H5 入口配置。 type H5Link struct { @@ -52,10 +58,31 @@ type Banner struct { UpdatedAtMs int64 `json:"updated_at_ms"` } +// VersionQuery 是 App 检查更新的公开筛选条件。 +type VersionQuery struct { + AppCode string + Platform string + CurrentBuildNumber int64 +} + +// Version 是后台 APP配置/版本管理 中当前平台的最新 App 版本。 +type Version struct { + ID uint `json:"id"` + AppCode string `json:"app_code"` + Platform string `json:"platform"` + Version string `json:"version"` + BuildNumber int64 `json:"build_number"` + ForceUpdate bool `json:"force_update"` + DownloadURL string `json:"download_url"` + Description string `json:"description"` + UpdatedAtMs int64 `json:"updated_at_ms"` +} + // Reader 是 HTTP 层读取 H5 配置的最小依赖。 type Reader interface { ListH5Links(ctx context.Context) ([]H5Link, error) ListBanners(ctx context.Context, query BannerQuery) ([]Banner, error) + LatestVersion(ctx context.Context, query VersionQuery) (Version, error) } type h5LinkDefinition struct { @@ -188,10 +215,38 @@ func (r *MySQLReader) ListBanners(ctx context.Context, query BannerQuery) ([]Ban return items, nil } +// LatestVersion 返回指定 App 和平台的最高 build_number 版本;未配置时返回空版本,方便 App 端按无更新处理。 +func (r *MySQLReader) LatestVersion(ctx context.Context, query VersionQuery) (Version, error) { + if r == nil || r.db == nil { + return Version{}, errors.New("app config reader is not configured") + } + + var item Version + err := r.db.QueryRowContext(ctx, latestAppVersionSQL, normalizeAppCode(query.AppCode), normalizePlatform(query.Platform)).Scan( + &item.ID, + &item.AppCode, + &item.Platform, + &item.Version, + &item.BuildNumber, + &item.ForceUpdate, + &item.DownloadURL, + &item.Description, + &item.UpdatedAtMs, + ) + if errors.Is(err, sql.ErrNoRows) { + return Version{AppCode: normalizeAppCode(query.AppCode), Platform: normalizePlatform(query.Platform)}, nil + } + if err != nil { + return Version{}, err + } + return item, nil +} + // StaticReader 给测试和临时环境提供内存版 H5 配置读取。 type StaticReader struct { Links []H5Link Banners []Banner + Version Version Err error } @@ -217,6 +272,21 @@ func (r StaticReader) ListBanners(context.Context, BannerQuery) ([]Banner, error return out, nil } +// LatestVersion 返回预置版本配置。 +func (r StaticReader) LatestVersion(_ context.Context, query VersionQuery) (Version, error) { + if r.Err != nil { + return Version{}, r.Err + } + item := r.Version + if item.AppCode == "" { + item.AppCode = normalizeAppCode(query.AppCode) + } + if item.Platform == "" { + item.Platform = normalizePlatform(query.Platform) + } + return item, nil +} + func normalizeAppCode(value string) string { value = strings.ToLower(strings.TrimSpace(value)) if value == "" { diff --git a/services/gateway-service/internal/client/registration_reward_client.go b/services/gateway-service/internal/client/registration_reward_client.go new file mode 100644 index 00000000..65353b36 --- /dev/null +++ b/services/gateway-service/internal/client/registration_reward_client.go @@ -0,0 +1,25 @@ +package client + +import ( + "context" + + "google.golang.org/grpc" + activityv1 "hyapp.local/api/proto/activity/v1" +) + +// RegistrationRewardClient abstracts gateway access to activity-service registration reward reads. +type RegistrationRewardClient interface { + GetRegistrationRewardEligibility(ctx context.Context, req *activityv1.GetRegistrationRewardEligibilityRequest) (*activityv1.GetRegistrationRewardEligibilityResponse, error) +} + +type grpcRegistrationRewardClient struct { + client activityv1.RegistrationRewardServiceClient +} + +func NewGRPCRegistrationRewardClient(conn *grpc.ClientConn) RegistrationRewardClient { + return &grpcRegistrationRewardClient{client: activityv1.NewRegistrationRewardServiceClient(conn)} +} + +func (c *grpcRegistrationRewardClient) GetRegistrationRewardEligibility(ctx context.Context, req *activityv1.GetRegistrationRewardEligibilityRequest) (*activityv1.GetRegistrationRewardEligibilityResponse, error) { + return c.client.GetRegistrationRewardEligibility(ctx, req) +} diff --git a/services/gateway-service/internal/client/room_client.go b/services/gateway-service/internal/client/room_client.go index 3089414b..a41aa291 100644 --- a/services/gateway-service/internal/client/room_client.go +++ b/services/gateway-service/internal/client/room_client.go @@ -23,7 +23,6 @@ type RoomClient interface { SetMicSeatLock(ctx context.Context, req *roomv1.SetMicSeatLockRequest) (*roomv1.SetMicSeatLockResponse, error) SetChatEnabled(ctx context.Context, req *roomv1.SetChatEnabledRequest) (*roomv1.SetChatEnabledResponse, error) SetRoomAdmin(ctx context.Context, req *roomv1.SetRoomAdminRequest) (*roomv1.SetRoomAdminResponse, error) - TransferRoomHost(ctx context.Context, req *roomv1.TransferRoomHostRequest) (*roomv1.TransferRoomHostResponse, error) MuteUser(ctx context.Context, req *roomv1.MuteUserRequest) (*roomv1.MuteUserResponse, error) KickUser(ctx context.Context, req *roomv1.KickUserRequest) (*roomv1.KickUserResponse, error) UnbanUser(ctx context.Context, req *roomv1.UnbanUserRequest) (*roomv1.UnbanUserResponse, error) @@ -136,10 +135,6 @@ func (c *grpcRoomClient) SetRoomAdmin(ctx context.Context, req *roomv1.SetRoomAd return c.client.SetRoomAdmin(ctx, req) } -func (c *grpcRoomClient) TransferRoomHost(ctx context.Context, req *roomv1.TransferRoomHostRequest) (*roomv1.TransferRoomHostResponse, error) { - return c.client.TransferRoomHost(ctx, req) -} - func (c *grpcRoomClient) MuteUser(ctx context.Context, req *roomv1.MuteUserRequest) (*roomv1.MuteUserResponse, error) { return c.client.MuteUser(ctx, req) } diff --git a/services/gateway-service/internal/transport/http/app_config_handler.go b/services/gateway-service/internal/transport/http/app_config_handler.go index b0d6c82e..d9fd4965 100644 --- a/services/gateway-service/internal/transport/http/app_config_handler.go +++ b/services/gateway-service/internal/transport/http/app_config_handler.go @@ -2,7 +2,6 @@ package http import ( "context" - "hyapp/services/gateway-service/internal/transport/http/httpkit" "net/http" "strconv" "strings" @@ -10,12 +9,14 @@ import ( "hyapp/pkg/appcode" "hyapp/services/gateway-service/internal/appconfig" + "hyapp/services/gateway-service/internal/transport/http/httpkit" ) // appConfigReader 是 gateway 对后台 App 配置的只读依赖。 type appConfigReader interface { ListH5Links(ctx context.Context) ([]appconfig.H5Link, error) ListBanners(ctx context.Context, query appconfig.BannerQuery) ([]appconfig.Banner, error) + LatestVersion(ctx context.Context, query appconfig.VersionQuery) (appconfig.Version, error) } type appBootstrapBottomTab struct { @@ -36,6 +37,20 @@ type appBootstrapResponse struct { ConfigVersions map[string]string `json:"config_versions"` } +type appVersionResponse struct { + AppCode string `json:"app_code"` + Platform string `json:"platform"` + Version string `json:"version"` + BuildNumber int64 `json:"build_number"` + ForceUpdate bool `json:"force_update"` + DownloadURL string `json:"download_url"` + Description string `json:"description"` + HasUpdate bool `json:"has_update"` + CurrentBuildNumber int64 `json:"current_build_number"` + UpdatedAtMs int64 `json:"updated_at_ms"` + ServerTimeMs int64 `json:"server_time_ms"` +} + // getAppBootstrap 返回 App 启动状态机需要的轻量配置摘要。 // bootstrap 只下发版本、开关和配置版本号,不返回 banner、礼物或资源大列表。 func (h *Handler) getAppBootstrap(writer http.ResponseWriter, request *http.Request) { @@ -108,6 +123,43 @@ func (h *Handler) listAppBanners(writer http.ResponseWriter, request *http.Reque httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items)}) } +// getAppVersion 返回当前平台最新版本;App 用 build_number 判定是否需要提示升级。 +func (h *Handler) getAppVersion(writer http.ResponseWriter, request *http.Request) { + if h.appConfigReader == nil { + httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error") + return + } + platform := normalizeAppPlatform(firstQueryOrHeader(request, "platform", "X-App-Platform", "X-Platform")) + if platform != "android" && platform != "ios" { + httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "platform is invalid") + return + } + currentBuildNumber := optionalInt64QueryOrHeader(request, "build_number", "X-App-Build-Number", "X-Build-Number") + item, err := h.appConfigReader.LatestVersion(request.Context(), appconfig.VersionQuery{ + AppCode: appcode.FromContext(request.Context()), + Platform: platform, + CurrentBuildNumber: currentBuildNumber, + }) + if err != nil { + httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error") + return + } + + httpkit.WriteOK(writer, request, appVersionResponse{ + AppCode: item.AppCode, + Platform: platform, + Version: item.Version, + BuildNumber: item.BuildNumber, + ForceUpdate: item.ForceUpdate && item.BuildNumber > currentBuildNumber, + DownloadURL: item.DownloadURL, + Description: item.Description, + HasUpdate: item.BuildNumber > currentBuildNumber, + CurrentBuildNumber: currentBuildNumber, + UpdatedAtMs: item.UpdatedAtMs, + ServerTimeMs: time.Now().UTC().UnixMilli(), + }) +} + func firstQueryOrHeader(request *http.Request, queryKey string, headerNames ...string) string { if value := strings.TrimSpace(request.URL.Query().Get(queryKey)); value != "" { return value @@ -115,6 +167,18 @@ func firstQueryOrHeader(request *http.Request, queryKey string, headerNames ...s return firstHeader(request, headerNames...) } +func optionalInt64QueryOrHeader(request *http.Request, queryKey string, headerNames ...string) int64 { + value := firstQueryOrHeader(request, queryKey, headerNames...) + if value == "" { + return 0 + } + parsed, err := strconv.ParseInt(value, 10, 64) + if err != nil || parsed < 0 { + return 0 + } + return parsed +} + func optionalInt64Query(request *http.Request, key string) int64 { value := strings.TrimSpace(request.URL.Query().Get(key)) if value == "" { @@ -126,3 +190,7 @@ func optionalInt64Query(request *http.Request, key string) int64 { } return parsed } + +func normalizeAppPlatform(value string) string { + return strings.ToLower(strings.TrimSpace(value)) +} diff --git a/services/gateway-service/internal/transport/http/app_wallet_handler.go b/services/gateway-service/internal/transport/http/app_wallet_handler.go index 30a838c0..4069f306 100644 --- a/services/gateway-service/internal/transport/http/app_wallet_handler.go +++ b/services/gateway-service/internal/transport/http/app_wallet_handler.go @@ -12,15 +12,22 @@ import ( ) type rechargeProductData struct { - ProductID int64 `json:"product_id"` - ProductCode string `json:"product_code"` - Channel string `json:"channel"` - CurrencyCode string `json:"currency_code"` - CoinAmount int64 `json:"coin_amount"` - AmountMinor int64 `json:"amount_minor"` - PolicyVersion string `json:"policy_version"` - Enabled bool `json:"enabled"` - SortOrder int32 `json:"sort_order"` + ProductID int64 `json:"product_id"` + ProductCode string `json:"product_code"` + ProductName string `json:"product_name"` + Description string `json:"description"` + Platform string `json:"platform"` + Channel string `json:"channel"` + CurrencyCode string `json:"currency_code"` + CoinAmount int64 `json:"coin_amount"` + AmountMinor int64 `json:"amount_minor"` + AmountMicro int64 `json:"amount_micro"` + PolicyVersion string `json:"policy_version"` + RegionIDs []int64 `json:"region_ids"` + ResourceAssetType string `json:"resource_asset_type"` + Status string `json:"status"` + Enabled bool `json:"enabled"` + SortOrder int32 `json:"sort_order"` } type diamondExchangeRuleData struct { @@ -143,6 +150,7 @@ func (h *Handler) listRechargeProducts(writer http.ResponseWriter, request *http AppCode: appcode.FromContext(request.Context()), UserId: userID, RegionId: profileResp.GetUser().GetRegionId(), + Platform: firstQueryOrHeader(request, "platform", "X-App-Platform", "X-Platform"), }) if err != nil { httpkit.WriteRPCError(writer, request, err) @@ -179,6 +187,15 @@ func (h *Handler) getDiamondExchangeConfig(writer http.ResponseWriter, request * // listWalletTransactions 返回当前用户钱包流水分页。 func (h *Handler) listWalletTransactions(writer http.ResponseWriter, request *http.Request) { + h.listWalletTransactionsByAsset(writer, request, strings.TrimSpace(request.URL.Query().Get("asset_type")), 20) +} + +// listCoinTransactions 返回当前用户金币流水分页;默认 page_size=30 对齐 App 最近 30 条展示。 +func (h *Handler) listCoinTransactions(writer http.ResponseWriter, request *http.Request) { + h.listWalletTransactionsByAsset(writer, request, "COIN", 30) +} + +func (h *Handler) listWalletTransactionsByAsset(writer http.ResponseWriter, request *http.Request, assetType string, defaultPageSize int32) { if h.walletClient == nil { httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error") return @@ -188,7 +205,7 @@ func (h *Handler) listWalletTransactions(writer http.ResponseWriter, request *ht httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument") return } - pageSize, ok := parsePositiveInt32Query(request, "page_size", 20) + pageSize, ok := parsePositiveInt32Query(request, "page_size", defaultPageSize) if !ok { httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument") return @@ -197,7 +214,7 @@ func (h *Handler) listWalletTransactions(writer http.ResponseWriter, request *ht RequestId: httpkit.RequestIDFromContext(request.Context()), AppCode: appcode.FromContext(request.Context()), UserId: auth.UserIDFromContext(request.Context()), - AssetType: strings.TrimSpace(request.URL.Query().Get("asset_type")), + AssetType: assetType, Page: page, PageSize: pageSize, }) @@ -257,15 +274,22 @@ func rechargeProductFromProto(product *walletv1.RechargeProduct) rechargeProduct return rechargeProductData{} } return rechargeProductData{ - ProductID: product.GetProductId(), - ProductCode: product.GetProductCode(), - Channel: product.GetChannel(), - CurrencyCode: product.GetCurrencyCode(), - CoinAmount: product.GetCoinAmount(), - AmountMinor: product.GetAmountMinor(), - PolicyVersion: product.GetPolicyVersion(), - Enabled: product.GetEnabled(), - SortOrder: product.GetSortOrder(), + ProductID: product.GetProductId(), + ProductCode: product.GetProductCode(), + ProductName: product.GetProductName(), + Description: product.GetDescription(), + Platform: product.GetPlatform(), + Channel: product.GetChannel(), + CurrencyCode: product.GetCurrencyCode(), + CoinAmount: product.GetCoinAmount(), + AmountMinor: product.GetAmountMinor(), + AmountMicro: product.GetAmountMicro(), + PolicyVersion: product.GetPolicyVersion(), + RegionIDs: product.GetRegionIds(), + ResourceAssetType: product.GetResourceAssetType(), + Status: product.GetStatus(), + Enabled: product.GetEnabled(), + SortOrder: product.GetSortOrder(), } } diff --git a/services/gateway-service/internal/transport/http/handler.go b/services/gateway-service/internal/transport/http/handler.go index c528616a..bf6c3a8e 100644 --- a/services/gateway-service/internal/transport/http/handler.go +++ b/services/gateway-service/internal/transport/http/handler.go @@ -36,6 +36,7 @@ type Handler struct { walletClient client.WalletClient messageClient client.MessageInboxClient taskClient client.TaskClient + registrationReward client.RegistrationRewardClient broadcastClient client.BroadcastClient gameClient client.GameClient appConfigReader appConfigReader @@ -173,6 +174,11 @@ func (h *Handler) SetTaskClient(taskClient client.TaskClient) { h.taskClient = taskClient } +// SetRegistrationRewardClient 注入 activity-service 注册奖励查询 client。 +func (h *Handler) SetRegistrationRewardClient(registrationReward client.RegistrationRewardClient) { + h.registrationReward = registrationReward +} + // SetBroadcastClient 注入 activity-service 播报群成员关系 client。 func (h *Handler) SetBroadcastClient(broadcastClient client.BroadcastClient) { h.broadcastClient = broadcastClient diff --git a/services/gateway-service/internal/transport/http/httproutes/router.go b/services/gateway-service/internal/transport/http/httproutes/router.go index 980d7ce9..f3355b36 100644 --- a/services/gateway-service/internal/transport/http/httproutes/router.go +++ b/services/gateway-service/internal/transport/http/httproutes/router.go @@ -39,6 +39,7 @@ type AppHandlers struct { GetAppBootstrap http.HandlerFunc ListH5Links http.HandlerFunc ListAppBanners http.HandlerFunc + GetAppVersion http.HandlerFunc ListResources http.HandlerFunc GetResourceGroup http.HandlerFunc ListGifts http.HandlerFunc @@ -103,7 +104,6 @@ type RoomHandlers struct { SetMicSeatLock http.HandlerFunc SetChatEnabled http.HandlerFunc SetRoomAdmin http.HandlerFunc - TransferRoomHost http.HandlerFunc MuteUser http.HandlerFunc KickUser http.HandlerFunc UnbanUser http.HandlerFunc @@ -119,8 +119,9 @@ type MessageHandlers struct { } type TaskHandlers struct { - ListTaskTabs http.HandlerFunc - ClaimTaskReward http.HandlerFunc + ListTaskTabs http.HandlerFunc + ClaimTaskReward http.HandlerFunc + GetRegistrationRewardEligibility http.HandlerFunc } type WalletHandlers struct { @@ -129,6 +130,7 @@ type WalletHandlers struct { ListRechargeProducts http.HandlerFunc GetDiamondExchangeConfig http.HandlerFunc ApplyWithdrawal http.HandlerFunc + ListCoinTransactions http.HandlerFunc ListWalletTransactions http.HandlerFunc TransferCoinFromSeller http.HandlerFunc } @@ -205,6 +207,7 @@ func (r routes) registerAppRoutes() { r.public("/app/bootstrap", "", h.GetAppBootstrap) r.public("/app/h5-links", "", h.ListH5Links) r.public("/app/banners", "", h.ListAppBanners) + r.public("/app/version", http.MethodGet, h.GetAppVersion) r.public("/resources", "", h.ListResources) r.public("/resource-groups/{group_id}", "", h.GetResourceGroup) r.public("/gifts", "", h.ListGifts) @@ -272,7 +275,6 @@ func (r routes) registerRoomRoutes() { r.profile("/rooms/mic/lock", http.MethodPost, h.SetMicSeatLock) r.profile("/rooms/chat/enabled", http.MethodPost, h.SetChatEnabled) r.profile("/rooms/admin/set", http.MethodPost, h.SetRoomAdmin) - r.profile("/rooms/host/transfer", http.MethodPost, h.TransferRoomHost) r.profile("/rooms/user/mute", http.MethodPost, h.MuteUser) r.profile("/rooms/user/kick", http.MethodPost, h.KickUser) r.profile("/rooms/user/unban", http.MethodPost, h.UnbanUser) @@ -290,6 +292,7 @@ func (r routes) registerMessageRoutes() { func (r routes) registerTaskRoutes() { h := r.config.Task + r.profile("/activities/registration-reward/eligibility", http.MethodGet, h.GetRegistrationRewardEligibility) r.profile("/tasks/tabs", http.MethodGet, h.ListTaskTabs) r.profile("/tasks/claim", http.MethodPost, h.ClaimTaskReward) } @@ -301,6 +304,7 @@ func (r routes) registerWalletRoutes() { r.profile("/wallet/recharge/products", http.MethodGet, h.ListRechargeProducts) r.profile("/wallet/diamond-exchange/config", http.MethodGet, h.GetDiamondExchangeConfig) r.profile("/wallet/withdrawals/apply", http.MethodPost, h.ApplyWithdrawal) + r.profile("/wallet/coin-transactions", http.MethodGet, h.ListCoinTransactions) r.profile("/wallet/transactions", http.MethodGet, h.ListWalletTransactions) r.profile("/wallet/coin-seller/transfer", "", h.TransferCoinFromSeller) } diff --git a/services/gateway-service/internal/transport/http/registration_reward_handler.go b/services/gateway-service/internal/transport/http/registration_reward_handler.go new file mode 100644 index 00000000..474c107c --- /dev/null +++ b/services/gateway-service/internal/transport/http/registration_reward_handler.go @@ -0,0 +1,59 @@ +package http + +import ( + "net/http" + + activityv1 "hyapp.local/api/proto/activity/v1" + "hyapp/services/gateway-service/internal/auth" + "hyapp/services/gateway-service/internal/transport/http/httpkit" +) + +type registrationRewardEligibilityData struct { + CanReceive bool `json:"can_receive"` + Reason string `json:"reason"` + Enabled bool `json:"enabled"` + RewardType string `json:"reward_type"` + CoinAmount int64 `json:"coin_amount"` + ResourceGroupID int64 `json:"resource_group_id"` + DailyLimit int64 `json:"daily_limit"` + DailyUsed int64 `json:"daily_used"` + DailyRemaining int64 `json:"daily_remaining"` + RewardDay string `json:"reward_day"` + ServerTimeMS int64 `json:"server_time_ms"` +} + +// getRegistrationRewardEligibility 只查询资格,不执行发放;注册后的实际发放由 user-service 触发。 +func (h *Handler) getRegistrationRewardEligibility(writer http.ResponseWriter, request *http.Request) { + if h.registrationReward == nil { + httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error") + return + } + resp, err := h.registrationReward.GetRegistrationRewardEligibility(request.Context(), &activityv1.GetRegistrationRewardEligibilityRequest{ + Meta: activityMeta(request), + UserId: auth.UserIDFromContext(request.Context()), + }) + if err != nil { + httpkit.WriteRPCError(writer, request, err) + return + } + httpkit.WriteOK(writer, request, registrationRewardEligibilityFromProto(resp.GetEligibility())) +} + +func registrationRewardEligibilityFromProto(item *activityv1.RegistrationRewardEligibility) registrationRewardEligibilityData { + if item == nil { + return registrationRewardEligibilityData{} + } + return registrationRewardEligibilityData{ + CanReceive: item.GetCanReceive(), + Reason: item.GetReason(), + Enabled: item.GetEnabled(), + RewardType: item.GetRewardType(), + CoinAmount: item.GetCoinAmount(), + ResourceGroupID: item.GetResourceGroupId(), + DailyLimit: item.GetDailyLimit(), + DailyUsed: item.GetDailyUsed(), + DailyRemaining: item.GetDailyRemaining(), + RewardDay: item.GetRewardDay(), + ServerTimeMS: item.GetServerTimeMs(), + } +} diff --git a/services/gateway-service/internal/transport/http/response_test.go b/services/gateway-service/internal/transport/http/response_test.go index 4f75e823..88612830 100644 --- a/services/gateway-service/internal/transport/http/response_test.go +++ b/services/gateway-service/internal/transport/http/response_test.go @@ -46,7 +46,6 @@ type fakeRoomClient struct { lastMicSeatLock *roomv1.SetMicSeatLockRequest lastChatEnabled *roomv1.SetChatEnabledRequest lastSetAdmin *roomv1.SetRoomAdminRequest - lastTransferHost *roomv1.TransferRoomHostRequest lastMute *roomv1.MuteUserRequest lastKick *roomv1.KickUserRequest lastUnban *roomv1.UnbanUserRequest @@ -79,7 +78,6 @@ func (f *fakeRoomClient) UpdateRoomProfile(_ context.Context, req *roomv1.Update Room: &roomv1.RoomSnapshot{ RoomId: req.GetMeta().GetRoomId(), OwnerUserId: req.GetMeta().GetActorUserId(), - HostUserId: req.GetMeta().GetActorUserId(), Mode: "voice", Status: "active", ChatEnabled: true, @@ -113,12 +111,11 @@ func (f *fakeRoomClient) JoinRoom(_ context.Context, req *roomv1.JoinRoomRequest Room: &roomv1.RoomSnapshot{ RoomId: req.GetMeta().GetRoomId(), OwnerUserId: 1001, - HostUserId: 1002, Mode: "voice", Status: "active", ChatEnabled: true, MicSeats: []*roomv1.SeatState{{SeatNo: 1}, {SeatNo: 2, UserId: 1002, PublishState: "publishing", MicSessionId: "mic-1002"}}, - OnlineUsers: []*roomv1.RoomUser{{UserId: userID, Role: role}, {UserId: 1002, Role: "host"}}, + OnlineUsers: []*roomv1.RoomUser{{UserId: userID, Role: role}, {UserId: 1002, Role: "admin"}}, GiftRank: []*roomv1.RankItem{{UserId: 1002, Score: 200, GiftValue: 200}}, RoomExt: map[string]string{"title": "Room", "cover_url": "https://cdn.example/room.png", "description": "welcome", "room_short_id": "100001"}, Heat: 99, @@ -183,11 +180,6 @@ func (f *fakeRoomClient) SetRoomAdmin(_ context.Context, req *roomv1.SetRoomAdmi return &roomv1.SetRoomAdminResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 9}}, nil } -func (f *fakeRoomClient) TransferRoomHost(_ context.Context, req *roomv1.TransferRoomHostRequest) (*roomv1.TransferRoomHostResponse, error) { - f.lastTransferHost = req - return &roomv1.TransferRoomHostResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 10}}, nil -} - func (f *fakeRoomClient) MuteUser(_ context.Context, req *roomv1.MuteUserRequest) (*roomv1.MuteUserResponse, error) { f.lastMute = req return &roomv1.MuteUserResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 11}}, nil @@ -1246,15 +1238,6 @@ func TestRoomCommandsPropagateClientCommandID(t *testing.T) { return client.lastSetAdmin.GetMeta() }, }, - { - name: "transfer_host", - path: "/api/v1/rooms/host/transfer", - body: `{"room_id":"room-1","command_id":"cmd-host-1","target_user_id":43}`, - commandID: "cmd-host-1", - extractMeta: func(client *fakeRoomClient) *roomv1.RequestMeta { - return client.lastTransferHost.GetMeta() - }, - }, { name: "mute", path: "/api/v1/rooms/user/mute", @@ -1337,12 +1320,11 @@ func TestJoinRoomReturnsInitialDataWithIMGroupRTCTokenAndProfiles(t *testing.T) Room: &roomv1.RoomSnapshot{ RoomId: "room_1001", OwnerUserId: 101, - HostUserId: 102, Mode: "voice", Status: "active", ChatEnabled: true, MicSeats: []*roomv1.SeatState{{SeatNo: 1, UserId: 102, PublishState: "publishing", MicSessionId: "mic-102"}, {SeatNo: 2, Locked: true}}, - OnlineUsers: []*roomv1.RoomUser{{UserId: 42, Role: "audience"}, {UserId: 102, Role: "host"}}, + OnlineUsers: []*roomv1.RoomUser{{UserId: 42, Role: "audience"}, {UserId: 102, Role: "admin"}}, GiftRank: []*roomv1.RankItem{{UserId: 301, Score: 900, GiftValue: 900}}, RoomExt: map[string]string{"title": "Live Room", "cover_url": "https://cdn.example/cover.png", "description": "welcome"}, Heat: 88, @@ -1397,7 +1379,7 @@ func TestJoinRoomReturnsInitialDataWithIMGroupRTCTokenAndProfiles(t *testing.T) if rtc["available"] != true || token["str_room_id"] != "room_1001" || token["rtc_user_id"] != "42" { t.Fatalf("join response must embed usable rtc token: rtc=%+v token=%+v", rtc, token) } - if profileClient.lastBatch == nil || strings.Join(int64SliceToStrings(profileClient.lastBatch.GetUserIds()), ",") != "101,102,42,301" { + if profileClient.lastBatch == nil || strings.Join(int64SliceToStrings(profileClient.lastBatch.GetUserIds()), ",") != "101,42,102,301" { t.Fatalf("join response must batch only first-screen profile users: %+v", profileClient.lastBatch) } } @@ -1960,6 +1942,49 @@ func TestListAppBannersReturnsAdminAppConfig(t *testing.T) { } } +func TestGetAppVersionReturnsLatestVersionAndUpdateDecision(t *testing.T) { + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetAppConfigReader(appconfig.StaticReader{Version: appconfig.Version{ + AppCode: "lalu", + Platform: "ios", + Version: "1.2.0", + BuildNumber: 120, + ForceUpdate: true, + DownloadURL: "https://apps.apple.com/app/lalu", + Description: "bug fixes", + UpdatedAtMs: 1700000003000, + }}) + router := handler.Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/app/version?build_number=100", nil) + request.Header.Set("X-Request-ID", "req-app-version") + request.Header.Set("X-App-Code", "lalu") + request.Header.Set("X-App-Platform", "ios") + 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()) + } + var response httpkit.ResponseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode response failed: %v", err) + } + data, ok := response.Data.(map[string]any) + if response.Code != httpkit.CodeOK || !ok { + t.Fatalf("unexpected envelope: %+v", response) + } + if data["platform"] != "ios" || + data["version"] != "1.2.0" || + data["build_number"] != float64(120) || + data["current_build_number"] != float64(100) || + data["has_update"] != true || + data["force_update"] != true || + data["download_url"] != "https://apps.apple.com/app/lalu" { + t.Fatalf("app version response mismatch: %+v", data) + } +} + func TestGetMyHostIdentityCombinesActiveHostAndBDProfiles(t *testing.T) { hostClient := &fakeUserHostClient{ hostProfile: &userv1.HostProfile{ @@ -2632,6 +2657,119 @@ func TestGetMyBalancesUsesAuthenticatedUserIDAndDefaultsCoin(t *testing.T) { } } +func TestListCoinTransactionsForcesCoinAndDefaultsPageSize30(t *testing.T) { + walletClient := &fakeWalletClient{transactionsResp: &walletv1.ListWalletTransactionsResponse{ + Total: 1, + Transactions: []*walletv1.WalletTransaction{{ + EntryId: 7, + TransactionId: "wtx-coin-1", + BizType: "coin_seller_transfer", + AssetType: "COIN", + AvailableDelta: 300, + AvailableAfter: 1300, + CreatedAtMs: 1_700_000_000_000, + }}, + }} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetWalletClient(walletClient) + router := handler.Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/wallet/coin-transactions?page=2", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-coin-ledger") + 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 walletClient.lastTransactions == nil || walletClient.lastTransactions.GetUserId() != 42 || walletClient.lastTransactions.GetAssetType() != "COIN" { + t.Fatalf("wallet transaction request mismatch: %+v", walletClient.lastTransactions) + } + if walletClient.lastTransactions.GetPage() != 2 || walletClient.lastTransactions.GetPageSize() != 30 { + t.Fatalf("coin transaction pagination mismatch: %+v", walletClient.lastTransactions) + } + var response httpkit.ResponseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode response failed: %v", err) + } + data, ok := response.Data.(map[string]any) + items, itemsOK := data["items"].([]any) + if response.Code != httpkit.CodeOK || !ok || !itemsOK || len(items) != 1 || data["page_size"] != float64(30) { + t.Fatalf("coin transaction response mismatch: %+v", response) + } +} + +func TestListRechargeProductsUsesProfileRegionAndPlatform(t *testing.T) { + walletClient := &fakeWalletClient{rechargeProductsResp: &walletv1.ListRechargeProductsResponse{ + Channels: []string{"google"}, + Products: []*walletv1.RechargeProduct{{ + ProductId: 11, + ProductCode: "iap_android_11", + ProductName: "1500 Coins", + Description: "coin pack", + Platform: "android", + Channel: "google", + CurrencyCode: "USDT", + CoinAmount: 1500, + AmountMicro: 1500000, + AmountMinor: 1500000, + RegionIds: []int64{2002}, + ResourceAssetType: "COIN", + Status: "active", + Enabled: true, + }}, + }} + profileClient := &fakeUserProfileClient{regionID: 2002} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, profileClient) + handler.SetWalletClient(walletClient) + router := handler.Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/wallet/recharge/products", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-recharge-products") + request.Header.Set("X-App-Platform", "android") + 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 profileClient.lastGet == nil || profileClient.lastGet.GetUserId() != 42 { + t.Fatalf("profile lookup mismatch: %+v", profileClient.lastGet) + } + if walletClient.lastRechargeProducts == nil || + walletClient.lastRechargeProducts.GetUserId() != 42 || + walletClient.lastRechargeProducts.GetRegionId() != 2002 || + walletClient.lastRechargeProducts.GetPlatform() != "android" || + walletClient.lastRechargeProducts.GetAppCode() != "lalu" || + walletClient.lastRechargeProducts.GetRequestId() != assertGeneratedRequestID(t, recorder, "req-recharge-products") { + t.Fatalf("recharge products request mismatch: %+v", walletClient.lastRechargeProducts) + } + var response httpkit.ResponseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode response failed: %v", err) + } + data, ok := response.Data.(map[string]any) + products, productsOK := data["products"].([]any) + channels, channelsOK := data["channels"].([]any) + if response.Code != httpkit.CodeOK || !ok || !productsOK || len(products) != 1 || !channelsOK || len(channels) != 1 { + t.Fatalf("recharge response shape mismatch: %+v", response) + } + product, ok := products[0].(map[string]any) + if !ok || + product["product_name"] != "1500 Coins" || + product["platform"] != "android" || + product["channel"] != "google" || + product["currency_code"] != "USDT" || + product["coin_amount"] != float64(1500) || + product["amount_micro"] != float64(1500000) || + product["resource_asset_type"] != "COIN" || + product["enabled"] != true { + t.Fatalf("recharge product dto mismatch: %+v", product) + } +} + func TestCoinSellerTransferChecksIdentityAndPropagatesWalletCommand(t *testing.T) { walletClient := &fakeWalletClient{transferResp: &walletv1.TransferCoinFromSellerResponse{ TransactionId: "wtx-coin-seller", diff --git a/services/gateway-service/internal/transport/http/room_handler.go b/services/gateway-service/internal/transport/http/room_handler.go index 1971b66b..5329dac5 100644 --- a/services/gateway-service/internal/transport/http/room_handler.go +++ b/services/gateway-service/internal/transport/http/room_handler.go @@ -895,25 +895,6 @@ func (h *Handler) setRoomAdmin(writer http.ResponseWriter, request *http.Request write(writer, request, resp, err) } -// transferRoomHost 把主持转移 HTTP JSON 请求转换为 room-service TransferRoomHost 命令。 -func (h *Handler) transferRoomHost(writer http.ResponseWriter, request *http.Request) { - var body struct { - RoomID string `json:"room_id"` - CommandID string `json:"command_id"` - TargetUserID int64 `json:"target_user_id"` - } - - if !decode(writer, request, &body) { - return - } - - resp, err := h.roomClient.TransferRoomHost(request.Context(), &roomv1.TransferRoomHostRequest{ - Meta: meta(request, body.RoomID, body.CommandID), - TargetUserId: body.TargetUserID, - }) - write(writer, request, resp, err) -} - // muteUser 把禁言 HTTP JSON 请求转换为 room-service MuteUser 命令。 func (h *Handler) muteUser(writer http.ResponseWriter, request *http.Request) { var body struct { @@ -1081,7 +1062,7 @@ func roomGiftRecipientUserIDs(snapshot *roomv1.RoomSnapshot) []int64 { } } if len(userIDs) == 0 { - userIDs = append(userIDs, snapshot.GetHostUserId()) + userIDs = append(userIDs, snapshot.GetOwnerUserId()) } return uniquePositiveUserIDs(userIDs) } diff --git a/services/gateway-service/internal/transport/http/room_view.go b/services/gateway-service/internal/transport/http/room_view.go index cd0fa7a7..09bcdb12 100644 --- a/services/gateway-service/internal/transport/http/room_view.go +++ b/services/gateway-service/internal/transport/http/room_view.go @@ -25,7 +25,6 @@ type roomListItemData struct { RoomID string `json:"room_id"` IMGroupID string `json:"im_group_id"` OwnerUserID string `json:"owner_user_id,omitempty"` - HostUserID string `json:"host_user_id,omitempty"` Title string `json:"title,omitempty"` CoverURL string `json:"cover_url,omitempty"` Mode string `json:"mode,omitempty"` @@ -81,7 +80,6 @@ type roomOnlineUserData struct { type roomPermissionsData struct { IsOwner bool `json:"is_owner"` - IsHost bool `json:"is_host"` IsAdmin bool `json:"is_admin"` IsMuted bool `json:"is_muted"` CanSpeak bool `json:"can_speak"` @@ -156,7 +154,6 @@ type roomInitialData struct { CoverURL string `json:"cover_url,omitempty"` Description string `json:"description,omitempty"` OwnerUserID string `json:"owner_user_id,omitempty"` - HostUserID string `json:"host_user_id,omitempty"` Mode string `json:"mode,omitempty"` Status string `json:"status,omitempty"` ChatEnabled bool `json:"chat_enabled"` @@ -243,7 +240,6 @@ func roomListItemDataFromProto(room *roomv1.RoomListItem) roomListItemData { RoomID: roomID, IMGroupID: roomIMGroupID(roomID), OwnerUserID: formatOptionalUserID(room.GetOwnerUserId()), - HostUserID: formatOptionalUserID(room.GetHostUserId()), Title: room.GetTitle(), CoverURL: room.GetCoverUrl(), Mode: room.GetMode(), @@ -316,7 +312,6 @@ func roomInitialRoomDataFromSnapshot(snapshot *roomv1.RoomSnapshot, roomID strin CoverURL: ext["cover_url"], Description: ext["description"], OwnerUserID: formatOptionalUserID(snapshot.GetOwnerUserId()), - HostUserID: formatOptionalUserID(snapshot.GetHostUserId()), Mode: snapshot.GetMode(), Status: snapshot.GetStatus(), ChatEnabled: snapshot.GetChatEnabled(), @@ -385,19 +380,17 @@ func roomPermissionsFromSnapshot(snapshot *roomv1.RoomSnapshot, viewerUserID int return roomPermissionsData{} } isOwner := snapshot.GetOwnerUserId() == viewerUserID - isHost := snapshot.GetHostUserId() == viewerUserID isAdmin := containsInt64(snapshot.GetAdminUserIds(), viewerUserID) isMuted := containsInt64(snapshot.GetMuteUserIds(), viewerUserID) inRoom := protoRoomUserByID(snapshot, viewerUserID) != nil return roomPermissionsData{ IsOwner: isOwner, - IsHost: isHost, IsAdmin: isAdmin, IsMuted: isMuted, CanSpeak: inRoom && snapshot.GetChatEnabled() && !isMuted, CanSendGift: inRoom && snapshot.GetStatus() == "active", CanMicUp: inRoom && snapshot.GetStatus() == "active" && protoSeatByUserID(snapshot, viewerUserID) == nil, - CanManageRoom: inRoom && (isOwner || isHost || isAdmin), + CanManageRoom: inRoom && (isOwner || isAdmin), CanLeaveRoom: inRoom, CanCloseRoom: inRoom, CanMuteMic: inRoom && protoSeatByUserID(snapshot, viewerUserID) != nil, @@ -434,7 +427,6 @@ func roomInitialProfileUserIDs(snapshot *roomv1.RoomSnapshot, viewerUserID int64 } add(snapshot.GetOwnerUserId()) - add(snapshot.GetHostUserId()) add(viewerUserID) for _, seat := range snapshot.GetMicSeats() { add(seat.GetUserId()) diff --git a/services/gateway-service/internal/transport/http/router.go b/services/gateway-service/internal/transport/http/router.go index 0d20dbc9..48230da8 100644 --- a/services/gateway-service/internal/transport/http/router.go +++ b/services/gateway-service/internal/transport/http/router.go @@ -30,6 +30,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { GetAppBootstrap: h.getAppBootstrap, ListH5Links: h.listH5Links, ListAppBanners: h.listAppBanners, + GetAppVersion: h.getAppVersion, ListResources: h.listResources, GetResourceGroup: h.getResourceGroup, ListGifts: h.listGifts, @@ -91,7 +92,6 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { SetMicSeatLock: h.setMicSeatLock, SetChatEnabled: h.setChatEnabled, SetRoomAdmin: h.setRoomAdmin, - TransferRoomHost: h.transferRoomHost, MuteUser: h.muteUser, KickUser: h.kickUser, UnbanUser: h.unbanUser, @@ -105,8 +105,9 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { ListInboxMessages: h.listInboxMessages, }, Task: httproutes.TaskHandlers{ - ListTaskTabs: h.listTaskTabs, - ClaimTaskReward: h.claimTaskReward, + ListTaskTabs: h.listTaskTabs, + ClaimTaskReward: h.claimTaskReward, + GetRegistrationRewardEligibility: h.getRegistrationRewardEligibility, }, Wallet: httproutes.WalletHandlers{ GetWalletOverview: h.getWalletOverview, @@ -114,6 +115,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { ListRechargeProducts: h.listRechargeProducts, GetDiamondExchangeConfig: h.getDiamondExchangeConfig, ApplyWithdrawal: h.applyWithdrawal, + ListCoinTransactions: h.listCoinTransactions, ListWalletTransactions: h.listWalletTransactions, TransferCoinFromSeller: h.transferCoinFromSeller, }, diff --git a/services/room-service/configs/config.docker.yaml b/services/room-service/configs/config.docker.yaml index 106ec750..21d8748b 100644 --- a/services/room-service/configs/config.docker.yaml +++ b/services/room-service/configs/config.docker.yaml @@ -28,6 +28,15 @@ tencent_im: endpoint: "adminapisgp.im.qcloud.com" group_type: "ChatRoom" request_timeout: "5s" +tencent_rtc: + # Docker 本地默认关闭真实 TRTC 管理 API;开启后封禁会同步调用 RemoveUserByStrRoomId。 + enabled: false + sdk_app_id: 0 + secret_id: "" + secret_key: "" + region: "ap-guangzhou" + endpoint: "trtc.tencentcloudapi.com" + request_timeout: "5s" mysql_dsn: "hyapp:hyapp@tcp(mysql:3306)/hyapp_room?parseTime=true&charset=utf8mb4&loc=UTC" mysql_max_open_conns: 20 mysql_max_idle_conns: 10 diff --git a/services/room-service/configs/config.tencent.example.yaml b/services/room-service/configs/config.tencent.example.yaml index a3f3832e..ce820479 100644 --- a/services/room-service/configs/config.tencent.example.yaml +++ b/services/room-service/configs/config.tencent.example.yaml @@ -35,6 +35,17 @@ tencent_im: group_type: "ChatRoom" # outbox worker 单次公网调用超时。 request_timeout: "5s" +tencent_rtc: + # 线上开启后,平台封禁会同步把用户从 TRTC 字符串房间踢出。 + enabled: true + # 必须和 gateway-service tencent_rtc.sdk_app_id 使用同一个 TRTC 应用。 + sdk_app_id: 1400000000 + # 腾讯云 API 3.0 访问密钥,只允许来自线上密钥系统或私有配置。 + secret_id: "TENCENT_CLOUD_SECRET_ID" + secret_key: "TENCENT_CLOUD_SECRET_KEY" + region: "ap-guangzhou" + endpoint: "trtc.tencentcloudapi.com" + request_timeout: "5s" mysql_dsn: "USER:PASSWORD@tcp(TENCENT_CDB_HOST:3306)/hyapp_room?parseTime=true&charset=utf8mb4&loc=UTC&tls=false" mysql_max_open_conns: 80 mysql_max_idle_conns: 20 diff --git a/services/room-service/configs/config.yaml b/services/room-service/configs/config.yaml index 3954b25e..72f75c45 100644 --- a/services/room-service/configs/config.yaml +++ b/services/room-service/configs/config.yaml @@ -31,6 +31,15 @@ tencent_im: group_type: "ChatRoom" # outbox worker 建群和发送房间系统消息的单次 REST 超时。 request_timeout: "5s" +tencent_rtc: + # 本地默认关闭真实 TRTC 管理 API;开启后封禁会同步调用 RemoveUserByStrRoomId。 + enabled: false + sdk_app_id: 0 + secret_id: "" + secret_key: "" + region: "ap-guangzhou" + endpoint: "trtc.tencentcloudapi.com" + request_timeout: "5s" mysql_dsn: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_room?parseTime=true&charset=utf8mb4&loc=UTC" mysql_max_open_conns: 20 mysql_max_idle_conns: 10 diff --git a/services/room-service/deploy/mysql/initdb/001_room_service.sql b/services/room-service/deploy/mysql/initdb/001_room_service.sql index ff6c359d..d43a6a60 100644 --- a/services/room-service/deploy/mysql/initdb/001_room_service.sql +++ b/services/room-service/deploy/mysql/initdb/001_room_service.sql @@ -11,7 +11,6 @@ CREATE TABLE IF NOT EXISTS rooms ( room_id VARCHAR(64) NOT NULL, room_short_id VARCHAR(32) NOT NULL DEFAULT '', owner_user_id BIGINT NOT NULL, - host_user_id BIGINT NOT NULL, seat_count INT NOT NULL, mode VARCHAR(64) NOT NULL, status VARCHAR(32) NOT NULL, @@ -30,7 +29,6 @@ CREATE TABLE IF NOT EXISTS room_list_entries ( room_short_id VARCHAR(32) NOT NULL DEFAULT '', visible_region_id BIGINT NOT NULL DEFAULT 0, owner_user_id BIGINT NOT NULL, - host_user_id BIGINT NOT NULL, title VARCHAR(128) NOT NULL DEFAULT '', cover_url VARCHAR(512) NOT NULL DEFAULT '', mode VARCHAR(64) NOT NULL, diff --git a/services/room-service/internal/app/app.go b/services/room-service/internal/app/app.go index 783de5c9..0831f6dc 100644 --- a/services/room-service/internal/app/app.go +++ b/services/room-service/internal/app/app.go @@ -19,6 +19,7 @@ import ( "hyapp/pkg/healthhttp" "hyapp/pkg/logx" "hyapp/pkg/tencentim" + "hyapp/pkg/tencentrtc" "hyapp/services/room-service/internal/config" "hyapp/services/room-service/internal/healthcheck" "hyapp/services/room-service/internal/integration" @@ -115,6 +116,7 @@ func New(cfg config.Config) (*App, error) { roomPublisher := integration.NewNoopRoomEventPublisher() activityPublisher := integration.NewActivityOutboxPublisher(activityv1.NewRoomEventConsumerServiceClient(activityConn), time.Second) outboxPublishers := []integration.OutboxPublisher{activityPublisher} + var rtcUserRemover integration.RTCUserRemover if cfg.TencentIM.Enabled { // 腾讯云 IM 替代自研 IM;room-service 只负责服务端 REST 群消息桥接。 tencentClient, err := tencentim.NewRESTClient(cfg.TencentIM.RESTConfig()) @@ -129,6 +131,17 @@ func New(cfg config.Config) (*App, error) { roomPublisher = tencentPublisher outboxPublishers = append(outboxPublishers, tencentPublisher) } + if cfg.TencentRTC.Enabled { + rtcClient, err := tencentrtc.NewRESTClient(cfg.TencentRTC.RESTConfig()) + if err != nil { + _ = repository.Close() + _ = activityConn.Close() + _ = walletConn.Close() + _ = redisClient.Close() + return nil, err + } + rtcUserRemover = rtcClient + } outboxPublisher := integration.NewCompositeOutboxPublisher(outboxPublishers...) // 领域服务只依赖接口,App 层负责选择 MySQL/Redis/gRPC 具体实现。 @@ -139,6 +152,7 @@ func New(cfg config.Config) (*App, error) { SnapshotEveryN: cfg.SnapshotEveryN, PresenceStaleAfter: cfg.PresenceStaleAfter, MicPublishTimeout: cfg.MicPublishTimeout, + RTCUserRemover: rtcUserRemover, }, directory, repository, integration.NewGRPCWalletClient(walletConn), roomPublisher, outboxPublisher) server := grpc.NewServer(grpc.UnaryInterceptor(logx.UnaryServerInterceptor("room-service"))) diff --git a/services/room-service/internal/config/config.go b/services/room-service/internal/config/config.go index 71c6aff3..0f7b4486 100644 --- a/services/room-service/internal/config/config.go +++ b/services/room-service/internal/config/config.go @@ -11,6 +11,7 @@ import ( "hyapp/pkg/configx" "hyapp/pkg/logx" "hyapp/pkg/tencentim" + "hyapp/pkg/tencentrtc" ) // Config 描述 room-service 进程启动所需的最小配置。 @@ -45,6 +46,8 @@ type Config struct { ActivityServiceAddr string `yaml:"activity_service_addr"` // TencentIM 是腾讯云 IM 群组和房间系统消息的外部集成配置。 TencentIM TencentIMConfig `yaml:"tencent_im"` + // TencentRTC 是平台级封禁后移出实时音频房的外部集成配置。 + TencentRTC TencentRTCConfig `yaml:"tencent_rtc"` // MySQLDSN 是 rooms、snapshot、command log 和 outbox 的持久化连接串。 MySQLDSN string `yaml:"mysql_dsn"` // MySQLMaxOpenConns 控制 MySQL 最大打开连接数。 @@ -113,6 +116,40 @@ type TencentIMConfig struct { RequestTimeout time.Duration `yaml:"request_timeout"` } +// TencentRTCConfig 描述 room-service 调用腾讯云 TRTC 房间管理 API 的配置。 +type TencentRTCConfig struct { + // Enabled 控制是否启用服务端 RTC 踢人;关闭时仍会提交 Room Cell 驱逐。 + Enabled bool `yaml:"enabled"` + // SDKAppID 是 TRTC 控制台分配的应用 ID,必须和 gateway 签发 RTC UserSig 的应用一致。 + SDKAppID int64 `yaml:"sdk_app_id"` + // SecretID/SecretKey 是腾讯云 API 3.0 访问密钥,只能写在线上密钥系统或私有配置中。 + SecretID string `yaml:"secret_id"` + SecretKey string `yaml:"secret_key"` + // Region 是腾讯云 API 公共参数;TRTC 房间管理接口当前使用 ap-guangzhou/ap-beijing。 + Region string `yaml:"region"` + // Endpoint 是腾讯云 API 域名,默认 trtc.tencentcloudapi.com。 + Endpoint string `yaml:"endpoint"` + // RequestTimeout 是单次公网调用超时。 + RequestTimeout time.Duration `yaml:"request_timeout"` +} + +// RESTConfig 把 YAML 配置转换成 pkg/tencentrtc 的 REST 客户端配置。 +func (c TencentRTCConfig) RESTConfig() tencentrtc.RESTConfig { + timeout := c.RequestTimeout + if timeout <= 0 { + timeout = 5 * time.Second + } + return tencentrtc.RESTConfig{ + Enabled: c.Enabled, + SDKAppID: c.SDKAppID, + SecretID: c.SecretID, + SecretKey: c.SecretKey, + Region: c.Region, + Endpoint: c.Endpoint, + HTTPClient: &http.Client{Timeout: timeout}, + } +} + // RESTConfig 把 YAML 配置转换成 pkg/tencentim 的 REST 客户端配置。 func (c TencentIMConfig) RESTConfig() tencentim.RESTConfig { timeout := c.RequestTimeout @@ -157,6 +194,12 @@ func Default() Config { GroupType: tencentim.DefaultGroupType, RequestTimeout: 5 * time.Second, }, + TencentRTC: TencentRTCConfig{ + Enabled: false, + Region: tencentrtc.DefaultRESTRegion, + Endpoint: tencentrtc.DefaultRESTEndpoint, + RequestTimeout: 5 * time.Second, + }, MySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_room?parseTime=true&charset=utf8mb4&loc=UTC", MySQLMaxOpenConns: 20, MySQLMaxIdleConns: 10, @@ -240,6 +283,19 @@ func Normalize(cfg Config) (Config, error) { if cfg.ActivityServiceAddr == "" { cfg.ActivityServiceAddr = "127.0.0.1:13006" } + cfg.TencentRTC.SecretID = strings.TrimSpace(cfg.TencentRTC.SecretID) + cfg.TencentRTC.SecretKey = strings.TrimSpace(cfg.TencentRTC.SecretKey) + cfg.TencentRTC.Region = strings.TrimSpace(cfg.TencentRTC.Region) + if cfg.TencentRTC.Region == "" { + cfg.TencentRTC.Region = tencentrtc.DefaultRESTRegion + } + cfg.TencentRTC.Endpoint = strings.TrimSpace(cfg.TencentRTC.Endpoint) + if cfg.TencentRTC.Endpoint == "" { + cfg.TencentRTC.Endpoint = tencentrtc.DefaultRESTEndpoint + } + if cfg.TencentRTC.RequestTimeout <= 0 { + cfg.TencentRTC.RequestTimeout = 5 * time.Second + } outboxWorker, err := normalizeOutboxWorkerConfig(cfg.OutboxWorker) if err != nil { return Config{}, err diff --git a/services/room-service/internal/integration/clients.go b/services/room-service/internal/integration/clients.go index 402a7da0..18eb7547 100644 --- a/services/room-service/internal/integration/clients.go +++ b/services/room-service/internal/integration/clients.go @@ -23,6 +23,12 @@ type RoomEventPublisher interface { PublishRoomEvent(ctx context.Context, event tencentim.RoomEvent) error } +// RTCUserRemover 抽象 room-service 对腾讯 RTC 实时房间的服务端踢人能力。 +// 连接态仍在腾讯 RTC,Room Cell 只在状态提交后触发这个外部副作用。 +type RTCUserRemover interface { + RemoveUserByStrRoomID(ctx context.Context, roomID string, userID int64) error +} + // OutboxPublisher 抽象 outbox worker 对外部消费者的异步投递。 type OutboxPublisher interface { // PublishOutboxEvent 投递 protobuf outbox 信封,失败由 room_outbox 转为 retryable 状态重试。 diff --git a/services/room-service/internal/integration/tencent_im.go b/services/room-service/internal/integration/tencent_im.go index 032609c0..4fabfe55 100644 --- a/services/room-service/internal/integration/tencent_im.go +++ b/services/room-service/internal/integration/tencent_im.go @@ -195,19 +195,6 @@ func roomEventFromEnvelope(envelope *roomeventsv1.EventEnvelope) (tencentim.Room base.TargetUserID = body.GetTargetUserId() base.Attributes = map[string]string{"enabled": fmt.Sprintf("%t", body.GetEnabled())} return base, true, nil - case "RoomHostTransferred": - // 主持人转移同时携带新旧 host,便于客户端展示交接提示。 - var body roomeventsv1.RoomHostTransferred - if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil { - return tencentim.RoomEvent{}, false, err - } - base.ActorUserID = body.GetActorUserId() - base.TargetUserID = body.GetNewHostUserId() - base.Attributes = map[string]string{ - "old_host_user_id": fmt.Sprintf("%d", body.GetOldHostUserId()), - "new_host_user_id": fmt.Sprintf("%d", body.GetNewHostUserId()), - } - return base, true, nil case "RoomUserMuted": // 禁言事件只影响公屏发言权限,不改变 presence、麦位或收消息资格。 var body roomeventsv1.RoomUserMuted @@ -274,8 +261,6 @@ func eventTypeForClient(eventType string) string { return "room_chat_enabled_changed" case "RoomAdminChanged": return "room_admin_changed" - case "RoomHostTransferred": - return "room_host_transferred" case "RoomUserMuted": return "room_user_muted" case "RoomUserKicked": diff --git a/services/room-service/internal/integration/tencent_im_test.go b/services/room-service/internal/integration/tencent_im_test.go index 53af6263..8bd03754 100644 --- a/services/room-service/internal/integration/tencent_im_test.go +++ b/services/room-service/internal/integration/tencent_im_test.go @@ -16,7 +16,6 @@ import ( func TestRoomEventFromEnvelopeSkipsNonIMEvents(t *testing.T) { record, err := outbox.Build("room-noop", "RoomCreated", 1, time.Now(), &roomeventsv1.RoomCreated{ OwnerUserId: 1, - HostUserId: 1, SeatCount: 4, Mode: "social", }) diff --git a/services/room-service/internal/room/command/command.go b/services/room-service/internal/room/command/command.go index 5cbef080..46887eab 100644 --- a/services/room-service/internal/room/command/command.go +++ b/services/room-service/internal/room/command/command.go @@ -58,8 +58,6 @@ type CreateRoom struct { Base // OwnerUserID 是房间所有者,创建后自动进入管理员集合。 OwnerUserID int64 `json:"owner_user_id"` - // HostUserID 是主持人,创建后也进入管理员集合。 - HostUserID int64 `json:"host_user_id"` // SeatCount 决定初始化麦位数量。 SeatCount int32 `json:"seat_count"` // Mode 记录房间模式,当前版本只保存不做复杂策略分发。 @@ -255,16 +253,6 @@ type SetRoomAdmin struct { // Type 返回命令类型。 func (SetRoomAdmin) Type() string { return "set_room_admin" } -// TransferRoomHost 定义主持人转移请求。 -type TransferRoomHost struct { - Base - // TargetUserID 是新的主持人,必须在当前房间 presence 中。 - TargetUserID int64 `json:"target_user_id"` -} - -// Type 返回命令类型。 -func (TransferRoomHost) Type() string { return "transfer_room_host" } - // MuteUser 定义禁言请求。 type MuteUser struct { Base @@ -287,6 +275,22 @@ type KickUser struct { // Type 返回命令类型。 func (KickUser) Type() string { return "kick_user" } +// SystemEvictUser 定义平台级封禁、风控或后台治理触发的房间驱逐请求。 +type SystemEvictUser struct { + Base + // TargetUserID 是被系统驱逐的房间用户。 + TargetUserID int64 `json:"target_user_id"` + // OperatorUserID 是触发治理动作的后台管理员或 App 管理员,不参与房间权限判断。 + OperatorUserID int64 `json:"operator_user_id"` + // Reason 记录封禁、风控或后台动作来源,进入 command log 便于审计追踪。 + Reason string `json:"reason"` + // BanFromRoom 控制是否写入当前房间 ban 集合。 + BanFromRoom bool `json:"ban_from_room"` +} + +// Type 返回命令类型。 +func (SystemEvictUser) Type() string { return "system_evict_user" } + // UnbanUser 定义解除房间 ban 请求。 type UnbanUser struct { Base @@ -398,12 +402,12 @@ func Deserialize(commandType string, payload []byte) (Command, error) { cmd = &SetChatEnabled{} case SetRoomAdmin{}.Type(): cmd = &SetRoomAdmin{} - case TransferRoomHost{}.Type(): - cmd = &TransferRoomHost{} case MuteUser{}.Type(): cmd = &MuteUser{} case KickUser{}.Type(): cmd = &KickUser{} + case SystemEvictUser{}.Type(): + cmd = &SystemEvictUser{} case UnbanUser{}.Type(): cmd = &UnbanUser{} case SendGift{}.Type(): diff --git a/services/room-service/internal/room/service/authorization.go b/services/room-service/internal/room/service/authorization.go index 248973e9..628f7440 100644 --- a/services/room-service/internal/room/service/authorization.go +++ b/services/room-service/internal/room/service/authorization.go @@ -11,23 +11,19 @@ type roomRole string const ( // roleOwner 来自 RoomState.OwnerUserID,拥有房间内最高管理权限。 roleOwner roomRole = "owner" - // roleHost 来自 RoomState.HostUserID,负责现场管理但不能越过 owner。 - roleHost roomRole = "host" - // roleAdmin 来自 RoomState.AdminUsers,权限低于 owner/host。 + // roleAdmin 来自 RoomState.AdminUsers,权限低于 owner。 roleAdmin roomRole = "admin" // roleAudience 是默认兜底角色,包含未登录、未在房间和普通观众。 roleAudience roomRole = "audience" ) func actorRole(current *state.RoomState, actorUserID int64) roomRole { - // 角色权威顺序按文档固定:owner > host > admin > audience,不能只看 RoomUser.role 展示字段。 + // 角色权威顺序按当前房间状态固定:owner > admin > audience,不能只看 RoomUser.role 展示字段。 switch { case current == nil || actorUserID <= 0: return roleAudience case actorUserID == current.OwnerUserID: return roleOwner - case actorUserID == current.HostUserID: - return roleHost case current.AdminUsers[actorUserID]: return roleAdmin default: @@ -44,7 +40,7 @@ func requireActiveRoom(current *state.RoomState) error { } func requireActorPresent(current *state.RoomState, actorUserID int64) error { - // 管理动作必须来自房间业务 presence;离房后的 host/admin 不能远程管理房间。 + // 管理动作必须来自房间业务 presence;离房后的 admin 不能远程管理房间。 if _, exists := current.OnlineUsers[actorUserID]; !exists { return xerr.New(xerr.PermissionDenied, "permission denied") } @@ -63,8 +59,8 @@ func requireManagerPresent(current *state.RoomState, actorUserID int64) error { } func isManagerRole(role roomRole) bool { - // 管理角色集合只包含 owner/host/admin,普通观众只能做自助动作。 - return role == roleOwner || role == roleHost || role == roleAdmin + // 管理角色集合只包含 owner/admin,普通观众只能做自助动作。 + return role == roleOwner || role == roleAdmin } func canManageTarget(current *state.RoomState, actorUserID int64, targetUserID int64) error { @@ -75,11 +71,7 @@ func canManageTarget(current *state.RoomState, actorUserID int64, targetUserID i return xerr.New(xerr.PermissionDenied, "permission denied") } if target == roleOwner && actor != roleOwner { - // host/admin 不能管理 owner,owner 自操作由具体命令的 self check 再收紧。 - return xerr.New(xerr.PermissionDenied, "permission denied") - } - if target == roleHost && actor == roleAdmin { - // 普通 admin 不能管理 host;host 变更必须走 owner 的 TransferRoomHost。 + // admin 不能管理 owner,owner 自操作由具体命令的 self check 再收紧。 return xerr.New(xerr.PermissionDenied, "permission denied") } return nil @@ -103,15 +95,3 @@ func requireOwnerPresent(current *state.RoomState, actorUserID int64) error { } return nil } - -func requireOwnerOrHostPresent(current *state.RoomState, actorUserID int64) error { - // 解封等高风险操作限制在 owner/host,普通 admin 不能恢复被 ban 用户。 - if err := requireActorPresent(current, actorUserID); err != nil { - return err - } - role := actorRole(current, actorUserID) - if role != roleOwner && role != roleHost { - return xerr.New(xerr.PermissionDenied, "permission denied") - } - return nil -} diff --git a/services/room-service/internal/room/service/create_room.go b/services/room-service/internal/room/service/create_room.go index 066b701c..a985a803 100644 --- a/services/room-service/internal/room/service/create_room.go +++ b/services/room-service/internal/room/service/create_room.go @@ -80,7 +80,7 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) } actorUserID := req.GetMeta().GetActorUserId() if actorUserID == 0 { - // CreateRoom 的 owner/host 默认来自已鉴权调用方,不允许匿名内部命令造房间。 + // CreateRoom 的 owner 来自已鉴权调用方,不允许匿名内部命令造房间。 return nil, xerr.New(xerr.InvalidArgument, "actor_user_id is required") } if s.isDraining() { @@ -91,7 +91,6 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) cmd := command.CreateRoom{ Base: baseFromMeta(req.GetMeta()), OwnerUserID: actorUserID, - HostUserID: actorUserID, SeatCount: seatCount, Mode: mode, VisibleRegionID: normalizeVisibleRegionID(req.GetVisibleRegionId()), @@ -147,7 +146,7 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) if existing, exists, err := s.repository.GetRoomMetaByOwner(ctx, cmd.OwnerUserID); err != nil { return nil, err } else if exists { - // 一个用户只能创建一个房间;加入、主持或管理别人的房间不受这个 owner 限制影响。 + // 一个用户只能创建一个房间;加入或管理别人的房间不受这个 owner 限制影响。 return nil, xerr.New(xerr.Conflict, fmt.Sprintf("owner already has room: %s", existing.RoomID)) } @@ -157,7 +156,7 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) // 创建态直接初始化 RoomState,owner 作为首个在线用户进入房间。 now := s.clock.Now() - roomState := state.NewRoomState(cmd.RoomID(), cmd.OwnerUserID, cmd.HostUserID, cmd.SeatCount, cmd.Mode) + roomState := state.NewRoomState(cmd.RoomID(), cmd.OwnerUserID, cmd.SeatCount, cmd.Mode) roomState.Version = 1 roomState.VisibleRegionID = cmd.VisibleRegionID applyRoomProfileExt(roomState, roomProfileInput{ @@ -176,7 +175,6 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) // RoomCreated 进入 outbox,供 activity/audit 等房间外系统异步消费。 createdEvent, err := outbox.Build(cmd.RoomID(), "RoomCreated", roomState.Version, now, &roomeventsv1.RoomCreated{ OwnerUserId: cmd.OwnerUserID, - HostUserId: cmd.HostUserID, SeatCount: cmd.SeatCount, Mode: cmd.Mode, RoomName: cmd.RoomName, @@ -193,7 +191,6 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) AppCode: cmd.AppCode, RoomID: cmd.RoomID(), OwnerUserID: cmd.OwnerUserID, - HostUserID: cmd.HostUserID, SeatCount: cmd.SeatCount, Mode: cmd.Mode, Status: state.RoomStatusActive, diff --git a/services/room-service/internal/room/service/lifecycle.go b/services/room-service/internal/room/service/lifecycle.go index 05dd854c..7654eed7 100644 --- a/services/room-service/internal/room/service/lifecycle.go +++ b/services/room-service/internal/room/service/lifecycle.go @@ -57,7 +57,7 @@ func (s *Service) CloseRoom(ctx context.Context, req *roomv1.CloseRoomRequest) ( if current.Status != state.RoomStatusActive && current.Status != state.RoomStatusClosing { return mutationResult{}, nil, xerr.New(xerr.Conflict, "room is not active") } - if err := requireOwnerOrHostPresent(current, cmd.ActorUserID()); err != nil { + if err := requireOwnerPresent(current, cmd.ActorUserID()); err != nil { return mutationResult{}, nil, err } diff --git a/services/room-service/internal/room/service/list.go b/services/room-service/internal/room/service/list.go index 8b709932..6bc1d27d 100644 --- a/services/room-service/internal/room/service/list.go +++ b/services/room-service/internal/room/service/list.go @@ -250,7 +250,6 @@ func roomListEntryFromSnapshot(snapshot *roomv1.RoomSnapshot, visibleRegionID in RoomShortID: roomShortID, VisibleRegionID: normalizeVisibleRegionID(visibleRegionID), OwnerUserID: snapshot.GetOwnerUserId(), - HostUserID: snapshot.GetHostUserId(), Title: title, CoverURL: coverURL, Mode: snapshot.GetMode(), @@ -378,7 +377,6 @@ func roomListItemToProto(entry RoomListEntry) *roomv1.RoomListItem { RoomId: entry.RoomID, RoomShortId: entry.RoomShortID, OwnerUserId: entry.OwnerUserID, - HostUserId: entry.HostUserID, Title: entry.Title, CoverUrl: entry.CoverURL, Mode: entry.Mode, @@ -399,7 +397,6 @@ func roomListEntryFromMetaAndSnapshot(meta RoomMeta, snapshot *roomv1.RoomSnapsh RoomShortID: meta.RoomShortID, VisibleRegionID: normalizeVisibleRegionID(meta.VisibleRegionID), OwnerUserID: meta.OwnerUserID, - HostUserID: meta.HostUserID, Mode: meta.Mode, Status: meta.Status, SeatCount: meta.SeatCount, @@ -421,8 +418,5 @@ func roomListEntryFromMetaAndSnapshot(meta RoomMeta, snapshot *roomv1.RoomSnapsh if entry.OwnerUserID <= 0 { entry.OwnerUserID = meta.OwnerUserID } - if entry.HostUserID <= 0 { - entry.HostUserID = meta.HostUserID - } return entry } diff --git a/services/room-service/internal/room/service/management.go b/services/room-service/internal/room/service/management.go index 4e542bf9..4ca6a948 100644 --- a/services/room-service/internal/room/service/management.go +++ b/services/room-service/internal/room/service/management.go @@ -161,15 +161,15 @@ func (s *Service) SetRoomAdmin(ctx context.Context, req *roomv1.SetRoomAdminRequ return mutationResult{}, nil, xerr.New(xerr.InvalidArgument, "target_user_id is required") } if err := requireOwnerPresent(current, cmd.ActorUserID()); err != nil { - // 只有 owner 可以增删 admin,host/admin 不能扩张自己的权限。 + // 只有 owner 可以增删 admin,避免管理员扩张自己的权限。 return mutationResult{}, nil, err } if _, exists := current.OnlineUsers[cmd.TargetUserID]; !exists { // 首版不支持预设管理员,避免把不存在或已离房用户加入管理集合。 return mutationResult{}, nil, xerr.New(xerr.NotFound, "target not in room") } - if !cmd.Enabled && (cmd.TargetUserID == current.OwnerUserID || cmd.TargetUserID == current.HostUserID) { - // owner/host 的管理身份由专门字段决定,不能通过 admin 集合移除。 + if !cmd.Enabled && cmd.TargetUserID == current.OwnerUserID { + // owner 的管理身份由专门字段决定,不能通过 admin 集合移除。 return mutationResult{}, nil, xerr.New(xerr.PermissionDenied, "permission denied") } if current.AdminUsers[cmd.TargetUserID] == cmd.Enabled { @@ -219,74 +219,3 @@ func (s *Service) SetRoomAdmin(ctx context.Context, req *roomv1.SetRoomAdminRequ Room: result.snapshot, }, nil } - -// TransferRoomHost 转移主持人;新 host 自动进入管理员集合。 -func (s *Service) TransferRoomHost(ctx context.Context, req *roomv1.TransferRoomHostRequest) (*roomv1.TransferRoomHostResponse, error) { - ctx = contextFromMeta(ctx, req.GetMeta()) - // 主持人是独立于 admin 集合的强角色,转移必须由 owner 发起。 - cmd := command.TransferRoomHost{ - Base: baseFromMeta(req.GetMeta()), - TargetUserID: req.GetTargetUserId(), - } - - result, err := s.mutateRoom(ctx, cmd, true, func(now time.Time, current *state.RoomState, _ *rank.LocalRank) (mutationResult, []outbox.Record, error) { - if err := requireActiveRoom(current); err != nil { - return mutationResult{}, nil, err - } - if cmd.TargetUserID <= 0 { - return mutationResult{}, nil, xerr.New(xerr.InvalidArgument, "target_user_id is required") - } - if err := requireOwnerPresent(current, cmd.ActorUserID()); err != nil { - // host 不能自转移或把主持权限授予他人。 - return mutationResult{}, nil, err - } - if _, exists := current.OnlineUsers[cmd.TargetUserID]; !exists { - // 新 host 必须当前在房间 presence 内,保证交接对象可立即管理现场。 - return mutationResult{}, nil, xerr.New(xerr.NotFound, "target not in room") - } - if current.HostUserID == cmd.TargetUserID { - // 转给当前 host 不改变状态,也不重复广播。 - return mutationResult{snapshot: current.ToProto()}, nil, nil - } - - oldHostUserID := current.HostUserID - // 新 host 自动进入 AdminUsers;旧 host 是否保留 admin 由当前实现保持不变。 - current.HostUserID = cmd.TargetUserID - current.AdminUsers[cmd.TargetUserID] = true - current.Version++ - - // 主持人转移是房间管理强事件,必须进入 outbox 便于客户端和审计同步。 - hostEvent, err := outbox.Build(current.RoomID, "RoomHostTransferred", current.Version, now, &roomeventsv1.RoomHostTransferred{ - ActorUserId: cmd.ActorUserID(), - OldHostUserId: oldHostUserID, - NewHostUserId: cmd.TargetUserID, - }) - if err != nil { - return mutationResult{}, nil, err - } - - return mutationResult{ - snapshot: current.ToProto(), - syncEvent: &tencentim.RoomEvent{ - EventID: hostEvent.EventID, - RoomID: current.RoomID, - EventType: "room_host_transferred", - ActorUserID: cmd.ActorUserID(), - TargetUserID: cmd.TargetUserID, - RoomVersion: current.Version, - Attributes: map[string]string{ - "old_host_user_id": int64String(oldHostUserID), - "new_host_user_id": int64String(cmd.TargetUserID), - }, - }, - }, []outbox.Record{hostEvent}, nil - }) - if err != nil { - return nil, err - } - - return &roomv1.TransferRoomHostResponse{ - Result: commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()), - Room: result.snapshot, - }, nil -} diff --git a/services/room-service/internal/room/service/moderation.go b/services/room-service/internal/room/service/moderation.go index b7e4d2ab..473101d8 100644 --- a/services/room-service/internal/room/service/moderation.go +++ b/services/room-service/internal/room/service/moderation.go @@ -106,9 +106,6 @@ func (s *Service) KickUser(ctx context.Context, req *roomv1.KickUserRequest) (*r if cmd.TargetUserID == cmd.ActorUserID() { return mutationResult{}, nil, xerr.New(xerr.InvalidArgument, "cannot kick self") } - if cmd.TargetUserID == current.HostUserID { - return mutationResult{}, nil, xerr.New(xerr.PermissionDenied, "permission denied") - } if err := requireActorPresent(current, cmd.ActorUserID()); err != nil { return mutationResult{}, nil, err } @@ -194,7 +191,7 @@ func (s *Service) UnbanUser(ctx context.Context, req *roomv1.UnbanUserRequest) ( if cmd.TargetUserID <= 0 { return mutationResult{}, nil, xerr.New(xerr.InvalidArgument, "target_user_id is required") } - if err := requireOwnerOrHostPresent(current, cmd.ActorUserID()); err != nil { + if err := requireOwnerPresent(current, cmd.ActorUserID()); err != nil { return mutationResult{}, nil, err } if !current.BanUsers[cmd.TargetUserID] { diff --git a/services/room-service/internal/room/service/recovery.go b/services/room-service/internal/room/service/recovery.go index a3e94eb5..15e086e7 100644 --- a/services/room-service/internal/room/service/recovery.go +++ b/services/room-service/internal/room/service/recovery.go @@ -83,7 +83,7 @@ func (s *Service) recoverRoom(ctx context.Context, roomMeta RoomMeta) (*state.Ro fromVersion = snapshot.GetVersion() } else { // 没有快照时从 rooms meta 重建初始状态,再从版本 0 回放命令。 - recovered = state.NewRoomState(roomMeta.RoomID, roomMeta.OwnerUserID, roomMeta.HostUserID, roomMeta.SeatCount, roomMeta.Mode) + recovered = state.NewRoomState(roomMeta.RoomID, roomMeta.OwnerUserID, roomMeta.SeatCount, roomMeta.Mode) recovered.Status = roomMeta.Status recovered.VisibleRegionID = roomMeta.VisibleRegionID fromVersion = 0 @@ -284,16 +284,11 @@ func replay(current *state.RoomState, cmd command.Command) error { if typed.Enabled { // 管理员集合是持久权限,恢复后用户重新进房即可继续具备 admin 身份。 current.AdminUsers[typed.TargetUserID] = true - } else if typed.TargetUserID != current.OwnerUserID && typed.TargetUserID != current.HostUserID { - // owner/host 的管理身份不能被 admin 删除命令移除。 + } else if typed.TargetUserID != current.OwnerUserID { + // owner 的管理身份不能被 admin 删除命令移除。 delete(current.AdminUsers, typed.TargetUserID) } current.Version++ - case *command.TransferRoomHost: - // 新 host 自动进入管理员集合,和在线命令路径保持一致。 - current.HostUserID = typed.TargetUserID - current.AdminUsers[typed.TargetUserID] = true - current.Version++ case *command.MuteUser: if typed.Muted { // 回放禁言集合,供 CheckSpeakPermission 使用。 diff --git a/services/room-service/internal/room/service/repository.go b/services/room-service/internal/room/service/repository.go index 7724ef7b..7d7d68ed 100644 --- a/services/room-service/internal/room/service/repository.go +++ b/services/room-service/internal/room/service/repository.go @@ -17,8 +17,6 @@ type RoomMeta struct { RoomShortID string // OwnerUserID 是房间所有者,恢复无快照房间时用于重建管理员集合。 OwnerUserID int64 - // HostUserID 是主持人,恢复无快照房间时用于重建管理员集合。 - HostUserID int64 // SeatCount 是初始麦位数量,只有无快照恢复时需要它重建麦位。 SeatCount int32 // Mode 是房间模式,当前作为元数据持久化。 @@ -91,8 +89,6 @@ type RoomListEntry struct { VisibleRegionID int64 // OwnerUserID 是房间所有者,用于卡片展示和运营排查。 OwnerUserID int64 - // HostUserID 是当前主持人,用于卡片展示。 - HostUserID int64 // Title 是卡片标题;空值由客户端或后续资料聚合兜底。 Title string // CoverURL 是卡片封面;空值表示没有单独封面。 diff --git a/services/room-service/internal/room/service/service.go b/services/room-service/internal/room/service/service.go index 70159328..c3ff561a 100644 --- a/services/room-service/internal/room/service/service.go +++ b/services/room-service/internal/room/service/service.go @@ -30,6 +30,8 @@ type Config struct { PresenceStaleAfter time.Duration // MicPublishTimeout 控制 MicUp 后等待 RTC 发流确认的最长时间。 MicPublishTimeout time.Duration + // RTCUserRemover 是平台级封禁后把用户从腾讯 RTC 房间移出的外部边界。 + RTCUserRemover integration.RTCUserRemover // Clock 允许测试注入稳定时间,生产默认使用系统时钟。 Clock clock.Clock } @@ -60,6 +62,8 @@ type Service struct { syncPublisher integration.RoomEventPublisher // outboxPublisher 是补偿 worker 对外部消费者的异步投递抽象。 outboxPublisher integration.OutboxPublisher + // rtcUserRemover 在 Room Cell 提交驱逐后同步移除实时音频房连接。 + rtcUserRemover integration.RTCUserRemover // draining 表示当前节点正在下线,只允许已经进入执行链路的命令收尾。 draining atomic.Bool @@ -148,6 +152,7 @@ func New(cfg Config, directory router.Directory, repository Repository, wallet i wallet: wallet, syncPublisher: syncPublisher, outboxPublisher: outboxPublisher, + rtcUserRemover: cfg.RTCUserRemover, cells: make(map[string]*cell.RoomCell), } } diff --git a/services/room-service/internal/room/service/system_evict.go b/services/room-service/internal/room/service/system_evict.go new file mode 100644 index 00000000..0ab9dea2 --- /dev/null +++ b/services/room-service/internal/room/service/system_evict.go @@ -0,0 +1,145 @@ +package service + +import ( + "context" + "strings" + "time" + + roomeventsv1 "hyapp.local/api/proto/events/room/v1" + roomv1 "hyapp.local/api/proto/room/v1" + "hyapp/pkg/tencentim" + "hyapp/pkg/xerr" + "hyapp/services/room-service/internal/room/command" + "hyapp/services/room-service/internal/room/outbox" + "hyapp/services/room-service/internal/room/rank" + "hyapp/services/room-service/internal/room/state" +) + +const defaultSystemEvictReason = "platform_moderation" + +// SystemEvictUser removes a platform-banned or risk-blocked user from their current Room Cell. +// It deliberately bypasses room manager role checks, but still serializes through the Room Cell command log. +func (s *Service) SystemEvictUser(ctx context.Context, req *roomv1.SystemEvictUserRequest) (*roomv1.SystemEvictUserResponse, error) { + ctx = contextFromMeta(ctx, req.GetMeta()) + targetUserID := req.GetTargetUserId() + if targetUserID <= 0 { + return nil, xerr.New(xerr.InvalidArgument, "target_user_id is required") + } + + roomID := strings.TrimSpace(req.GetMeta().GetRoomId()) + if roomID == "" { + presence, exists, err := s.repository.GetCurrentRoomPresence(ctx, targetUserID) + if err != nil { + return nil, err + } + if !exists { + return &roomv1.SystemEvictUserResponse{ + HadCurrentRoom: false, + Result: commandResult(false, 0, s.clock.Now()), + }, nil + } + roomID = presence.RoomID + } + + base := baseFromMeta(req.GetMeta()) + base.Room = roomID + if base.ActorID <= 0 { + // mutateRoom requires a non-zero actor for idempotency metadata; system eviction does not use it for authorization. + base.ActorID = targetUserID + } + cmd := command.SystemEvictUser{ + Base: base, + TargetUserID: targetUserID, + OperatorUserID: req.GetOperatorUserId(), + Reason: normalizeSystemEvictReason(req.GetReason()), + BanFromRoom: req.GetBanFromRoom(), + } + + shouldKickRTC := false + result, err := s.mutateRoom(ctx, cmd, true, func(now time.Time, current *state.RoomState, _ *rank.LocalRank) (mutationResult, []outbox.Record, error) { + if err := requireActiveRoom(current); err != nil { + return mutationResult{}, nil, err + } + + _, inRoom := current.OnlineUsers[cmd.TargetUserID] + _, onSeat := current.SeatByUser(cmd.TargetUserID) + alreadyBanned := current.BanUsers[cmd.TargetUserID] + if !inRoom && !onSeat && !current.AdminUsers[cmd.TargetUserID] && (!cmd.BanFromRoom || alreadyBanned) { + // 重复系统驱逐保持幂等;没有残留状态时只返回当前快照。 + return mutationResult{snapshot: current.ToProto()}, nil, nil + } + shouldKickRTC = inRoom || onSeat + + var releasedSeatNo int32 + var releasedMicSessionID string + if seat, exists := current.SeatByUser(cmd.TargetUserID); exists { + index := current.SeatIndex(seat.SeatNo) + releasedSeatNo = seat.SeatNo + releasedMicSessionID = current.MicSeats[index].MicSessionID + current.ClearMicSession(index) + } + + delete(current.OnlineUsers, cmd.TargetUserID) + delete(current.AdminUsers, cmd.TargetUserID) + if cmd.BanFromRoom { + current.BanUsers[cmd.TargetUserID] = true + } + current.Version++ + + evictEvent, err := outbox.Build(current.RoomID, "RoomUserKicked", current.Version, now, &roomeventsv1.RoomUserKicked{ + ActorUserId: 0, + TargetUserId: cmd.TargetUserID, + }) + if err != nil { + return mutationResult{}, nil, err + } + records := make([]outbox.Record, 0, 2) + if releasedMicSessionID != "" { + micEvent, err := buildMicDownEventForSeat(current.RoomID, current.Version, now, 0, cmd.TargetUserID, releasedSeatNo, releasedMicSessionID, cmd.Reason) + if err != nil { + return mutationResult{}, nil, err + } + records = append(records, micEvent) + } + records = append(records, evictEvent) + + return mutationResult{ + snapshot: current.ToProto(), + syncEvent: &tencentim.RoomEvent{ + EventID: evictEvent.EventID, + RoomID: current.RoomID, + EventType: "room_user_kicked", + TargetUserID: cmd.TargetUserID, + RoomVersion: current.Version, + Attributes: map[string]string{"reason": cmd.Reason}, + }, + }, records, nil + }) + if err != nil { + return nil, err + } + + response := &roomv1.SystemEvictUserResponse{ + HadCurrentRoom: true, + Result: commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()), + Room: result.snapshot, + RoomId: roomID, + } + if result.applied && shouldKickRTC && s.rtcUserRemover != nil { + if err := s.rtcUserRemover.RemoveUserByStrRoomID(ctx, roomID, targetUserID); err != nil { + response.RtcKickError = err.Error() + } else { + response.RtcKicked = true + } + } + + return response, nil +} + +func normalizeSystemEvictReason(reason string) string { + reason = strings.TrimSpace(reason) + if reason == "" { + return defaultSystemEvictReason + } + return reason +} diff --git a/services/room-service/internal/room/state/state.go b/services/room-service/internal/room/state/state.go index 7e833dfd..491c7371 100644 --- a/services/room-service/internal/room/state/state.go +++ b/services/room-service/internal/room/state/state.go @@ -79,8 +79,6 @@ type RoomState struct { RoomID string // OwnerUserID 是房间所有者,进入 AdminUsers。 OwnerUserID int64 - // HostUserID 是主持人,进入 AdminUsers。 - HostUserID int64 // Mode 是房间模式,当前只作为状态字段透出。 Mode string // VisibleRegionID 是房间礼物、列表和区域可见性策略使用的区域桶。 @@ -110,7 +108,7 @@ type RoomState struct { } // NewRoomState 初始化一个空房间状态。 -func NewRoomState(roomID string, ownerUserID int64, hostUserID int64, seatCount int32, mode string) *RoomState { +func NewRoomState(roomID string, ownerUserID int64, seatCount int32, mode string) *RoomState { // 麦位编号从 1 开始,避免对外暴露 0 号麦位和切片下标。 seats := make([]MicSeat, 0, seatCount) @@ -121,16 +119,14 @@ func NewRoomState(roomID string, ownerUserID int64, hostUserID int64, seatCount return &RoomState{ RoomID: roomID, OwnerUserID: ownerUserID, - HostUserID: hostUserID, Mode: mode, Status: RoomStatusActive, ChatEnabled: true, MicSeats: seats, OnlineUsers: make(map[int64]*RoomUserState), AdminUsers: map[int64]bool{ - // owner 和 host 默认具备管理权限,后续可以扩展管理员命令。 + // owner 默认具备管理权限,后续可以扩展管理员命令。 ownerUserID: true, - hostUserID: true, }, BanUsers: make(map[int64]bool), MuteUsers: make(map[int64]bool), @@ -149,7 +145,6 @@ func (s *RoomState) Clone() *RoomState { cloned := &RoomState{ RoomID: s.RoomID, OwnerUserID: s.OwnerUserID, - HostUserID: s.HostUserID, Mode: s.Mode, VisibleRegionID: s.VisibleRegionID, Status: s.Status, @@ -287,7 +282,6 @@ func (s *RoomState) ToProto() *roomv1.RoomSnapshot { return &roomv1.RoomSnapshot{ RoomId: s.RoomID, OwnerUserId: s.OwnerUserID, - HostUserId: s.HostUserID, Mode: s.Mode, VisibleRegionId: s.VisibleRegionID, Status: s.Status, @@ -316,7 +310,6 @@ func FromProto(snapshot *roomv1.RoomSnapshot) *RoomState { restored := &RoomState{ RoomID: snapshot.GetRoomId(), OwnerUserID: snapshot.GetOwnerUserId(), - HostUserID: snapshot.GetHostUserId(), Mode: snapshot.GetMode(), VisibleRegionID: snapshot.GetVisibleRegionId(), Status: snapshot.GetStatus(), @@ -361,9 +354,8 @@ func FromProto(snapshot *roomv1.RoomSnapshot) *RoomState { // set 在 protobuf 中用数组表达,恢复时重新转为 map。 restored.AdminUsers[userID] = true } - // owner 和 host 是派生管理员身份,快照恢复后必须重新压实该不变量。 + // owner 是派生管理员身份,快照恢复后必须重新压实该不变量。 restored.AdminUsers[restored.OwnerUserID] = true - restored.AdminUsers[restored.HostUserID] = true for _, userID := range snapshot.GetBanUserIds() { restored.BanUsers[userID] = true diff --git a/services/room-service/internal/storage/mysql/repository.go b/services/room-service/internal/storage/mysql/repository.go index cfcf320a..53f3b942 100644 --- a/services/room-service/internal/storage/mysql/repository.go +++ b/services/room-service/internal/storage/mysql/repository.go @@ -76,7 +76,6 @@ func (r *Repository) Migrate(ctx context.Context) error { room_id VARCHAR(64) NOT NULL, room_short_id VARCHAR(32) NOT NULL DEFAULT '', owner_user_id BIGINT NOT NULL, - host_user_id BIGINT NOT NULL, seat_count INT NOT NULL, mode VARCHAR(64) NOT NULL, status VARCHAR(32) NOT NULL, @@ -94,7 +93,6 @@ func (r *Repository) Migrate(ctx context.Context) error { room_short_id VARCHAR(32) NOT NULL DEFAULT '', visible_region_id BIGINT NOT NULL DEFAULT 0, owner_user_id BIGINT NOT NULL, - host_user_id BIGINT NOT NULL, title VARCHAR(128) NOT NULL DEFAULT '', cover_url VARCHAR(512) NOT NULL DEFAULT '', mode VARCHAR(64) NOT NULL, @@ -258,13 +256,12 @@ func (r *Repository) SaveRoomMeta(ctx context.Context, meta roomservice.RoomMeta appCode := normalizedRecordAppCode(ctx, meta.AppCode) nowMS := time.Now().UTC().UnixMilli() _, err := r.db.ExecContext(ctx, - `INSERT INTO rooms (app_code, room_id, room_short_id, owner_user_id, host_user_id, seat_count, mode, status, visible_region_id, created_at_ms, updated_at_ms) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + `INSERT INTO rooms (app_code, room_id, room_short_id, owner_user_id, seat_count, mode, status, visible_region_id, created_at_ms, updated_at_ms) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, appCode, meta.RoomID, meta.RoomShortID, meta.OwnerUserID, - meta.HostUserID, meta.SeatCount, meta.Mode, meta.Status, @@ -280,7 +277,7 @@ func (r *Repository) SaveRoomMeta(ctx context.Context, meta roomservice.RoomMeta func (r *Repository) GetRoomMeta(ctx context.Context, roomID string) (roomservice.RoomMeta, bool, error) { // meta 是无内存 Cell 恢复的入口;不存在时上层返回 room not found。 row := r.db.QueryRowContext(ctx, - `SELECT app_code, room_id, room_short_id, owner_user_id, host_user_id, seat_count, mode, status, visible_region_id + `SELECT app_code, room_id, room_short_id, owner_user_id, seat_count, mode, status, visible_region_id FROM rooms WHERE app_code = ? AND room_id = ?`, appcode.FromContext(ctx), @@ -288,7 +285,7 @@ func (r *Repository) GetRoomMeta(ctx context.Context, roomID string) (roomservic ) var meta roomservice.RoomMeta - if err := row.Scan(&meta.AppCode, &meta.RoomID, &meta.RoomShortID, &meta.OwnerUserID, &meta.HostUserID, &meta.SeatCount, &meta.Mode, &meta.Status, &meta.VisibleRegionID); err != nil { + if err := row.Scan(&meta.AppCode, &meta.RoomID, &meta.RoomShortID, &meta.OwnerUserID, &meta.SeatCount, &meta.Mode, &meta.Status, &meta.VisibleRegionID); err != nil { if errors.Is(err, sql.ErrNoRows) { // 未创建房间不是数据库错误,用 exists=false 表达。 return roomservice.RoomMeta{}, false, nil @@ -304,7 +301,7 @@ func (r *Repository) GetRoomMeta(ctx context.Context, roomID string) (roomservic func (r *Repository) GetRoomMetaByOwner(ctx context.Context, ownerUserID int64) (roomservice.RoomMeta, bool, error) { // rooms.owner_user_id 有唯一约束,查询最多返回一条;该读路径用于 CreateRoom 前置失败。 row := r.db.QueryRowContext(ctx, - `SELECT app_code, room_id, room_short_id, owner_user_id, host_user_id, seat_count, mode, status, visible_region_id + `SELECT app_code, room_id, room_short_id, owner_user_id, seat_count, mode, status, visible_region_id FROM rooms WHERE app_code = ? AND owner_user_id = ? LIMIT 1`, @@ -313,7 +310,7 @@ func (r *Repository) GetRoomMetaByOwner(ctx context.Context, ownerUserID int64) ) var meta roomservice.RoomMeta - if err := row.Scan(&meta.AppCode, &meta.RoomID, &meta.RoomShortID, &meta.OwnerUserID, &meta.HostUserID, &meta.SeatCount, &meta.Mode, &meta.Status, &meta.VisibleRegionID); err != nil { + if err := row.Scan(&meta.AppCode, &meta.RoomID, &meta.RoomShortID, &meta.OwnerUserID, &meta.SeatCount, &meta.Mode, &meta.Status, &meta.VisibleRegionID); err != nil { if errors.Is(err, sql.ErrNoRows) { return roomservice.RoomMeta{}, false, nil } @@ -893,14 +890,13 @@ func (r *Repository) UpsertRoomListEntry(ctx context.Context, entry roomservice. appCode := normalizedRecordAppCode(ctx, entry.AppCode) _, err := r.db.ExecContext(ctx, `INSERT INTO room_list_entries ( - app_code, room_id, room_short_id, visible_region_id, owner_user_id, host_user_id, title, cover_url, mode, status, + app_code, room_id, room_short_id, visible_region_id, owner_user_id, title, cover_url, mode, status, heat, online_count, seat_count, occupied_seat_count, sort_score, created_at_ms, updated_at_ms - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE room_short_id = VALUES(room_short_id), visible_region_id = VALUES(visible_region_id), owner_user_id = VALUES(owner_user_id), - host_user_id = VALUES(host_user_id), title = VALUES(title), cover_url = VALUES(cover_url), mode = VALUES(mode), @@ -916,7 +912,6 @@ func (r *Repository) UpsertRoomListEntry(ctx context.Context, entry roomservice. entry.RoomShortID, entry.VisibleRegionID, entry.OwnerUserID, - entry.HostUserID, entry.Title, entry.CoverURL, entry.Mode, @@ -956,7 +951,6 @@ func (r *Repository) ListRoomListEntries(ctx context.Context, query roomservice. &entry.RoomShortID, &entry.VisibleRegionID, &entry.OwnerUserID, - &entry.HostUserID, &entry.Title, &entry.CoverURL, &entry.Mode, @@ -1023,7 +1017,6 @@ func (r *Repository) ListRoomUserFeedEntries(ctx context.Context, query roomserv &entry.RoomShortID, &entry.VisibleRegionID, &entry.OwnerUserID, - &entry.HostUserID, &entry.Title, &entry.CoverURL, &entry.Mode, @@ -1075,7 +1068,6 @@ func (r *Repository) ListRoomRelatedFeedEntries(ctx context.Context, query rooms &entry.RoomShortID, &entry.VisibleRegionID, &entry.OwnerUserID, - &entry.HostUserID, &entry.Title, &entry.CoverURL, &entry.Mode, @@ -1117,12 +1109,12 @@ func (r *Repository) ListRoomRelatedFeedEntries(ctx context.Context, query rooms } const roomListSelectColumns = ` - SELECT app_code, room_id, room_short_id, visible_region_id, owner_user_id, host_user_id, title, cover_url, mode, status, + SELECT app_code, room_id, room_short_id, visible_region_id, owner_user_id, title, cover_url, mode, status, heat, online_count, seat_count, occupied_seat_count, sort_score, created_at_ms, updated_at_ms FROM room_list_entries` const roomUserFeedSelectColumns = ` - SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_user_id, r.host_user_id, r.title, r.cover_url, r.mode, r.status, + SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.heat, r.online_count, r.seat_count, r.occupied_seat_count, r.sort_score, r.created_at_ms, f.updated_at_ms FROM room_user_feed_entries f JOIN room_list_entries r ON r.app_code = f.app_code AND r.room_id = f.room_id` @@ -1183,8 +1175,7 @@ func buildRoomRelatedFeedQuerySQL(query roomservice.RoomRelatedFeedQuery, relati relatedIDs = append(relatedIDs, userID) } inClause := strings.Join(placeholders, ",") - where = append(where, "(owner_user_id IN ("+inClause+") OR host_user_id IN ("+inClause+"))") - args = append(args, relatedIDs...) + where = append(where, "owner_user_id IN ("+inClause+")") args = append(args, relatedIDs...) if strings.TrimSpace(query.Query) != "" { @@ -1222,7 +1213,6 @@ func relatedFeedSortKey(entry roomservice.RoomListEntry, relations map[int64]int } } choose(entry.OwnerUserID) - choose(entry.HostUserID) return bestUserID, bestUpdatedAtMS } diff --git a/services/room-service/internal/transport/grpc/server.go b/services/room-service/internal/transport/grpc/server.go index 1c518fd9..cbbec4df 100644 --- a/services/room-service/internal/transport/grpc/server.go +++ b/services/room-service/internal/transport/grpc/server.go @@ -240,18 +240,6 @@ func (s *Server) SetRoomAdmin(ctx context.Context, req *roomv1.SetRoomAdminReque return mapServiceResult(s.svc.SetRoomAdmin(ctx, req)) } -// TransferRoomHost 代理到领域服务。 -func (s *Server) TransferRoomHost(ctx context.Context, req *roomv1.TransferRoomHostRequest) (*roomv1.TransferRoomHostResponse, error) { - // 主持人转移由 Room Cell 串行提交,并进入 command log/outbox。 - ctx = contextWithMetaApp(ctx, req.GetMeta()) - if resp, forwarded, err := forwardCommand(s, ctx, req.GetMeta(), func(callCtx context.Context, client roomv1.RoomCommandServiceClient) (*roomv1.TransferRoomHostResponse, error) { - return client.TransferRoomHost(callCtx, req) - }); forwarded { - return resp, err - } - return mapServiceResult(s.svc.TransferRoomHost(ctx, req)) -} - // MuteUser 代理到领域服务。 func (s *Server) MuteUser(ctx context.Context, req *roomv1.MuteUserRequest) (*roomv1.MuteUserResponse, error) { // 禁言状态是腾讯云 IM 发言回调的权威来源。 @@ -288,6 +276,18 @@ func (s *Server) UnbanUser(ctx context.Context, req *roomv1.UnbanUserRequest) (* return mapServiceResult(s.svc.UnbanUser(ctx, req)) } +// SystemEvictUser 代理到领域服务。 +func (s *Server) SystemEvictUser(ctx context.Context, req *roomv1.SystemEvictUserRequest) (*roomv1.SystemEvictUserResponse, error) { + // 系统驱逐由平台封禁或风控触发,仍必须经 Room Cell 串行提交。 + ctx = contextWithMetaApp(ctx, req.GetMeta()) + if resp, forwarded, err := forwardCommand(s, ctx, req.GetMeta(), func(callCtx context.Context, client roomv1.RoomCommandServiceClient) (*roomv1.SystemEvictUserResponse, error) { + return client.SystemEvictUser(callCtx, req) + }); forwarded { + return resp, err + } + return mapServiceResult(s.svc.SystemEvictUser(ctx, req)) +} + // SendGift 代理到领域服务。 func (s *Server) SendGift(ctx context.Context, req *roomv1.SendGiftRequest) (*roomv1.SendGiftResponse, error) { // SendGift 先同步扣费,成功后才更新房间热度和本地榜。 diff --git a/services/user-service/configs/config.docker.yaml b/services/user-service/configs/config.docker.yaml index b23b316a..5cf35fc5 100644 --- a/services/user-service/configs/config.docker.yaml +++ b/services/user-service/configs/config.docker.yaml @@ -46,6 +46,23 @@ login_risk: provider_timeout_ms: 800 providers: - "edge_country" +room_service: + enabled: true + addr: "room-service:13001" + request_timeout_ms: 3000 +activity_service: + enabled: true + addr: "activity-service:13006" + request_timeout_ms: 3000 +tencent_im: + # Docker 本地默认关闭真实腾讯 IM 账号踢下线;开启后必须和 gateway/room 使用同一个 IM 应用。 + enabled: false + sdk_app_id: 0 + secret_key: "" + admin_identifier: "administrator" + admin_user_sig_ttl_sec: 86400 + endpoint: "console.tim.qq.com" + request_timeout_ms: 5000 jwt: issuer: "hyapp" access_token_ttl_sec: 1800 diff --git a/services/user-service/configs/config.tencent.example.yaml b/services/user-service/configs/config.tencent.example.yaml index 47d88b96..a03095e2 100644 --- a/services/user-service/configs/config.tencent.example.yaml +++ b/services/user-service/configs/config.tencent.example.yaml @@ -49,6 +49,24 @@ login_risk: - "primary_geo" - "fallback_geo_a" - "fallback_geo_b" +room_service: + enabled: true + addr: "room-service.internal:13001" + request_timeout_ms: 3000 +activity_service: + enabled: true + addr: "activity-service.internal:13006" + request_timeout_ms: 3000 +tencent_im: + # 线上开启后,用户封禁会同步调用腾讯云 IM 账号踢下线。 + enabled: true + # 必须和 gateway-service/room-service 使用同一个 IM 应用。 + sdk_app_id: 1400000000 + secret_key: "TENCENT_IM_SECRET_KEY" + admin_identifier: "administrator" + admin_user_sig_ttl_sec: 86400 + endpoint: "adminapisgp.im.qcloud.com" + request_timeout_ms: 5000 jwt: issuer: "hyapp" access_token_ttl_sec: 1800 diff --git a/services/user-service/configs/config.yaml b/services/user-service/configs/config.yaml index 56ef7269..1146ce99 100644 --- a/services/user-service/configs/config.yaml +++ b/services/user-service/configs/config.yaml @@ -46,6 +46,23 @@ login_risk: provider_timeout_ms: 800 providers: - "edge_country" +room_service: + enabled: true + addr: "127.0.0.1:13001" + request_timeout_ms: 3000 +activity_service: + enabled: true + addr: "127.0.0.1:13006" + request_timeout_ms: 3000 +tencent_im: + # 本地默认关闭真实腾讯 IM 账号踢下线;开启后必须和 gateway/room 使用同一个 IM 应用。 + enabled: false + sdk_app_id: 0 + secret_key: "" + admin_identifier: "administrator" + admin_user_sig_ttl_sec: 86400 + endpoint: "console.tim.qq.com" + request_timeout_ms: 5000 jwt: issuer: "hyapp" access_token_ttl_sec: 1800 diff --git a/services/user-service/deploy/data/countries.json b/services/user-service/deploy/data/countries.json index 8248e319..8e231574 100644 --- a/services/user-service/deploy/data/countries.json +++ b/services/user-service/deploy/data/countries.json @@ -1,8 +1,8 @@ { "schema_version": 1, "country_code_standard": "ISO 3166-1 alpha-2 for country_code; XK is retained as a user-assigned code because the source dataset includes it for product coverage.", - "total": 250, - "official_iso_3166_1_total": 249, + "total": 218, + "official_iso_3166_1_total": 217, "user_assigned_total": 1, "sources": [ { @@ -77,21 +77,6 @@ "status": "active", "sort_order": 30 }, - { - "country_name": "Antigua and Barbuda", - "country_code": "AG", - "country_display_name": "安提瓜和巴布达", - "iso_alpha3": "ATG", - "iso_numeric": "028", - "phone_country_code": "+1", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "🇦🇬", - "status": "active", - "sort_order": 40 - }, { "country_name": "Anguilla", "country_code": "AI", @@ -152,21 +137,6 @@ "status": "active", "sort_order": 80 }, - { - "country_name": "Antarctica", - "country_code": "AQ", - "country_display_name": "南极洲", - "iso_alpha3": "ATA", - "iso_numeric": "010", - "phone_country_code": null, - "region": "Antarctic", - "region_display_name": "南极洲", - "subregion": "", - "subregion_display_name": "", - "flag": "🇦🇶", - "status": "active", - "sort_order": 90 - }, { "country_name": "Argentina", "country_code": "AR", @@ -182,21 +152,6 @@ "status": "active", "sort_order": 100 }, - { - "country_name": "American Samoa", - "country_code": "AS", - "country_display_name": "美属萨摩亚", - "iso_alpha3": "ASM", - "iso_numeric": "016", - "phone_country_code": "+1", - "region": "Oceania", - "region_display_name": "大洋洲", - "subregion": "Polynesia", - "subregion_display_name": "波利尼西亚", - "flag": "🇦🇸", - "status": "active", - "sort_order": 110 - }, { "country_name": "Austria", "country_code": "AT", @@ -272,21 +227,6 @@ "status": "active", "sort_order": 160 }, - { - "country_name": "Bosnia and Herzegovina", - "country_code": "BA", - "country_display_name": "波斯尼亚和黑塞哥维那", - "iso_alpha3": "BIH", - "iso_numeric": "070", - "phone_country_code": "+387", - "region": "Europe", - "region_display_name": "欧洲", - "subregion": "Southeast Europe", - "subregion_display_name": "东南欧", - "flag": "🇧🇦", - "status": "active", - "sort_order": 170 - }, { "country_name": "Barbados", "country_code": "BB", @@ -467,21 +407,6 @@ "status": "active", "sort_order": 290 }, - { - "country_name": "Caribbean Netherlands", - "country_code": "BQ", - "country_display_name": "荷蘭加勒比區", - "iso_alpha3": "BES", - "iso_numeric": "535", - "phone_country_code": "+599", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "", - "status": "active", - "sort_order": 300 - }, { "country_name": "Brazil", "country_code": "BR", @@ -692,21 +617,6 @@ "status": "active", "sort_order": 440 }, - { - "country_name": "Cook Islands", - "country_code": "CK", - "country_display_name": "库克群岛", - "iso_alpha3": "COK", - "iso_numeric": "184", - "phone_country_code": "+682", - "region": "Oceania", - "region_display_name": "大洋洲", - "subregion": "Polynesia", - "subregion_display_name": "波利尼西亚", - "flag": "🇨🇰", - "status": "active", - "sort_order": 450 - }, { "country_name": "Chile", "country_code": "CL", @@ -1007,21 +917,6 @@ "status": "active", "sort_order": 650 }, - { - "country_name": "Western Sahara", - "country_code": "EH", - "country_display_name": "西撒哈拉", - "iso_alpha3": "ESH", - "iso_numeric": "732", - "phone_country_code": "+212", - "region": "Africa", - "region_display_name": "非洲", - "subregion": "Northern Africa", - "subregion_display_name": "北非", - "flag": "🇪🇭", - "status": "active", - "sort_order": 660 - }, { "country_name": "Eritrea", "country_code": "ER", @@ -1097,21 +992,6 @@ "status": "active", "sort_order": 710 }, - { - "country_name": "Falkland Islands", - "country_code": "FK", - "country_display_name": "福克兰群岛", - "iso_alpha3": "FLK", - "iso_numeric": "238", - "phone_country_code": "+500", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "South America", - "subregion_display_name": "南美洲", - "flag": "🇫🇰", - "status": "active", - "sort_order": 720 - }, { "country_name": "Micronesia", "country_code": "FM", @@ -1127,21 +1007,6 @@ "status": "active", "sort_order": 730 }, - { - "country_name": "Faroe Islands", - "country_code": "FO", - "country_display_name": "法罗群岛", - "iso_alpha3": "FRO", - "iso_numeric": "234", - "phone_country_code": "+298", - "region": "Europe", - "region_display_name": "欧洲", - "subregion": "Northern Europe", - "subregion_display_name": "北欧", - "flag": "🇫🇴", - "status": "active", - "sort_order": 740 - }, { "country_name": "France", "country_code": "FR", @@ -1322,21 +1187,6 @@ "status": "active", "sort_order": 860 }, - { - "country_name": "Guadeloupe", - "country_code": "GP", - "country_display_name": "瓜德罗普岛", - "iso_alpha3": "GLP", - "iso_numeric": "312", - "phone_country_code": "+590", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "🇬🇵", - "status": "active", - "sort_order": 870 - }, { "country_name": "Equatorial Guinea", "country_code": "GQ", @@ -1412,21 +1262,6 @@ "status": "active", "sort_order": 920 }, - { - "country_name": "Guinea-Bissau", - "country_code": "GW", - "country_display_name": "几内亚比绍", - "iso_alpha3": "GNB", - "iso_numeric": "624", - "phone_country_code": "+245", - "region": "Africa", - "region_display_name": "非洲", - "subregion": "Western Africa", - "subregion_display_name": "西非", - "flag": "🇬🇼", - "status": "active", - "sort_order": 930 - }, { "country_name": "Guyana", "country_code": "GY", @@ -1442,36 +1277,6 @@ "status": "active", "sort_order": 940 }, - { - "country_name": "Hong Kong", - "country_code": "HK", - "country_display_name": "中国香港", - "iso_alpha3": "HKG", - "iso_numeric": "344", - "phone_country_code": "+852", - "region": "Asia", - "region_display_name": "亚洲", - "subregion": "Eastern Asia", - "subregion_display_name": "东亚", - "flag": "🇭🇰", - "status": "active", - "sort_order": 950 - }, - { - "country_name": "Heard Island and McDonald Islands", - "country_code": "HM", - "country_display_name": "赫德岛和麦当劳群岛", - "iso_alpha3": "HMD", - "iso_numeric": "334", - "phone_country_code": null, - "region": "Antarctic", - "region_display_name": "南极洲", - "subregion": "", - "subregion_display_name": "", - "flag": "🇭🇲", - "status": "active", - "sort_order": 960 - }, { "country_name": "Honduras", "country_code": "HN", @@ -1607,21 +1412,6 @@ "status": "active", "sort_order": 1050 }, - { - "country_name": "British Indian Ocean Territory", - "country_code": "IO", - "country_display_name": "英属印度洋领地", - "iso_alpha3": "IOT", - "iso_numeric": "086", - "phone_country_code": "+246", - "region": "Africa", - "region_display_name": "非洲", - "subregion": "Eastern Africa", - "subregion_display_name": "东非", - "flag": "🇮🇴", - "status": "active", - "sort_order": 1060 - }, { "country_name": "Iraq", "country_code": "IQ", @@ -1817,21 +1607,6 @@ "status": "active", "sort_order": 1190 }, - { - "country_name": "Saint Kitts and Nevis", - "country_code": "KN", - "country_display_name": "圣基茨和尼维斯", - "iso_alpha3": "KNA", - "iso_numeric": "659", - "phone_country_code": "+1", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "🇰🇳", - "status": "active", - "sort_order": 1200 - }, { "country_name": "North Korea", "country_code": "KP", @@ -2162,36 +1937,6 @@ "status": "active", "sort_order": 1420 }, - { - "country_name": "Marshall Islands", - "country_code": "MH", - "country_display_name": "马绍尔群岛", - "iso_alpha3": "MHL", - "iso_numeric": "584", - "phone_country_code": "+692", - "region": "Oceania", - "region_display_name": "大洋洲", - "subregion": "Micronesia", - "subregion_display_name": "密克罗尼西亚", - "flag": "🇲🇭", - "status": "active", - "sort_order": 1430 - }, - { - "country_name": "North Macedonia", - "country_code": "MK", - "country_display_name": "北馬其頓", - "iso_alpha3": "MKD", - "iso_numeric": "807", - "phone_country_code": "+389", - "region": "Europe", - "region_display_name": "欧洲", - "subregion": "Southeast Europe", - "subregion_display_name": "东南欧", - "flag": "🇲🇰", - "status": "active", - "sort_order": 1440 - }, { "country_name": "Mali", "country_code": "ML", @@ -2252,21 +1997,6 @@ "status": "active", "sort_order": 1480 }, - { - "country_name": "Northern Mariana Islands", - "country_code": "MP", - "country_display_name": "北马里亚纳群岛", - "iso_alpha3": "MNP", - "iso_numeric": "580", - "phone_country_code": "+1", - "region": "Oceania", - "region_display_name": "大洋洲", - "subregion": "Micronesia", - "subregion_display_name": "密克罗尼西亚", - "flag": "🇲🇵", - "status": "active", - "sort_order": 1490 - }, { "country_name": "Martinique", "country_code": "MQ", @@ -2642,36 +2372,6 @@ "status": "active", "sort_order": 1740 }, - { - "country_name": "French Polynesia", - "country_code": "PF", - "country_display_name": "法属波利尼西亚", - "iso_alpha3": "PYF", - "iso_numeric": "258", - "phone_country_code": "+689", - "region": "Oceania", - "region_display_name": "大洋洲", - "subregion": "Polynesia", - "subregion_display_name": "波利尼西亚", - "flag": "🇵🇫", - "status": "active", - "sort_order": 1750 - }, - { - "country_name": "Papua New Guinea", - "country_code": "PG", - "country_display_name": "巴布亚新几内亚", - "iso_alpha3": "PNG", - "iso_numeric": "598", - "phone_country_code": "+675", - "region": "Oceania", - "region_display_name": "大洋洲", - "subregion": "Melanesia", - "subregion_display_name": "美拉尼西亚", - "flag": "🇵🇬", - "status": "active", - "sort_order": 1760 - }, { "country_name": "Philippines", "country_code": "PH", @@ -2717,36 +2417,6 @@ "status": "active", "sort_order": 1790 }, - { - "country_name": "Saint Pierre and Miquelon", - "country_code": "PM", - "country_display_name": "圣皮埃尔和密克隆", - "iso_alpha3": "SPM", - "iso_numeric": "666", - "phone_country_code": "+508", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "North America", - "subregion_display_name": "北美洲", - "flag": "🇵🇲", - "status": "active", - "sort_order": 1800 - }, - { - "country_name": "Pitcairn Islands", - "country_code": "PN", - "country_display_name": "皮特凯恩群岛", - "iso_alpha3": "PCN", - "iso_numeric": "612", - "phone_country_code": null, - "region": "Oceania", - "region_display_name": "大洋洲", - "subregion": "Polynesia", - "subregion_display_name": "波利尼西亚", - "flag": "🇵🇳", - "status": "active", - "sort_order": 1810 - }, { "country_name": "Puerto Rico", "country_code": "PR", @@ -3002,21 +2672,6 @@ "status": "active", "sort_order": 1980 }, - { - "country_name": "Saint Helena, Ascension and Tristan da Cunha", - "country_code": "SH", - "country_display_name": "圣赫勒拿、阿森松和特里斯坦-达库尼亚", - "iso_alpha3": "SHN", - "iso_numeric": "654", - "phone_country_code": "+290", - "region": "Africa", - "region_display_name": "非洲", - "subregion": "Western Africa", - "subregion_display_name": "西非", - "flag": "🇸🇭", - "status": "active", - "sort_order": 1990 - }, { "country_name": "Slovenia", "country_code": "SI", @@ -3152,21 +2807,6 @@ "status": "active", "sort_order": 2080 }, - { - "country_name": "São Tomé and Príncipe", - "country_code": "ST", - "country_display_name": "圣多美和普林西比", - "iso_alpha3": "STP", - "iso_numeric": "678", - "phone_country_code": "+239", - "region": "Africa", - "region_display_name": "非洲", - "subregion": "Middle Africa", - "subregion_display_name": "中非", - "flag": "🇸🇹", - "status": "active", - "sort_order": 2090 - }, { "country_name": "El Salvador", "country_code": "SV", @@ -3227,21 +2867,6 @@ "status": "active", "sort_order": 2130 }, - { - "country_name": "Turks and Caicos Islands", - "country_code": "TC", - "country_display_name": "特克斯和凯科斯群岛", - "iso_alpha3": "TCA", - "iso_numeric": "796", - "phone_country_code": "+1", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "🇹🇨", - "status": "active", - "sort_order": 2140 - }, { "country_name": "Chad", "country_code": "TD", @@ -3257,21 +2882,6 @@ "status": "active", "sort_order": 2150 }, - { - "country_name": "French Southern and Antarctic Lands", - "country_code": "TF", - "country_display_name": "法国南部和南极土地", - "iso_alpha3": "ATF", - "iso_numeric": "260", - "phone_country_code": null, - "region": "Antarctic", - "region_display_name": "南极洲", - "subregion": "", - "subregion_display_name": "", - "flag": "🇹🇫", - "status": "active", - "sort_order": 2160 - }, { "country_name": "Togo", "country_code": "TG", @@ -3407,21 +3017,6 @@ "status": "active", "sort_order": 2250 }, - { - "country_name": "Trinidad and Tobago", - "country_code": "TT", - "country_display_name": "特立尼达和多巴哥", - "iso_alpha3": "TTO", - "iso_numeric": "780", - "phone_country_code": "+1", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "🇹🇹", - "status": "active", - "sort_order": 2260 - }, { "country_name": "Tuvalu", "country_code": "TV", @@ -3497,21 +3092,6 @@ "status": "active", "sort_order": 2310 }, - { - "country_name": "United States Minor Outlying Islands", - "country_code": "UM", - "country_display_name": "美国本土外小岛屿", - "iso_alpha3": "UMI", - "iso_numeric": "581", - "phone_country_code": null, - "region": "Americas", - "region_display_name": "美洲", - "subregion": "North America", - "subregion_display_name": "北美洲", - "flag": "🇺🇲", - "status": "active", - "sort_order": 2320 - }, { "country_name": "United States", "country_code": "US", @@ -3572,21 +3152,6 @@ "status": "active", "sort_order": 2360 }, - { - "country_name": "Saint Vincent and the Grenadines", - "country_code": "VC", - "country_display_name": "圣文森特和格林纳丁斯", - "iso_alpha3": "VCT", - "iso_numeric": "670", - "phone_country_code": "+1", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "🇻🇨", - "status": "active", - "sort_order": 2370 - }, { "country_name": "Venezuela", "country_code": "VE", @@ -3602,36 +3167,6 @@ "status": "active", "sort_order": 2380 }, - { - "country_name": "British Virgin Islands", - "country_code": "VG", - "country_display_name": "英属维尔京群岛", - "iso_alpha3": "VGB", - "iso_numeric": "092", - "phone_country_code": "+1", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "🇻🇬", - "status": "active", - "sort_order": 2390 - }, - { - "country_name": "United States Virgin Islands", - "country_code": "VI", - "country_display_name": "美属维尔京群岛", - "iso_alpha3": "VIR", - "iso_numeric": "850", - "phone_country_code": "+1", - "region": "Americas", - "region_display_name": "美洲", - "subregion": "Caribbean", - "subregion_display_name": "加勒比地区", - "flag": "🇻🇮", - "status": "active", - "sort_order": 2400 - }, { "country_name": "Vietnam", "country_code": "VN", @@ -3662,21 +3197,6 @@ "status": "active", "sort_order": 2420 }, - { - "country_name": "Wallis and Futuna", - "country_code": "WF", - "country_display_name": "瓦利斯和富图纳群岛", - "iso_alpha3": "WLF", - "iso_numeric": "876", - "phone_country_code": "+681", - "region": "Oceania", - "region_display_name": "大洋洲", - "subregion": "Polynesia", - "subregion_display_name": "波利尼西亚", - "flag": "🇼🇫", - "status": "active", - "sort_order": 2430 - }, { "country_name": "Samoa", "country_code": "WS", diff --git a/services/user-service/deploy/mysql/initdb/001_user_service.sql b/services/user-service/deploy/mysql/initdb/001_user_service.sql index e7909a47..ae2a2114 100644 --- a/services/user-service/deploy/mysql/initdb/001_user_service.sql +++ b/services/user-service/deploy/mysql/initdb/001_user_service.sql @@ -127,6 +127,23 @@ CREATE TABLE IF NOT EXISTS user_friendships ( KEY idx_user_friendships_friend_status (app_code, friend_user_id, status, updated_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE IF NOT EXISTS user_status_change_logs ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + target_user_id BIGINT NOT NULL, + old_status VARCHAR(32) NOT NULL, + new_status VARCHAR(32) NOT NULL, + operator_type VARCHAR(32) NOT NULL, + operator_user_id BIGINT NOT NULL DEFAULT 0, + reason VARCHAR(128) NOT NULL DEFAULT '', + request_id VARCHAR(96) NOT NULL DEFAULT '', + created_at_ms BIGINT NOT NULL, + KEY idx_user_status_logs_target (app_code, target_user_id, created_at_ms), + KEY idx_user_status_logs_status (app_code, new_status, created_at_ms), + KEY idx_user_status_logs_operator (app_code, operator_type, operator_user_id, created_at_ms), + KEY idx_user_status_logs_request (app_code, request_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CREATE TABLE IF NOT EXISTS display_user_id_sequences ( app_code VARCHAR(32) NOT NULL PRIMARY KEY, next_value BIGINT NOT NULL, @@ -608,20 +625,16 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Andorra', 'AD', 'AND', '020', '安道尔', '+376', '🇦🇩', TRUE, 10, 0, 0), ('United Arab Emirates', 'AE', 'ARE', '784', '阿拉伯联合酋长国', '+971', '🇦🇪', TRUE, 20, 0, 0), ('Afghanistan', 'AF', 'AFG', '004', '阿富汗', '+93', '🇦🇫', TRUE, 30, 0, 0), - ('Antigua and Barbuda', 'AG', 'ATG', '028', '安提瓜和巴布达', '+1', '🇦🇬', TRUE, 40, 0, 0), ('Anguilla', 'AI', 'AIA', '660', '安圭拉', '+1', '🇦🇮', TRUE, 50, 0, 0), ('Albania', 'AL', 'ALB', '008', '阿尔巴尼亚', '+355', '🇦🇱', TRUE, 60, 0, 0), ('Armenia', 'AM', 'ARM', '051', '亚美尼亚', '+374', '🇦🇲', TRUE, 70, 0, 0), ('Angola', 'AO', 'AGO', '024', '安哥拉', '+244', '🇦🇴', TRUE, 80, 0, 0), - ('Antarctica', 'AQ', 'ATA', '010', '南极洲', NULL, '🇦🇶', TRUE, 90, 0, 0), ('Argentina', 'AR', 'ARG', '032', '阿根廷', '+54', '🇦🇷', TRUE, 100, 0, 0), - ('American Samoa', 'AS', 'ASM', '016', '美属萨摩亚', '+1', '🇦🇸', TRUE, 110, 0, 0), ('Austria', 'AT', 'AUT', '040', '奥地利', '+43', '🇦🇹', TRUE, 120, 0, 0), ('Australia', 'AU', 'AUS', '036', '澳大利亚', '+61', '🇦🇺', TRUE, 130, 0, 0), ('Aruba', 'AW', 'ABW', '533', '阿鲁巴', '+297', '🇦🇼', TRUE, 140, 0, 0), ('Åland Islands', 'AX', 'ALA', '248', '奥兰群岛', '+358', '🇦🇽', TRUE, 150, 0, 0), ('Azerbaijan', 'AZ', 'AZE', '031', '阿塞拜疆', '+994', '🇦🇿', TRUE, 160, 0, 0), - ('Bosnia and Herzegovina', 'BA', 'BIH', '070', '波斯尼亚和黑塞哥维那', '+387', '🇧🇦', TRUE, 170, 0, 0), ('Barbados', 'BB', 'BRB', '052', '巴巴多斯', '+1', '🇧🇧', TRUE, 180, 0, 0), ('Bangladesh', 'BD', 'BGD', '050', '孟加拉国', '+880', '🇧🇩', TRUE, 190, 0, 0), ('Belgium', 'BE', 'BEL', '056', '比利时', '+32', '🇧🇪', TRUE, 200, 0, 0), @@ -634,7 +647,6 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Bermuda', 'BM', 'BMU', '060', '百慕大', '+1', '🇧🇲', TRUE, 270, 0, 0), ('Brunei', 'BN', 'BRN', '096', '文莱', '+673', '🇧🇳', TRUE, 280, 0, 0), ('Bolivia', 'BO', 'BOL', '068', '玻利维亚', '+591', '🇧🇴', TRUE, 290, 0, 0), - ('Caribbean Netherlands', 'BQ', 'BES', '535', '荷蘭加勒比區', '+599', '', TRUE, 300, 0, 0), ('Brazil', 'BR', 'BRA', '076', '巴西', '+55', '🇧🇷', TRUE, 310, 0, 0), ('Bahamas', 'BS', 'BHS', '044', '巴哈马', '+1', '🇧🇸', TRUE, 320, 0, 0), ('Bhutan', 'BT', 'BTN', '064', '不丹', '+975', '🇧🇹', TRUE, 330, 0, 0), @@ -649,7 +661,6 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Congo', 'CG', 'COG', '178', '刚果', '+242', '🇨🇬', TRUE, 420, 0, 0), ('Switzerland', 'CH', 'CHE', '756', '瑞士', '+41', '🇨🇭', TRUE, 430, 0, 0), ('Ivory Coast', 'CI', 'CIV', '384', '科特迪瓦', '+225', '🇨🇮', TRUE, 440, 0, 0), - ('Cook Islands', 'CK', 'COK', '184', '库克群岛', '+682', '🇨🇰', TRUE, 450, 0, 0), ('Chile', 'CL', 'CHL', '152', '智利', '+56', '🇨🇱', TRUE, 460, 0, 0), ('Cameroon', 'CM', 'CMR', '120', '喀麦隆', '+237', '🇨🇲', TRUE, 470, 0, 0), ('China', 'CN', 'CHN', '156', '中国', '+86', '🇨🇳', TRUE, 480, 0, 0), @@ -670,15 +681,12 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Ecuador', 'EC', 'ECU', '218', '厄瓜多尔', '+593', '🇪🇨', TRUE, 630, 0, 0), ('Estonia', 'EE', 'EST', '233', '爱沙尼亚', '+372', '🇪🇪', TRUE, 640, 0, 0), ('Egypt', 'EG', 'EGY', '818', '埃及', '+20', '🇪🇬', TRUE, 650, 0, 0), - ('Western Sahara', 'EH', 'ESH', '732', '西撒哈拉', '+212', '🇪🇭', TRUE, 660, 0, 0), ('Eritrea', 'ER', 'ERI', '232', '厄立特里亚', '+291', '🇪🇷', TRUE, 670, 0, 0), ('Spain', 'ES', 'ESP', '724', '西班牙', '+34', '🇪🇸', TRUE, 680, 0, 0), ('Ethiopia', 'ET', 'ETH', '231', '埃塞俄比亚', '+251', '🇪🇹', TRUE, 690, 0, 0), ('Finland', 'FI', 'FIN', '246', '芬兰', '+358', '🇫🇮', TRUE, 700, 0, 0), ('Fiji', 'FJ', 'FJI', '242', '斐济', '+679', '🇫🇯', TRUE, 710, 0, 0), - ('Falkland Islands', 'FK', 'FLK', '238', '福克兰群岛', '+500', '🇫🇰', TRUE, 720, 0, 0), ('Micronesia', 'FM', 'FSM', '583', '密克罗尼西亚', '+691', '🇫🇲', TRUE, 730, 0, 0), - ('Faroe Islands', 'FO', 'FRO', '234', '法罗群岛', '+298', '🇫🇴', TRUE, 740, 0, 0), ('France', 'FR', 'FRA', '250', '法国', '+33', '🇫🇷', TRUE, 750, 0, 0), ('Gabon', 'GA', 'GAB', '266', '加蓬', '+241', '🇬🇦', TRUE, 760, 0, 0), ('United Kingdom', 'GB', 'GBR', '826', '英国', '+44', '🇬🇧', TRUE, 770, 0, 0), @@ -691,16 +699,12 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Greenland', 'GL', 'GRL', '304', '格陵兰', '+299', '🇬🇱', TRUE, 840, 0, 0), ('Gambia', 'GM', 'GMB', '270', '冈比亚', '+220', '🇬🇲', TRUE, 850, 0, 0), ('Guinea', 'GN', 'GIN', '324', '几内亚', '+224', '🇬🇳', TRUE, 860, 0, 0), - ('Guadeloupe', 'GP', 'GLP', '312', '瓜德罗普岛', '+590', '🇬🇵', TRUE, 870, 0, 0), ('Equatorial Guinea', 'GQ', 'GNQ', '226', '赤道几内亚', '+240', '🇬🇶', TRUE, 880, 0, 0), ('Greece', 'GR', 'GRC', '300', '希腊', '+30', '🇬🇷', TRUE, 890, 0, 0), ('South Georgia', 'GS', 'SGS', '239', '南乔治亚', NULL, '🇬🇸', TRUE, 900, 0, 0), ('Guatemala', 'GT', 'GTM', '320', '危地马拉', '+502', '🇬🇹', TRUE, 910, 0, 0), ('Guam', 'GU', 'GUM', '316', '关岛', '+1', '🇬🇺', TRUE, 920, 0, 0), - ('Guinea-Bissau', 'GW', 'GNB', '624', '几内亚比绍', '+245', '🇬🇼', TRUE, 930, 0, 0), ('Guyana', 'GY', 'GUY', '328', '圭亚那', '+592', '🇬🇾', TRUE, 940, 0, 0), - ('Hong Kong', 'HK', 'HKG', '344', '中国香港', '+852', '🇭🇰', TRUE, 950, 0, 0), - ('Heard Island and McDonald Islands', 'HM', 'HMD', '334', '赫德岛和麦当劳群岛', NULL, '🇭🇲', TRUE, 960, 0, 0), ('Honduras', 'HN', 'HND', '340', '洪都拉斯', '+504', '🇭🇳', TRUE, 970, 0, 0), ('Croatia', 'HR', 'HRV', '191', '克罗地亚', '+385', '🇭🇷', TRUE, 980, 0, 0), ('Haiti', 'HT', 'HTI', '332', '海地', '+509', '🇭🇹', TRUE, 990, 0, 0), @@ -710,7 +714,6 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Israel', 'IL', 'ISR', '376', '以色列', '+972', '🇮🇱', TRUE, 1030, 0, 0), ('Isle of Man', 'IM', 'IMN', '833', '马恩岛', '+44', '🇮🇲', TRUE, 1040, 0, 0), ('India', 'IN', 'IND', '356', '印度', '+91', '🇮🇳', TRUE, 1050, 0, 0), - ('British Indian Ocean Territory', 'IO', 'IOT', '086', '英属印度洋领地', '+246', '🇮🇴', TRUE, 1060, 0, 0), ('Iraq', 'IQ', 'IRQ', '368', '伊拉克', '+964', '🇮🇶', TRUE, 1070, 0, 0), ('Iran', 'IR', 'IRN', '364', '伊朗', '+98', '🇮🇷', TRUE, 1080, 0, 0), ('Iceland', 'IS', 'ISL', '352', '冰岛', '+354', '🇮🇸', TRUE, 1090, 0, 0), @@ -724,7 +727,6 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Cambodia', 'KH', 'KHM', '116', '柬埔寨', '+855', '🇰🇭', TRUE, 1170, 0, 0), ('Kiribati', 'KI', 'KIR', '296', '基里巴斯', '+686', '🇰🇮', TRUE, 1180, 0, 0), ('Comoros', 'KM', 'COM', '174', '科摩罗', '+269', '🇰🇲', TRUE, 1190, 0, 0), - ('Saint Kitts and Nevis', 'KN', 'KNA', '659', '圣基茨和尼维斯', '+1', '🇰🇳', TRUE, 1200, 0, 0), ('North Korea', 'KP', 'PRK', '408', '朝鲜', '+850', '🇰🇵', TRUE, 1210, 0, 0), ('South Korea', 'KR', 'KOR', '410', '韩国', '+82', '🇰🇷', TRUE, 1220, 0, 0), ('Kuwait', 'KW', 'KWT', '414', '科威特', '+965', '🇰🇼', TRUE, 1230, 0, 0), @@ -747,13 +749,10 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Montenegro', 'ME', 'MNE', '499', '黑山', '+382', '🇲🇪', TRUE, 1400, 0, 0), ('Saint Martin', 'MF', 'MAF', '663', '圣马丁', '+590', '🇲🇫', TRUE, 1410, 0, 0), ('Madagascar', 'MG', 'MDG', '450', '马达加斯加', '+261', '🇲🇬', TRUE, 1420, 0, 0), - ('Marshall Islands', 'MH', 'MHL', '584', '马绍尔群岛', '+692', '🇲🇭', TRUE, 1430, 0, 0), - ('North Macedonia', 'MK', 'MKD', '807', '北馬其頓', '+389', '🇲🇰', TRUE, 1440, 0, 0), ('Mali', 'ML', 'MLI', '466', '马里', '+223', '🇲🇱', TRUE, 1450, 0, 0), ('Myanmar', 'MM', 'MMR', '104', '缅甸', '+95', '🇲🇲', TRUE, 1460, 0, 0), ('Mongolia', 'MN', 'MNG', '496', '蒙古', '+976', '🇲🇳', TRUE, 1470, 0, 0), ('Macao', 'MO', 'MAC', '446', '中国澳门', '+853', '🇲🇴', TRUE, 1480, 0, 0), - ('Northern Mariana Islands', 'MP', 'MNP', '580', '北马里亚纳群岛', '+1', '🇲🇵', TRUE, 1490, 0, 0), ('Martinique', 'MQ', 'MTQ', '474', '马提尼克', '+596', '🇲🇶', TRUE, 1500, 0, 0), ('Mauritania', 'MR', 'MRT', '478', '毛里塔尼亚', '+222', '🇲🇷', TRUE, 1510, 0, 0), ('Montserrat', 'MS', 'MSR', '500', '蒙特塞拉特', '+1', '🇲🇸', TRUE, 1520, 0, 0), @@ -779,13 +778,9 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Oman', 'OM', 'OMN', '512', '阿曼', '+968', '🇴🇲', TRUE, 1720, 0, 0), ('Panama', 'PA', 'PAN', '591', '巴拿马', '+507', '🇵🇦', TRUE, 1730, 0, 0), ('Peru', 'PE', 'PER', '604', '秘鲁', '+51', '🇵🇪', TRUE, 1740, 0, 0), - ('French Polynesia', 'PF', 'PYF', '258', '法属波利尼西亚', '+689', '🇵🇫', TRUE, 1750, 0, 0), - ('Papua New Guinea', 'PG', 'PNG', '598', '巴布亚新几内亚', '+675', '🇵🇬', TRUE, 1760, 0, 0), ('Philippines', 'PH', 'PHL', '608', '菲律宾', '+63', '🇵🇭', TRUE, 1770, 0, 0), ('Pakistan', 'PK', 'PAK', '586', '巴基斯坦', '+92', '🇵🇰', TRUE, 1780, 0, 0), ('Poland', 'PL', 'POL', '616', '波兰', '+48', '🇵🇱', TRUE, 1790, 0, 0), - ('Saint Pierre and Miquelon', 'PM', 'SPM', '666', '圣皮埃尔和密克隆', '+508', '🇵🇲', TRUE, 1800, 0, 0), - ('Pitcairn Islands', 'PN', 'PCN', '612', '皮特凯恩群岛', NULL, '🇵🇳', TRUE, 1810, 0, 0), ('Puerto Rico', 'PR', 'PRI', '630', '波多黎各', '+1', '🇵🇷', TRUE, 1820, 0, 0), ('Palestine', 'PS', 'PSE', '275', '巴勒斯坦', '+970', '🇵🇸', TRUE, 1830, 0, 0), ('Portugal', 'PT', 'PRT', '620', '葡萄牙', '+351', '🇵🇹', TRUE, 1840, 0, 0), @@ -803,7 +798,6 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Sudan', 'SD', 'SDN', '729', '苏丹', '+249', '🇸🇩', TRUE, 1960, 0, 0), ('Sweden', 'SE', 'SWE', '752', '瑞典', '+46', '🇸🇪', TRUE, 1970, 0, 0), ('Singapore', 'SG', 'SGP', '702', '新加坡', '+65', '🇸🇬', TRUE, 1980, 0, 0), - ('Saint Helena, Ascension and Tristan da Cunha', 'SH', 'SHN', '654', '圣赫勒拿、阿森松和特里斯坦-达库尼亚', '+290', '🇸🇭', TRUE, 1990, 0, 0), ('Slovenia', 'SI', 'SVN', '705', '斯洛文尼亚', '+386', '🇸🇮', TRUE, 2000, 0, 0), ('Svalbard and Jan Mayen', 'SJ', 'SJM', '744', '斯瓦尔巴特', '+47', '🇸🇯', TRUE, 2010, 0, 0), ('Slovakia', 'SK', 'SVK', '703', '斯洛伐克', '+421', '🇸🇰', TRUE, 2020, 0, 0), @@ -813,14 +807,11 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Somalia', 'SO', 'SOM', '706', '索马里', '+252', '🇸🇴', TRUE, 2060, 0, 0), ('Suriname', 'SR', 'SUR', '740', '苏里南', '+597', '🇸🇷', TRUE, 2070, 0, 0), ('South Sudan', 'SS', 'SSD', '728', '南苏丹', '+211', '🇸🇸', TRUE, 2080, 0, 0), - ('São Tomé and Príncipe', 'ST', 'STP', '678', '圣多美和普林西比', '+239', '🇸🇹', TRUE, 2090, 0, 0), ('El Salvador', 'SV', 'SLV', '222', '萨尔瓦多', '+503', '🇸🇻', TRUE, 2100, 0, 0), ('Sint Maarten', 'SX', 'SXM', '534', '圣马丁岛', '+1', '🇸🇽', TRUE, 2110, 0, 0), ('Syria', 'SY', 'SYR', '760', '叙利亚', '+963', '🇸🇾', TRUE, 2120, 0, 0), ('Eswatini', 'SZ', 'SWZ', '748', '斯威士兰', '+268', '🇸🇿', TRUE, 2130, 0, 0), - ('Turks and Caicos Islands', 'TC', 'TCA', '796', '特克斯和凯科斯群岛', '+1', '🇹🇨', TRUE, 2140, 0, 0), ('Chad', 'TD', 'TCD', '148', '乍得', '+235', '🇹🇩', TRUE, 2150, 0, 0), - ('French Southern and Antarctic Lands', 'TF', 'ATF', '260', '法国南部和南极土地', NULL, '🇹🇫', TRUE, 2160, 0, 0), ('Togo', 'TG', 'TGO', '768', '多哥', '+228', '🇹🇬', TRUE, 2170, 0, 0), ('Thailand', 'TH', 'THA', '764', '泰国', '+66', '🇹🇭', TRUE, 2180, 0, 0), ('Tajikistan', 'TJ', 'TJK', '762', '塔吉克斯坦', '+992', '🇹🇯', TRUE, 2190, 0, 0), @@ -830,26 +821,20 @@ INSERT INTO countries (country_name, country_code, iso_alpha3, iso_numeric, coun ('Tunisia', 'TN', 'TUN', '788', '突尼斯', '+216', '🇹🇳', TRUE, 2230, 0, 0), ('Tonga', 'TO', 'TON', '776', '汤加', '+676', '🇹🇴', TRUE, 2240, 0, 0), ('Türkiye', 'TR', 'TUR', '792', '土耳其', '+90', '🇹🇷', TRUE, 2250, 0, 0), - ('Trinidad and Tobago', 'TT', 'TTO', '780', '特立尼达和多巴哥', '+1', '🇹🇹', TRUE, 2260, 0, 0), ('Tuvalu', 'TV', 'TUV', '798', '图瓦卢', '+688', '🇹🇻', TRUE, 2270, 0, 0), ('Taiwan', 'TW', 'TWN', '158', '中国台湾', '+886', '🇹🇼', TRUE, 2280, 0, 0), ('Tanzania', 'TZ', 'TZA', '834', '坦桑尼亚', '+255', '🇹🇿', TRUE, 2290, 0, 0), ('Ukraine', 'UA', 'UKR', '804', '乌克兰', '+380', '🇺🇦', TRUE, 2300, 0, 0), ('Uganda', 'UG', 'UGA', '800', '乌干达', '+256', '🇺🇬', TRUE, 2310, 0, 0), - ('United States Minor Outlying Islands', 'UM', 'UMI', '581', '美国本土外小岛屿', NULL, '🇺🇲', TRUE, 2320, 0, 0), ('United States', 'US', 'USA', '840', '美国', '+1', '🇺🇸', TRUE, 2330, 0, 0), ('Uruguay', 'UY', 'URY', '858', '乌拉圭', '+598', '🇺🇾', TRUE, 2340, 0, 0), ('Uzbekistan', 'UZ', 'UZB', '860', '乌兹别克斯坦', '+998', '🇺🇿', TRUE, 2350, 0, 0), ('Vatican City', 'VA', 'VAT', '336', '梵蒂冈', '+39', '🇻🇦', TRUE, 2360, 0, 0), - ('Saint Vincent and the Grenadines', 'VC', 'VCT', '670', '圣文森特和格林纳丁斯', '+1', '🇻🇨', TRUE, 2370, 0, 0), ('Venezuela', 'VE', 'VEN', '862', '委内瑞拉', '+58', '🇻🇪', TRUE, 2380, 0, 0), - ('British Virgin Islands', 'VG', 'VGB', '092', '英属维尔京群岛', '+1', '🇻🇬', TRUE, 2390, 0, 0), - ('United States Virgin Islands', 'VI', 'VIR', '850', '美属维尔京群岛', '+1', '🇻🇮', TRUE, 2400, 0, 0), ('Vietnam', 'VN', 'VNM', '704', '越南', '+84', '🇻🇳', TRUE, 2410, 0, 0), ('Vanuatu', 'VU', 'VUT', '548', '瓦努阿图', '+678', '🇻🇺', TRUE, 2420, 0, 0), - ('Wallis and Futuna', 'WF', 'WLF', '876', '瓦利斯和富图纳群岛', '+681', '🇼🇫', TRUE, 2430, 0, 0), ('Samoa', 'WS', 'WSM', '882', '萨摩亚', '+685', '🇼🇸', TRUE, 2440, 0, 0), - ('Kosovo', 'XK', 'UNK', NULL, '科索沃', '+383', '🇽🇰', TRUE, 2450, 0, 0), + ('Kosovo', 'XK', 'UNK', '', '科索沃', '+383', '🇽🇰', TRUE, 2450, 0, 0), ('Yemen', 'YE', 'YEM', '887', '也门', '+967', '🇾🇪', TRUE, 2460, 0, 0), ('Mayotte', 'YT', 'MYT', '175', '马约特', '+262', '🇾🇹', TRUE, 2470, 0, 0), ('South Africa', 'ZA', 'ZAF', '710', '南非', '+27', '🇿🇦', TRUE, 2480, 0, 0), @@ -901,8 +886,6 @@ FROM ( UNION ALL SELECT 'AF' AS country_code, 'Southern Asia' AS region_code UNION ALL - SELECT 'AG' AS country_code, 'Caribbean' AS region_code - UNION ALL SELECT 'AI' AS country_code, 'Caribbean' AS region_code UNION ALL SELECT 'AL' AS country_code, 'Southeast Europe' AS region_code @@ -911,12 +894,8 @@ FROM ( UNION ALL SELECT 'AO' AS country_code, 'Middle Africa' AS region_code UNION ALL - SELECT 'AQ' AS country_code, 'UNSPECIFIED' AS region_code - UNION ALL SELECT 'AR' AS country_code, 'South America' AS region_code UNION ALL - SELECT 'AS' AS country_code, 'Polynesia' AS region_code - UNION ALL SELECT 'AT' AS country_code, 'Central Europe' AS region_code UNION ALL SELECT 'AU' AS country_code, 'Australia and New Zealand' AS region_code @@ -927,8 +906,6 @@ FROM ( UNION ALL SELECT 'AZ' AS country_code, 'Western Asia' AS region_code UNION ALL - SELECT 'BA' AS country_code, 'Southeast Europe' AS region_code - UNION ALL SELECT 'BB' AS country_code, 'Caribbean' AS region_code UNION ALL SELECT 'BD' AS country_code, 'Southern Asia' AS region_code @@ -953,8 +930,6 @@ FROM ( UNION ALL SELECT 'BO' AS country_code, 'South America' AS region_code UNION ALL - SELECT 'BQ' AS country_code, 'Caribbean' AS region_code - UNION ALL SELECT 'BR' AS country_code, 'South America' AS region_code UNION ALL SELECT 'BS' AS country_code, 'Caribbean' AS region_code @@ -983,8 +958,6 @@ FROM ( UNION ALL SELECT 'CI' AS country_code, 'Western Africa' AS region_code UNION ALL - SELECT 'CK' AS country_code, 'Polynesia' AS region_code - UNION ALL SELECT 'CL' AS country_code, 'South America' AS region_code UNION ALL SELECT 'CM' AS country_code, 'Middle Africa' AS region_code @@ -1025,8 +998,6 @@ FROM ( UNION ALL SELECT 'EG' AS country_code, 'Northern Africa' AS region_code UNION ALL - SELECT 'EH' AS country_code, 'Northern Africa' AS region_code - UNION ALL SELECT 'ER' AS country_code, 'Eastern Africa' AS region_code UNION ALL SELECT 'ES' AS country_code, 'Southern Europe' AS region_code @@ -1037,12 +1008,8 @@ FROM ( UNION ALL SELECT 'FJ' AS country_code, 'Melanesia' AS region_code UNION ALL - SELECT 'FK' AS country_code, 'South America' AS region_code - UNION ALL SELECT 'FM' AS country_code, 'Micronesia' AS region_code UNION ALL - SELECT 'FO' AS country_code, 'Northern Europe' AS region_code - UNION ALL SELECT 'FR' AS country_code, 'Western Europe' AS region_code UNION ALL SELECT 'GA' AS country_code, 'Middle Africa' AS region_code @@ -1067,8 +1034,6 @@ FROM ( UNION ALL SELECT 'GN' AS country_code, 'Western Africa' AS region_code UNION ALL - SELECT 'GP' AS country_code, 'Caribbean' AS region_code - UNION ALL SELECT 'GQ' AS country_code, 'Middle Africa' AS region_code UNION ALL SELECT 'GR' AS country_code, 'Southern Europe' AS region_code @@ -1079,14 +1044,8 @@ FROM ( UNION ALL SELECT 'GU' AS country_code, 'Micronesia' AS region_code UNION ALL - SELECT 'GW' AS country_code, 'Western Africa' AS region_code - UNION ALL SELECT 'GY' AS country_code, 'South America' AS region_code UNION ALL - SELECT 'HK' AS country_code, 'Eastern Asia' AS region_code - UNION ALL - SELECT 'HM' AS country_code, 'UNSPECIFIED' AS region_code - UNION ALL SELECT 'HN' AS country_code, 'Central America' AS region_code UNION ALL SELECT 'HR' AS country_code, 'Southeast Europe' AS region_code @@ -1105,8 +1064,6 @@ FROM ( UNION ALL SELECT 'IN' AS country_code, 'Southern Asia' AS region_code UNION ALL - SELECT 'IO' AS country_code, 'Eastern Africa' AS region_code - UNION ALL SELECT 'IQ' AS country_code, 'Western Asia' AS region_code UNION ALL SELECT 'IR' AS country_code, 'Southern Asia' AS region_code @@ -1133,8 +1090,6 @@ FROM ( UNION ALL SELECT 'KM' AS country_code, 'Eastern Africa' AS region_code UNION ALL - SELECT 'KN' AS country_code, 'Caribbean' AS region_code - UNION ALL SELECT 'KP' AS country_code, 'Eastern Asia' AS region_code UNION ALL SELECT 'KR' AS country_code, 'Eastern Asia' AS region_code @@ -1179,10 +1134,6 @@ FROM ( UNION ALL SELECT 'MG' AS country_code, 'Eastern Africa' AS region_code UNION ALL - SELECT 'MH' AS country_code, 'Micronesia' AS region_code - UNION ALL - SELECT 'MK' AS country_code, 'Southeast Europe' AS region_code - UNION ALL SELECT 'ML' AS country_code, 'Western Africa' AS region_code UNION ALL SELECT 'MM' AS country_code, 'South-Eastern Asia' AS region_code @@ -1191,8 +1142,6 @@ FROM ( UNION ALL SELECT 'MO' AS country_code, 'Eastern Asia' AS region_code UNION ALL - SELECT 'MP' AS country_code, 'Micronesia' AS region_code - UNION ALL SELECT 'MQ' AS country_code, 'Caribbean' AS region_code UNION ALL SELECT 'MR' AS country_code, 'Western Africa' AS region_code @@ -1243,20 +1192,12 @@ FROM ( UNION ALL SELECT 'PE' AS country_code, 'South America' AS region_code UNION ALL - SELECT 'PF' AS country_code, 'Polynesia' AS region_code - UNION ALL - SELECT 'PG' AS country_code, 'Melanesia' AS region_code - UNION ALL SELECT 'PH' AS country_code, 'South-Eastern Asia' AS region_code UNION ALL SELECT 'PK' AS country_code, 'Southern Asia' AS region_code UNION ALL SELECT 'PL' AS country_code, 'Central Europe' AS region_code UNION ALL - SELECT 'PM' AS country_code, 'North America' AS region_code - UNION ALL - SELECT 'PN' AS country_code, 'Polynesia' AS region_code - UNION ALL SELECT 'PR' AS country_code, 'Caribbean' AS region_code UNION ALL SELECT 'PS' AS country_code, 'Western Asia' AS region_code @@ -1291,8 +1232,6 @@ FROM ( UNION ALL SELECT 'SG' AS country_code, 'South-Eastern Asia' AS region_code UNION ALL - SELECT 'SH' AS country_code, 'Western Africa' AS region_code - UNION ALL SELECT 'SI' AS country_code, 'Central Europe' AS region_code UNION ALL SELECT 'SJ' AS country_code, 'Northern Europe' AS region_code @@ -1311,8 +1250,6 @@ FROM ( UNION ALL SELECT 'SS' AS country_code, 'Middle Africa' AS region_code UNION ALL - SELECT 'ST' AS country_code, 'Middle Africa' AS region_code - UNION ALL SELECT 'SV' AS country_code, 'Central America' AS region_code UNION ALL SELECT 'SX' AS country_code, 'Caribbean' AS region_code @@ -1321,12 +1258,8 @@ FROM ( UNION ALL SELECT 'SZ' AS country_code, 'Southern Africa' AS region_code UNION ALL - SELECT 'TC' AS country_code, 'Caribbean' AS region_code - UNION ALL SELECT 'TD' AS country_code, 'Middle Africa' AS region_code UNION ALL - SELECT 'TF' AS country_code, 'UNSPECIFIED' AS region_code - UNION ALL SELECT 'TG' AS country_code, 'Western Africa' AS region_code UNION ALL SELECT 'TH' AS country_code, 'South-Eastern Asia' AS region_code @@ -1345,8 +1278,6 @@ FROM ( UNION ALL SELECT 'TR' AS country_code, 'Western Asia' AS region_code UNION ALL - SELECT 'TT' AS country_code, 'Caribbean' AS region_code - UNION ALL SELECT 'TV' AS country_code, 'Polynesia' AS region_code UNION ALL SELECT 'TW' AS country_code, 'Eastern Asia' AS region_code @@ -1357,8 +1288,6 @@ FROM ( UNION ALL SELECT 'UG' AS country_code, 'Eastern Africa' AS region_code UNION ALL - SELECT 'UM' AS country_code, 'North America' AS region_code - UNION ALL SELECT 'US' AS country_code, 'North America' AS region_code UNION ALL SELECT 'UY' AS country_code, 'South America' AS region_code @@ -1367,20 +1296,12 @@ FROM ( UNION ALL SELECT 'VA' AS country_code, 'Southern Europe' AS region_code UNION ALL - SELECT 'VC' AS country_code, 'Caribbean' AS region_code - UNION ALL SELECT 'VE' AS country_code, 'South America' AS region_code UNION ALL - SELECT 'VG' AS country_code, 'Caribbean' AS region_code - UNION ALL - SELECT 'VI' AS country_code, 'Caribbean' AS region_code - UNION ALL SELECT 'VN' AS country_code, 'South-Eastern Asia' AS region_code UNION ALL SELECT 'VU' AS country_code, 'Melanesia' AS region_code UNION ALL - SELECT 'WF' AS country_code, 'Polynesia' AS region_code - UNION ALL SELECT 'WS' AS country_code, 'Polynesia' AS region_code UNION ALL SELECT 'XK' AS country_code, 'Southeast Europe' AS region_code @@ -1403,6 +1324,15 @@ ON DUPLICATE KEY UPDATE status = VALUES(status), updated_at_ms = VALUES(updated_at_ms); +-- Product-excluded countries are hard removed so reapplying initdb updates existing local databases as well as fresh volumes. +DELETE FROM region_countries +WHERE app_code = 'lalu' + AND country_code IN ('AG', 'AQ', 'AS', 'BA', 'BQ', 'CK', 'EH', 'FK', 'FO', 'GP', 'GW', 'HK', 'HM', 'IO', 'KN', 'MH', 'MK', 'MP', 'PF', 'PG', 'PM', 'PN', 'SH', 'ST', 'TC', 'TF', 'TT', 'UM', 'VC', 'VG', 'VI', 'WF'); + +DELETE FROM countries +WHERE app_code = 'lalu' + AND country_code IN ('AG', 'AQ', 'AS', 'BA', 'BQ', 'CK', 'EH', 'FK', 'FO', 'GP', 'GW', 'HK', 'HM', 'IO', 'KN', 'MH', 'MK', 'MP', 'PF', 'PG', 'PM', 'PN', 'SH', 'ST', 'TC', 'TF', 'TT', 'UM', 'VC', 'VG', 'VI', 'WF'); + CREATE TABLE IF NOT EXISTS user_display_user_ids ( app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, diff --git a/services/user-service/internal/app/app.go b/services/user-service/internal/app/app.go index 5c51724b..46f72f3e 100644 --- a/services/user-service/internal/app/app.go +++ b/services/user-service/internal/app/app.go @@ -10,12 +10,16 @@ import ( "time" userv1 "hyapp.local/api/proto/user/v1" + "hyapp/pkg/grpcclient" "hyapp/pkg/grpchealth" "hyapp/pkg/grpcshutdown" "hyapp/pkg/healthhttp" "hyapp/pkg/idgen" "hyapp/pkg/logx" + "hyapp/pkg/tencentim" "hyapp/services/user-service/internal/config" + "hyapp/services/user-service/internal/integration/activityclient" + "hyapp/services/user-service/internal/integration/roomclient" authservice "hyapp/services/user-service/internal/service/auth" hostservice "hyapp/services/user-service/internal/service/host" inviteservice "hyapp/services/user-service/internal/service/invite" @@ -46,6 +50,10 @@ type App struct { walletDB *sql.DB // roomDB 只用于读取 room_outbox 麦位事实,Room Cell 状态仍由 room-service owner。 roomDB *sql.DB + // roomConn 是低频平台治理调用 room-service 的 gRPC 连接。 + roomConn *grpc.ClientConn + // activityConn 是注册完成后触发注册奖励的 gRPC 连接。 + activityConn *grpc.ClientConn // userSvc 持有用户主数据用例,cron RPC 复用它消费区域重算任务。 userSvc *userservice.Service // authSvc 持有认证、登录 session 和登录 IP 风控用例。 @@ -118,6 +126,54 @@ func New(cfg config.Config) (*App, error) { logx.Warn(startupCtx, "login_risk_redis_unavailable") } } + var imLoginKicker userservice.IMLoginKicker + if cfg.TencentIM.Enabled { + imClient, err := tencentim.NewRESTClient(cfg.TencentIM.RESTConfig()) + if err != nil { + if loginRiskRedisClose != nil { + _ = loginRiskRedisClose() + } + _ = listener.Close() + _ = mysqlRepo.Close() + return nil, err + } + imLoginKicker = imClient + } + var roomConn *grpc.ClientConn + var roomEvictor userservice.RoomEvictor + if cfg.RoomService.Enabled { + roomConn, err = grpcclient.Dial(cfg.RoomService.Addr, grpcclient.Config{ + DefaultTimeout: time.Duration(cfg.RoomService.RequestTimeoutMs) * time.Millisecond, + }) + if err != nil { + if loginRiskRedisClose != nil { + _ = loginRiskRedisClose() + } + _ = listener.Close() + _ = mysqlRepo.Close() + return nil, err + } + roomEvictor = roomclient.NewGRPC(roomConn) + } + var activityConn *grpc.ClientConn + var registrationRewardIssuer authservice.RegistrationRewardIssuer + if cfg.ActivityService.Enabled { + activityConn, err = grpcclient.Dial(cfg.ActivityService.Addr, grpcclient.Config{ + DefaultTimeout: time.Duration(cfg.ActivityService.RequestTimeoutMs) * time.Millisecond, + }) + if err != nil { + if loginRiskRedisClose != nil { + _ = loginRiskRedisClose() + } + if roomConn != nil { + _ = roomConn.Close() + } + _ = listener.Close() + _ = mysqlRepo.Close() + return nil, err + } + registrationRewardIssuer = activityclient.NewGRPC(activityConn) + } // auth service 负责登录、session 和 token;用户主数据和短号事务仍通过各自领域存储完成。 authSvc := authservice.New(authservice.Config{ @@ -146,6 +202,7 @@ func New(cfg config.Config) (*App, error) { }), authservice.WithIPDecisionCache(ipDecisionCache), authservice.WithIPGeoProviders(authservice.BuildIPGeoProviders(cfg.LoginRisk.Providers)), + authservice.WithRegistrationRewardIssuer(registrationRewardIssuer), ) // user service 负责用户主状态和 display_user_id/靓号用例,不进入房间高频流程。 userSvc := userservice.New(userRepo, @@ -156,6 +213,10 @@ func New(cfg config.Config) (*App, error) { userservice.WithRegionAdminRepository(regionRepo), userservice.WithRegionRebuildRepository(regionRepo), userservice.WithDeviceRepository(deviceRepo), + userservice.WithModerationRepository(userRepo), + userservice.WithSessionDenylist(ipDecisionCache, time.Duration(cfg.JWT.AccessTokenTTLSec+60)*time.Second), + userservice.WithIMLoginKicker(imLoginKicker), + userservice.WithRoomEvictor(roomEvictor), userservice.WithIDGenerator(idgen.NewInt64Generator(cfg.IDGenerator.NodeID)), userservice.WithDisplayUserIDPolicy(cfg.DisplayUserID.AllocateMaxAttempts, time.Duration(cfg.DisplayUserID.ChangeCooldownSec)*time.Second), ) @@ -170,6 +231,12 @@ func New(cfg config.Config) (*App, error) { if loginRiskRedisClose != nil { _ = loginRiskRedisClose() } + if roomConn != nil { + _ = roomConn.Close() + } + if activityConn != nil { + _ = activityConn.Close() + } _ = listener.Close() _ = mysqlRepo.Close() return nil, err @@ -179,6 +246,12 @@ func New(cfg config.Config) (*App, error) { if loginRiskRedisClose != nil { _ = loginRiskRedisClose() } + if roomConn != nil { + _ = roomConn.Close() + } + if activityConn != nil { + _ = activityConn.Close() + } _ = listener.Close() _ = mysqlRepo.Close() return nil, err @@ -196,6 +269,12 @@ func New(cfg config.Config) (*App, error) { if loginRiskRedisClose != nil { _ = loginRiskRedisClose() } + if roomConn != nil { + _ = roomConn.Close() + } + if activityConn != nil { + _ = activityConn.Close() + } _ = listener.Close() _ = mysqlRepo.Close() return nil, err @@ -208,6 +287,12 @@ func New(cfg config.Config) (*App, error) { if loginRiskRedisClose != nil { _ = loginRiskRedisClose() } + if roomConn != nil { + _ = roomConn.Close() + } + if activityConn != nil { + _ = activityConn.Close() + } _ = listener.Close() _ = mysqlRepo.Close() return nil, err @@ -260,6 +345,12 @@ func New(cfg config.Config) (*App, error) { if loginRiskRedisClose != nil { _ = loginRiskRedisClose() } + if roomConn != nil { + _ = roomConn.Close() + } + if activityConn != nil { + _ = activityConn.Close() + } _ = listener.Close() _ = mysqlRepo.Close() return nil, err @@ -274,6 +365,8 @@ func New(cfg config.Config) (*App, error) { mysqlRepo: mysqlRepo, walletDB: walletDB, roomDB: roomDB, + roomConn: roomConn, + activityConn: activityConn, authSvc: authSvc, userSvc: userSvc, inviteSvc: inviteSvc, @@ -346,6 +439,12 @@ func (a *App) Close() { if a.roomDB != nil { _ = a.roomDB.Close() } + if a.roomConn != nil { + _ = a.roomConn.Close() + } + if a.activityConn != nil { + _ = a.activityConn.Close() + } if a.loginRiskRedisClose != nil { _ = a.loginRiskRedisClose() } diff --git a/services/user-service/internal/config/config.go b/services/user-service/internal/config/config.go index b2a8bab0..d78e421f 100644 --- a/services/user-service/internal/config/config.go +++ b/services/user-service/internal/config/config.go @@ -2,10 +2,13 @@ package config import ( + "net/http" "strings" + "time" "hyapp/pkg/configx" "hyapp/pkg/logx" + "hyapp/pkg/tencentim" ) // Config 描述 user-service 启动配置。 @@ -36,6 +39,12 @@ type Config struct { MicTimeWorker MicTimeWorkerConfig `yaml:"mic_time_worker"` // LoginRisk 控制登录后 IP 风控策略、Redis session denylist 和 IP 查询 provider。 LoginRisk LoginRiskConfig `yaml:"login_risk"` + // RoomService 是封禁后驱逐当前房间用户的内部 gRPC 依赖。 + RoomService RoomServiceConfig `yaml:"room_service"` + // ActivityService 是注册成功后发放注册奖励的内部 gRPC 依赖。 + ActivityService ActivityServiceConfig `yaml:"activity_service"` + // TencentIM 是封禁后失效用户 IM 登录态的外部集成配置。 + TencentIM TencentIMConfig `yaml:"tencent_im"` // JWT 控制 access token 和 refresh session 的签发参数。 JWT JWTConfig `yaml:"jwt"` // Log 控制 stdout 结构化日志格式、等级和 access body 策略。 @@ -56,6 +65,52 @@ type LoginRiskConfig struct { Providers []string `yaml:"providers"` } +// RoomServiceConfig 保存 user-service 到 room-service 的低频治理 RPC 连接参数。 +type RoomServiceConfig struct { + Enabled bool `yaml:"enabled"` + Addr string `yaml:"addr"` + RequestTimeoutMs int64 `yaml:"request_timeout_ms"` +} + +// ActivityServiceConfig 保存 user-service 到 activity-service 的低频注册奖励 RPC 连接参数。 +type ActivityServiceConfig struct { + Enabled bool `yaml:"enabled"` + Addr string `yaml:"addr"` + RequestTimeoutMs int64 `yaml:"request_timeout_ms"` +} + +// TencentIMConfig 描述 user-service 调用腾讯云 IM REST API 的账号级治理配置。 +type TencentIMConfig struct { + Enabled bool `yaml:"enabled"` + SDKAppID int64 `yaml:"sdk_app_id"` + SecretKey string `yaml:"secret_key"` + AdminIdentifier string `yaml:"admin_identifier"` + AdminUserSigTTLSec int64 `yaml:"admin_user_sig_ttl_sec"` + Endpoint string `yaml:"endpoint"` + RequestTimeoutMs int64 `yaml:"request_timeout_ms"` +} + +// RESTConfig 转换成 pkg/tencentim REST client 配置。 +func (c TencentIMConfig) RESTConfig() tencentim.RESTConfig { + timeout := time.Duration(c.RequestTimeoutMs) * time.Millisecond + if timeout <= 0 { + timeout = 5 * time.Second + } + ttl := time.Duration(c.AdminUserSigTTLSec) * time.Second + if ttl <= 0 { + ttl = 24 * time.Hour + } + return tencentim.RESTConfig{ + SDKAppID: c.SDKAppID, + SecretKey: c.SecretKey, + AdminIdentifier: c.AdminIdentifier, + AdminUserSigTTL: ttl, + Endpoint: c.Endpoint, + GroupType: tencentim.DefaultGroupType, + HTTPClient: &http.Client{Timeout: timeout}, + } +} + // IDGeneratorConfig 保存 user_id 发号节点配置。 type IDGeneratorConfig struct { // NodeID 参与雪花 ID 发号,多个 user-service 节点必须不同。 @@ -172,6 +227,23 @@ func Default() Config { ProviderTimeoutMs: 800, Providers: []string{"edge_country"}, }, + RoomService: RoomServiceConfig{ + Enabled: true, + Addr: "127.0.0.1:13001", + RequestTimeoutMs: 3000, + }, + ActivityService: ActivityServiceConfig{ + Enabled: true, + Addr: "127.0.0.1:13006", + RequestTimeoutMs: 3000, + }, + TencentIM: TencentIMConfig{ + Enabled: false, + AdminIdentifier: "administrator", + AdminUserSigTTLSec: 86400, + Endpoint: tencentim.DefaultEndpoint, + RequestTimeoutMs: 5000, + }, JWT: JWTConfig{ Issuer: "hyapp", AccessTokenTTLSec: 1800, @@ -217,6 +289,35 @@ func Load(path string) (Config, error) { cfg.HealthHTTPAddr = ":13105" } cfg.LoginRisk.RedisAddr = strings.TrimSpace(cfg.LoginRisk.RedisAddr) + cfg.RoomService.Addr = strings.TrimSpace(cfg.RoomService.Addr) + if cfg.RoomService.Addr == "" { + cfg.RoomService.Addr = "127.0.0.1:13001" + } + if cfg.RoomService.RequestTimeoutMs <= 0 { + cfg.RoomService.RequestTimeoutMs = 3000 + } + cfg.ActivityService.Addr = strings.TrimSpace(cfg.ActivityService.Addr) + if cfg.ActivityService.Addr == "" { + cfg.ActivityService.Addr = "127.0.0.1:13006" + } + if cfg.ActivityService.RequestTimeoutMs <= 0 { + cfg.ActivityService.RequestTimeoutMs = 3000 + } + cfg.TencentIM.SecretKey = strings.TrimSpace(cfg.TencentIM.SecretKey) + cfg.TencentIM.AdminIdentifier = strings.TrimSpace(cfg.TencentIM.AdminIdentifier) + if cfg.TencentIM.AdminIdentifier == "" { + cfg.TencentIM.AdminIdentifier = "administrator" + } + cfg.TencentIM.Endpoint = strings.TrimSpace(cfg.TencentIM.Endpoint) + if cfg.TencentIM.Endpoint == "" { + cfg.TencentIM.Endpoint = tencentim.DefaultEndpoint + } + if cfg.TencentIM.AdminUserSigTTLSec <= 0 { + cfg.TencentIM.AdminUserSigTTLSec = 86400 + } + if cfg.TencentIM.RequestTimeoutMs <= 0 { + cfg.TencentIM.RequestTimeoutMs = 5000 + } if cfg.LoginRisk.BlockedTTLSec <= 0 { cfg.LoginRisk.BlockedTTLSec = 2592000 } diff --git a/services/user-service/internal/integration/activityclient/client.go b/services/user-service/internal/integration/activityclient/client.go new file mode 100644 index 00000000..9bb78767 --- /dev/null +++ b/services/user-service/internal/integration/activityclient/client.go @@ -0,0 +1,37 @@ +// Package activityclient adapts activity-service registration reward RPCs for user-service. +package activityclient + +import ( + "context" + "time" + + "google.golang.org/grpc" + activityv1 "hyapp.local/api/proto/activity/v1" + authservice "hyapp/services/user-service/internal/service/auth" +) + +type Client struct { + client activityv1.RegistrationRewardServiceClient +} + +func NewGRPC(conn grpc.ClientConnInterface) *Client { + return &Client{client: activityv1.NewRegistrationRewardServiceClient(conn)} +} + +// IssueRegistrationReward 只发起注册奖励幂等命令;可领取判断和实际发放都在 activity-service。 +func (c *Client) IssueRegistrationReward(ctx context.Context, command authservice.RegistrationRewardCommand) error { + if c == nil || c.client == nil { + return nil + } + _, err := c.client.IssueRegistrationReward(ctx, &activityv1.IssueRegistrationRewardRequest{ + Meta: &activityv1.RequestMeta{ + RequestId: command.RequestID, + Caller: "user-service", + AppCode: command.AppCode, + SentAtMs: time.Now().UnixMilli(), + }, + UserId: command.UserID, + CommandId: command.CommandID, + }) + return err +} diff --git a/services/user-service/internal/integration/roomclient/client.go b/services/user-service/internal/integration/roomclient/client.go new file mode 100644 index 00000000..05d322d2 --- /dev/null +++ b/services/user-service/internal/integration/roomclient/client.go @@ -0,0 +1,27 @@ +// Package roomclient adapts room-service protobuf clients for user-service moderation use cases. +package roomclient + +import ( + "context" + + "google.golang.org/grpc" + roomv1 "hyapp.local/api/proto/room/v1" +) + +// Client exposes only the room command needed by user-service platform moderation. +type Client interface { + SystemEvictUser(ctx context.Context, req *roomv1.SystemEvictUserRequest) (*roomv1.SystemEvictUserResponse, error) +} + +type grpcClient struct { + client roomv1.RoomCommandServiceClient +} + +// NewGRPC returns a minimal room-service client. +func NewGRPC(conn grpc.ClientConnInterface) Client { + return &grpcClient{client: roomv1.NewRoomCommandServiceClient(conn)} +} + +func (c *grpcClient) SystemEvictUser(ctx context.Context, req *roomv1.SystemEvictUserRequest) (*roomv1.SystemEvictUserResponse, error) { + return c.client.SystemEvictUser(ctx, req) +} diff --git a/services/user-service/internal/service/auth/service.go b/services/user-service/internal/service/auth/service.go index 57f20d0e..ca114c35 100644 --- a/services/user-service/internal/service/auth/service.go +++ b/services/user-service/internal/service/auth/service.go @@ -93,6 +93,19 @@ type ThirdPartyVerifier interface { Verify(ctx context.Context, provider string, credential string) (authdomain.ThirdPartyProfile, error) } +// RegistrationRewardCommand 是三方首次注册成功后发往 activity-service 的幂等奖励命令。 +type RegistrationRewardCommand struct { + AppCode string + RequestID string + UserID int64 + CommandID string +} + +// RegistrationRewardIssuer 隔离 auth service 和 activity protobuf,避免认证领域直接依赖外部 RPC 细节。 +type RegistrationRewardIssuer interface { + IssueRegistrationReward(ctx context.Context, command RegistrationRewardCommand) error +} + // Config 保存认证底座需要的稳定参数。 type Config struct { // Issuer 写入 access token 的 iss claim。 @@ -175,6 +188,8 @@ type Service struct { ipDecisionCache IPDecisionCache // ipGeoProviders 按顺序提供 IP 国家解析能力。 ipGeoProviders []IPGeoProvider + // registrationRewardIssuer 在注册事务提交后异步式触发奖励;失败只记录日志,不回滚用户注册。 + registrationRewardIssuer RegistrationRewardIssuer } // Option 调整 auth service 的依赖和策略。 @@ -247,6 +262,15 @@ func WithIPGeoProviders(providers []IPGeoProvider) Option { } } +// WithRegistrationRewardIssuer 注入注册奖励发放 client;nil 表示本环境不启用该集成。 +func WithRegistrationRewardIssuer(issuer RegistrationRewardIssuer) Option { + return func(s *Service) { + if issuer != nil { + s.registrationRewardIssuer = issuer + } + } +} + // WithAuthRepository 注入纯认证持久化实现。 func WithAuthRepository(repository AuthRepository) Option { return func(s *Service) { diff --git a/services/user-service/internal/service/auth/third_party.go b/services/user-service/internal/service/auth/third_party.go index 5229cbd4..6f7ac5f6 100644 --- a/services/user-service/internal/service/auth/third_party.go +++ b/services/user-service/internal/service/auth/third_party.go @@ -2,6 +2,7 @@ package auth import ( "context" + "fmt" "log/slog" "strings" "time" @@ -174,6 +175,7 @@ func (s *Service) createThirdPartyUser(ctx context.Context, provider string, pro return authdomain.Token{}, false, tokenErr } s.enqueueLoginIPRiskJob(ctx, meta, token, normalizeThirdPartyChannel(provider), registration.Platform, registration.Language, registration.Timezone) + s.issueRegistrationRewardAfterCommit(ctx, registration.AppCode, user.UserID, meta) return token, true, nil } if xerr.IsCode(err, xerr.DisplayUserIDExists) { @@ -201,6 +203,27 @@ func (s *Service) createThirdPartyUser(ctx context.Context, provider string, pro return authdomain.Token{}, false, xerr.New(xerr.DisplayUserIDAllocateFailed, "display_user_id allocation failed") } +func (s *Service) issueRegistrationRewardAfterCommit(ctx context.Context, appCode string, userID int64, meta Meta) { + if s.registrationRewardIssuer == nil { + return + } + commandID := fmt.Sprintf("registration_reward:%s:%d", appcode.Normalize(appCode), userID) + if err := s.registrationRewardIssuer.IssueRegistrationReward(ctx, RegistrationRewardCommand{ + AppCode: appcode.Normalize(appCode), + RequestID: meta.RequestID, + UserID: userID, + CommandID: commandID, + }); err != nil { + // 注册主事务已经提交,奖励是后置权益发放;失败只能记录并依赖同 command_id 的人工或重试修复,不能让用户注册回滚。 + logx.Warn(logx.With(ctx, slog.String("request_id", meta.RequestID), slog.String("app_code", appcode.Normalize(appCode))), "registration_reward_issue_failed", + slog.String("component", "user_auth"), + slog.Int64("user_id", userID), + slog.String("command_id", commandID), + slog.String("error", err.Error()), + ) + } +} + func normalizeThirdPartyRegistration(registration authdomain.ThirdPartyRegistration, meta Meta) authdomain.ThirdPartyRegistration { // 注册资料来自公网入口,进入领域前统一裁剪空白,避免数据库里出现不可见差异。 registration.Username = strings.TrimSpace(registration.Username) diff --git a/services/user-service/internal/service/user/moderation.go b/services/user-service/internal/service/user/moderation.go new file mode 100644 index 00000000..534b7b4a --- /dev/null +++ b/services/user-service/internal/service/user/moderation.go @@ -0,0 +1,196 @@ +package user + +import ( + "context" + "strings" + "time" + + roomv1 "hyapp.local/api/proto/room/v1" + "hyapp/pkg/appcode" + "hyapp/pkg/idgen" + "hyapp/pkg/xerr" + userdomain "hyapp/services/user-service/internal/domain/user" +) + +const userStatusRevokeReason = "USER_STATUS_CHANGED" + +const ( + OperatorTypeAdmin = "admin" + OperatorTypeAppUser = "app_user" + OperatorTypeSystem = "system" +) + +// UserStatusCommand 是用户治理入口的服务层命令。 +type UserStatusCommand struct { + AppCode string + TargetUserID int64 + Status userdomain.Status + OperatorType string + OperatorUserID int64 + Reason string + RequestID string + NowMs int64 +} + +// UserStatusPersistenceResult 是状态事务提交后的数据库事实。 +type UserStatusPersistenceResult struct { + User userdomain.User + RevokedSessionIDs []string +} + +// UserStatusResult 汇总状态事实和封禁后需要立即执行的外部副作用结果。 +type UserStatusResult struct { + User userdomain.User + RevokedSessionCount int64 + AccessTokenRevoked bool + AccessTokenError string + IMKicked bool + IMKickError string + RoomEvicted bool + RoomID string + RTCKicked bool + RTCKickError string + RoomEvictError string +} + +// SetUserStatus 是封禁、停用和恢复用户的通用用例入口。 +// 非 active 状态会先提交用户状态和 session 吊销事实,再执行 Redis/IM/Room 的可重试副作用。 +func (s *Service) SetUserStatus(ctx context.Context, command UserStatusCommand) (UserStatusResult, error) { + if command.TargetUserID <= 0 { + return UserStatusResult{}, xerr.New(xerr.InvalidArgument, "target_user_id is required") + } + command.Status = normalizeUserStatus(command.Status) + if !validUserStatus(command.Status) { + return UserStatusResult{}, xerr.New(xerr.InvalidArgument, "status is invalid") + } + if s.moderationRepository == nil { + return UserStatusResult{}, xerr.New(xerr.Unavailable, "moderation repository is not configured") + } + if command.NowMs <= 0 { + command.NowMs = s.now().UTC().UnixMilli() + } + command.AppCode = appcode.Normalize(command.AppCode) + if command.AppCode == "" { + command.AppCode = appcode.FromContext(ctx) + } + command.Reason = normalizeModerationReason(command.Reason, command.Status) + command.OperatorType = normalizeOperatorType(command.OperatorType) + + persisted, err := s.moderationRepository.SetUserStatus(ctx, command) + if err != nil { + return UserStatusResult{}, err + } + result := UserStatusResult{ + User: persisted.User, + RevokedSessionCount: int64(len(persisted.RevokedSessionIDs)), + AccessTokenRevoked: true, + } + if command.Status == userdomain.StatusActive { + // 恢复 active 只改变准入状态,不重建旧 session、IM 登录或房间 presence。 + return result, nil + } + + result.AccessTokenRevoked, result.AccessTokenError = s.writeSessionDenylist(ctx, command, persisted.RevokedSessionIDs) + result.IMKicked, result.IMKickError = s.kickIMLogin(ctx, command.TargetUserID) + result.RoomEvicted, result.RoomID, result.RTCKicked, result.RTCKickError, result.RoomEvictError = s.evictCurrentRoom(ctx, command) + return result, nil +} + +func (s *Service) writeSessionDenylist(ctx context.Context, command UserStatusCommand, sessionIDs []string) (bool, string) { + if len(sessionIDs) == 0 { + return true, "" + } + if s.sessionDenylist == nil { + return false, "session denylist is not configured" + } + ttl := s.sessionDenylistTTL + if ttl <= 0 { + ttl = time.Hour + } + failed := 0 + var firstError string + for _, sessionID := range sessionIDs { + sessionID = strings.TrimSpace(sessionID) + if sessionID == "" { + continue + } + // 单个 Redis 写入失败不能回滚已经提交的封禁事实;调用方可通过重复封禁补偿剩余 session。 + if err := s.sessionDenylist.SetRevokedSession(ctx, command.AppCode, sessionID, userStatusRevokeReason, ttl); err != nil { + failed++ + if firstError == "" { + firstError = err.Error() + } + } + } + if failed > 0 { + return false, firstError + } + return true, "" +} + +func (s *Service) kickIMLogin(ctx context.Context, userID int64) (bool, string) { + if s.imLoginKicker == nil { + return false, "" + } + if err := s.imLoginKicker.KickUser(ctx, userID); err != nil { + return false, err.Error() + } + return true, "" +} + +func (s *Service) evictCurrentRoom(ctx context.Context, command UserStatusCommand) (bool, string, bool, string, string) { + if s.roomEvictor == nil { + return false, "", false, "", "" + } + resp, err := s.roomEvictor.SystemEvictUser(ctx, &roomv1.SystemEvictUserRequest{ + Meta: &roomv1.RequestMeta{ + RequestId: command.RequestID, + CommandId: idgen.New("cmd_user_status_evict"), + ActorUserId: command.TargetUserID, + SentAtMs: command.NowMs, + AppCode: command.AppCode, + }, + TargetUserId: command.TargetUserID, + OperatorUserId: command.OperatorUserID, + Reason: command.Reason, + BanFromRoom: true, + }) + if err != nil { + return false, "", false, "", err.Error() + } + return resp.GetHadCurrentRoom() && resp.GetResult().GetApplied(), resp.GetRoomId(), resp.GetRtcKicked(), resp.GetRtcKickError(), "" +} + +func normalizeUserStatus(status userdomain.Status) userdomain.Status { + return userdomain.Status(strings.ToLower(strings.TrimSpace(string(status)))) +} + +func validUserStatus(status userdomain.Status) bool { + return status == userdomain.StatusActive || status == userdomain.StatusDisabled || status == userdomain.StatusBanned +} + +func normalizeOperatorType(operatorType string) string { + switch strings.ToLower(strings.TrimSpace(operatorType)) { + case OperatorTypeAdmin: + return OperatorTypeAdmin + case OperatorTypeAppUser: + return OperatorTypeAppUser + default: + return OperatorTypeSystem + } +} + +func normalizeModerationReason(reason string, status userdomain.Status) string { + reason = strings.TrimSpace(reason) + if reason != "" { + return reason + } + switch status { + case userdomain.StatusBanned: + return "user_banned" + case userdomain.StatusDisabled: + return "user_disabled" + default: + return "user_status_active" + } +} diff --git a/services/user-service/internal/service/user/moderation_test.go b/services/user-service/internal/service/user/moderation_test.go new file mode 100644 index 00000000..fcde8318 --- /dev/null +++ b/services/user-service/internal/service/user/moderation_test.go @@ -0,0 +1,219 @@ +package user + +import ( + "context" + "errors" + "testing" + "time" + + roomv1 "hyapp.local/api/proto/room/v1" + "hyapp/pkg/appcode" + userdomain "hyapp/services/user-service/internal/domain/user" +) + +func TestSetUserStatusBanRevokesSessionsAndKicksRealtimeSurfaces(t *testing.T) { + repository := &fakeModerationRepository{ + user: userdomain.User{ + AppCode: "lalu", + UserID: 10001, + Status: userdomain.StatusBanned, + }, + sessionIDs: []string{"sess_a", "sess_b"}, + } + denylist := &fakeSessionDenylist{} + im := &fakeIMLoginKicker{} + room := &fakeRoomEvictor{resp: &roomv1.SystemEvictUserResponse{ + HadCurrentRoom: true, + Result: &roomv1.CommandResult{Applied: true, RoomVersion: 7}, + RoomId: "room_1001", + RtcKicked: true, + }} + svc := New(repository, + WithModerationRepository(repository), + WithSessionDenylist(denylist, time.Minute), + WithIMLoginKicker(im), + WithRoomEvictor(room), + WithClock(func() time.Time { return time.UnixMilli(1_700_000_000_000).UTC() }), + ) + + result, err := svc.SetUserStatus(appcode.WithContext(context.Background(), "lalu"), UserStatusCommand{ + AppCode: "lalu", + TargetUserID: 10001, + Status: userdomain.StatusBanned, + OperatorType: OperatorTypeAdmin, + OperatorUserID: 9001, + RequestID: "req-ban", + }) + if err != nil { + t.Fatalf("SetUserStatus failed: %v", err) + } + + if repository.lastCommand.Status != userdomain.StatusBanned || repository.lastCommand.OperatorType != OperatorTypeAdmin || repository.lastCommand.NowMs != 1_700_000_000_000 { + t.Fatalf("unexpected repository command: %+v", repository.lastCommand) + } + if len(denylist.sessions) != 2 || denylist.sessions[0] != "sess_a" || denylist.sessions[1] != "sess_b" { + t.Fatalf("denylist sessions mismatch: %+v", denylist.sessions) + } + if im.userID != 10001 { + t.Fatalf("im kick target mismatch: %d", im.userID) + } + if room.req.GetTargetUserId() != 10001 || !room.req.GetBanFromRoom() || room.req.GetMeta().GetAppCode() != "lalu" { + t.Fatalf("room eviction request mismatch: %+v", room.req) + } + if !result.AccessTokenRevoked || result.AccessTokenError != "" { + t.Fatalf("access token revoke result mismatch: %+v", result) + } + if !result.IMKicked || !result.RoomEvicted || !result.RTCKicked || result.RoomID != "room_1001" { + t.Fatalf("unexpected moderation result: %+v", result) + } +} + +func TestSetUserStatusSurfacesAccessDenylistError(t *testing.T) { + repository := &fakeModerationRepository{ + user: userdomain.User{ + AppCode: "lalu", + UserID: 10001, + Status: userdomain.StatusBanned, + }, + sessionIDs: []string{"sess_a"}, + } + denylist := &fakeSessionDenylist{err: errors.New("redis unavailable")} + svc := New(repository, + WithModerationRepository(repository), + WithSessionDenylist(denylist, time.Minute), + ) + + result, err := svc.SetUserStatus(appcode.WithContext(context.Background(), "lalu"), UserStatusCommand{ + AppCode: "lalu", + TargetUserID: 10001, + Status: userdomain.StatusBanned, + RequestID: "req-ban", + }) + if err != nil { + t.Fatalf("SetUserStatus failed: %v", err) + } + + if result.AccessTokenRevoked || result.AccessTokenError != "redis unavailable" { + t.Fatalf("denylist error must be surfaced for retry: %+v", result) + } + if result.RevokedSessionCount != 1 { + t.Fatalf("database revocation fact mismatch: %+v", result) + } +} + +type fakeModerationRepository struct { + user userdomain.User + sessionIDs []string + lastCommand UserStatusCommand +} + +func (r *fakeModerationRepository) SetUserStatus(_ context.Context, command UserStatusCommand) (UserStatusPersistenceResult, error) { + r.lastCommand = command + r.user.Status = command.Status + return UserStatusPersistenceResult{User: r.user, RevokedSessionIDs: append([]string{}, r.sessionIDs...)}, nil +} + +func (r *fakeModerationRepository) GetUser(context.Context, int64) (userdomain.User, error) { + return r.user, nil +} + +func (r *fakeModerationRepository) GetMyProfileStats(context.Context, int64) (userdomain.ProfileStats, error) { + return userdomain.ProfileStats{}, nil +} + +func (r *fakeModerationRepository) RecordProfileVisit(context.Context, int64, int64, int64) (bool, userdomain.ProfileStats, error) { + return false, userdomain.ProfileStats{}, nil +} + +func (r *fakeModerationRepository) ListProfileVisitors(context.Context, int64, int32, int32) ([]userdomain.ProfileVisitRecord, int64, error) { + return nil, 0, nil +} + +func (r *fakeModerationRepository) FollowUser(context.Context, int64, int64, int64) (userdomain.ProfileStats, error) { + return userdomain.ProfileStats{}, nil +} + +func (r *fakeModerationRepository) UnfollowUser(context.Context, int64, int64, int64) (userdomain.ProfileStats, error) { + return userdomain.ProfileStats{}, nil +} + +func (r *fakeModerationRepository) ListFollowing(context.Context, int64, int32, int32, int64, int64) ([]userdomain.FollowRecord, int64, error) { + return nil, 0, nil +} + +func (r *fakeModerationRepository) ApplyFriend(context.Context, int64, int64, int64) (userdomain.FriendApplication, bool, error) { + return userdomain.FriendApplication{}, false, nil +} + +func (r *fakeModerationRepository) AcceptFriendApplication(context.Context, int64, int64, int64) (userdomain.FriendRecord, error) { + return userdomain.FriendRecord{}, nil +} + +func (r *fakeModerationRepository) DeleteFriend(context.Context, int64, int64, int64) (bool, error) { + return false, nil +} + +func (r *fakeModerationRepository) ListFriends(context.Context, int64, int32, int32, int64, int64) ([]userdomain.FriendRecord, int64, error) { + return nil, 0, nil +} + +func (r *fakeModerationRepository) ListFriendApplications(context.Context, int64, string, int32, int32) ([]userdomain.FriendApplication, int64, error) { + return nil, 0, nil +} + +func (r *fakeModerationRepository) BusinessUserLookup(context.Context, string, bool, int32) ([]userdomain.BusinessUserLookupItem, error) { + return nil, nil +} + +func (r *fakeModerationRepository) BatchGetUsers(context.Context, []int64) (map[int64]userdomain.User, error) { + return nil, nil +} + +func (r *fakeModerationRepository) ListUserIDs(context.Context, userdomain.UserIDPageFilter) ([]int64, error) { + return nil, nil +} + +func (r *fakeModerationRepository) CreateUserWithIdentity(context.Context, userdomain.User, userdomain.Identity) error { + return nil +} + +func (r *fakeModerationRepository) UpdateUserProfile(context.Context, userdomain.ProfileUpdateCommand) (userdomain.User, error) { + return r.user, nil +} + +func (r *fakeModerationRepository) CompleteOnboarding(context.Context, userdomain.CompleteOnboardingCommand) (userdomain.User, error) { + return r.user, nil +} + +func (r *fakeModerationRepository) ChangeUserCountry(context.Context, userdomain.CountryChangeCommand) (userdomain.User, int64, error) { + return r.user, 0, nil +} + +type fakeSessionDenylist struct { + sessions []string + err error +} + +func (d *fakeSessionDenylist) SetRevokedSession(_ context.Context, _ string, sessionID string, _ string, _ time.Duration) error { + d.sessions = append(d.sessions, sessionID) + return d.err +} + +type fakeIMLoginKicker struct { + userID int64 +} + +func (k *fakeIMLoginKicker) KickUser(_ context.Context, userID int64) error { + k.userID = userID + return nil +} + +type fakeRoomEvictor struct { + req *roomv1.SystemEvictUserRequest + resp *roomv1.SystemEvictUserResponse +} + +func (e *fakeRoomEvictor) SystemEvictUser(_ context.Context, req *roomv1.SystemEvictUserRequest) (*roomv1.SystemEvictUserResponse, error) { + e.req = req + return e.resp, nil +} diff --git a/services/user-service/internal/service/user/service.go b/services/user-service/internal/service/user/service.go index 070bd6dc..a501a1d3 100644 --- a/services/user-service/internal/service/user/service.go +++ b/services/user-service/internal/service/user/service.go @@ -5,6 +5,7 @@ import ( "context" "time" + roomv1 "hyapp.local/api/proto/room/v1" "hyapp/pkg/idgen" userdomain "hyapp/services/user-service/internal/domain/user" ) @@ -114,6 +115,26 @@ type DeviceRepository interface { DeletePushToken(ctx context.Context, command userdomain.DeletePushTokenCommand) (bool, error) } +// ModerationRepository 持有用户状态和认证 session 的同库事务。 +type ModerationRepository interface { + SetUserStatus(ctx context.Context, command UserStatusCommand) (UserStatusPersistenceResult, error) +} + +// SessionDenylist 写入 gateway access token 快速拒绝缓存。 +type SessionDenylist interface { + SetRevokedSession(ctx context.Context, appCode string, sessionID string, reason string, ttl time.Duration) error +} + +// IMLoginKicker 失效用户在腾讯云 IM SDK 的当前登录态。 +type IMLoginKicker interface { + KickUser(ctx context.Context, userID int64) error +} + +// RoomEvictor 通过 room-service 驱逐用户当前所在的 Room Cell。 +type RoomEvictor interface { + SystemEvictUser(ctx context.Context, req *roomv1.SystemEvictUserRequest) (*roomv1.SystemEvictUserResponse, error) +} + // IDGenerator 生成系统内部不可变 user_id。 type IDGenerator interface { // NewInt64 返回全局唯一 user_id。 @@ -148,6 +169,16 @@ type Service struct { regionRebuildRepository RegionRebuildRepository // deviceRepository 持有设备 push token 绑定能力。 deviceRepository DeviceRepository + // moderationRepository 持有用户状态和 session 吊销事务能力。 + moderationRepository ModerationRepository + // sessionDenylist 让已签发 access token 在 gateway 立即失效。 + sessionDenylist SessionDenylist + // sessionDenylistTTL 覆盖 access token 剩余有效期,避免 Redis key 先于 JWT 过期。 + sessionDenylistTTL time.Duration + // imLoginKicker 失效腾讯云 IM 当前登录态。 + imLoginKicker IMLoginKicker + // roomEvictor 通过 room-service 清理当前房间 presence、麦位和 RTC 连接。 + roomEvictor RoomEvictor // idGenerator 生成系统内部不可变 user_id。 idGenerator IDGenerator // displayUserIDAllocator 生成默认短号候选,唯一性由 repository 保证。 @@ -175,6 +206,10 @@ func New(userRepository UserRepository, options ...Option) *Service { displayUserIDCooldown: 30 * 24 * time.Hour, countryChangeCooldown: 30 * 24 * time.Hour, } + if repository, ok := userRepository.(ModerationRepository); ok { + // MySQL 用户 repository 同时持有 auth_sessions 表的同库事务能力。 + svc.moderationRepository = repository + } for _, option := range options { // option 只改依赖或策略,不做 IO。 option(svc) @@ -183,6 +218,43 @@ func New(userRepository UserRepository, options ...Option) *Service { return svc } +// WithModerationRepository 注入用户治理事务 repository。 +func WithModerationRepository(repository ModerationRepository) Option { + return func(s *Service) { + if repository != nil { + s.moderationRepository = repository + } + } +} + +// WithSessionDenylist 注入 access session denylist 缓存。 +func WithSessionDenylist(denylist SessionDenylist, ttl time.Duration) Option { + return func(s *Service) { + if denylist != nil { + s.sessionDenylist = denylist + s.sessionDenylistTTL = ttl + } + } +} + +// WithIMLoginKicker 注入腾讯云 IM 当前登录态失效边界。 +func WithIMLoginKicker(kicker IMLoginKicker) Option { + return func(s *Service) { + if kicker != nil { + s.imLoginKicker = kicker + } + } +} + +// WithRoomEvictor 注入当前房间驱逐边界。 +func WithRoomEvictor(evictor RoomEvictor) Option { + return func(s *Service) { + if evictor != nil { + s.roomEvictor = evictor + } + } +} + // WithAppRegistryRepository 注入 App 注册表 repository。 func WithAppRegistryRepository(repository AppRegistryRepository) Option { return func(s *Service) { diff --git a/services/user-service/internal/storage/mysql/user/moderation.go b/services/user-service/internal/storage/mysql/user/moderation.go new file mode 100644 index 00000000..a122ef16 --- /dev/null +++ b/services/user-service/internal/storage/mysql/user/moderation.go @@ -0,0 +1,117 @@ +package user + +import ( + "context" + "database/sql" + + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + userdomain "hyapp/services/user-service/internal/domain/user" + userservice "hyapp/services/user-service/internal/service/user" +) + +// SetUserStatus 原子更新用户主状态,并在非 active 状态下吊销该用户所有 active refresh session。 +func (r *Repository) SetUserStatus(ctx context.Context, command userservice.UserStatusCommand) (userservice.UserStatusPersistenceResult, error) { + if r == nil || r.db == nil { + return userservice.UserStatusPersistenceResult{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + appCode := appcode.Normalize(command.AppCode) + if appCode == "" { + appCode = appcode.FromContext(ctx) + } + + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return userservice.UserStatusPersistenceResult{}, err + } + defer tx.Rollback() + + var oldStatus string + if err := tx.QueryRowContext(ctx, ` + SELECT status + FROM users + WHERE app_code = ? AND user_id = ? + FOR UPDATE + `, appCode, command.TargetUserID).Scan(&oldStatus); err != nil { + if err == sql.ErrNoRows { + return userservice.UserStatusPersistenceResult{}, xerr.New(xerr.NotFound, "user not found") + } + return userservice.UserStatusPersistenceResult{}, err + } + + _, err = tx.ExecContext(ctx, ` + UPDATE users + SET status = ?, updated_at_ms = ? + WHERE app_code = ? AND user_id = ? + `, string(command.Status), command.NowMs, appCode, command.TargetUserID) + if err != nil { + return userservice.UserStatusPersistenceResult{}, err + } + if _, err := tx.ExecContext(ctx, ` + INSERT INTO user_status_change_logs ( + app_code, target_user_id, old_status, new_status, operator_type, operator_user_id, reason, request_id, created_at_ms + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + `, appCode, command.TargetUserID, oldStatus, string(command.Status), command.OperatorType, command.OperatorUserID, command.Reason, command.RequestID, command.NowMs); err != nil { + return userservice.UserStatusPersistenceResult{}, err + } + + sessionIDs := make([]string, 0) + if command.Status != userdomain.StatusActive { + rows, err := tx.QueryContext(ctx, ` + SELECT session_id + FROM auth_sessions + WHERE app_code = ? AND user_id = ? AND expires_at_ms > ? + FOR UPDATE + `, appCode, command.TargetUserID, command.NowMs) + if err != nil { + return userservice.UserStatusPersistenceResult{}, err + } + for rows.Next() { + var sessionID string + if err := rows.Scan(&sessionID); err != nil { + _ = rows.Close() + return userservice.UserStatusPersistenceResult{}, err + } + sessionIDs = append(sessionIDs, sessionID) + } + if err := rows.Close(); err != nil { + return userservice.UserStatusPersistenceResult{}, err + } + if _, err := tx.ExecContext(ctx, ` + UPDATE auth_sessions + SET revoked_at_ms = ?, revoked_reason = ?, revoked_request_id = ?, revoked_by = ?, updated_at_ms = ? + WHERE app_code = ? AND user_id = ? AND revoked_at_ms IS NULL + `, command.NowMs, userStatusRevokeReason(command.Status), command.RequestID, revokedBy(command.OperatorUserID), command.NowMs, appCode, command.TargetUserID); err != nil { + return userservice.UserStatusPersistenceResult{}, err + } + } + + if err := tx.Commit(); err != nil { + return userservice.UserStatusPersistenceResult{}, err + } + + user, err := r.GetUser(appcode.WithContext(ctx, appCode), command.TargetUserID) + if err != nil { + return userservice.UserStatusPersistenceResult{}, err + } + return userservice.UserStatusPersistenceResult{User: user, RevokedSessionIDs: sessionIDs}, nil +} + +func userStatusRevokeReason(status userdomain.Status) string { + switch status { + case userdomain.StatusBanned: + return "USER_BANNED" + case userdomain.StatusDisabled: + return "USER_DISABLED" + default: + return "USER_STATUS_CHANGED" + } +} + +func revokedBy(operatorUserID int64) string { + if operatorUserID > 0 { + return "user_status_operator" + } + return "user_status" +} diff --git a/services/user-service/internal/transport/grpc/convert.go b/services/user-service/internal/transport/grpc/convert.go index b7018919..4377b028 100644 --- a/services/user-service/internal/transport/grpc/convert.go +++ b/services/user-service/internal/transport/grpc/convert.go @@ -239,6 +239,19 @@ func toProtoStatus(status userdomain.Status) userv1.UserStatus { } } +func fromProtoStatus(status userv1.UserStatus) userdomain.Status { + switch status { + case userv1.UserStatus_USER_STATUS_ACTIVE: + return userdomain.StatusActive + case userv1.UserStatus_USER_STATUS_DISABLED: + return userdomain.StatusDisabled + case userv1.UserStatus_USER_STATUS_BANNED: + return userdomain.StatusBanned + default: + return "" + } +} + // authMeta 提取认证链路审计所需的 gateway 透传字段。 func authMeta(meta *userv1.RequestMeta) authservice.Meta { if meta == nil { diff --git a/services/user-service/internal/transport/grpc/server.go b/services/user-service/internal/transport/grpc/server.go index d45c818e..bd90fe04 100644 --- a/services/user-service/internal/transport/grpc/server.go +++ b/services/user-service/internal/transport/grpc/server.go @@ -229,6 +229,38 @@ func (s *Server) GetMyProfileStats(ctx context.Context, req *userv1.GetMyProfile return &userv1.GetMyProfileStatsResponse{Stats: toProtoProfileStats(stats)}, nil } +// SetUserStatus 处理平台封禁、停用和恢复用户。 +func (s *Server) SetUserStatus(ctx context.Context, req *userv1.SetUserStatusRequest) (*userv1.SetUserStatusResponse, error) { + ctx = contextWithApp(ctx, req.GetMeta()) + result, err := s.userSvc.SetUserStatus(ctx, userservice.UserStatusCommand{ + AppCode: req.GetMeta().GetAppCode(), + TargetUserID: req.GetTargetUserId(), + Status: fromProtoStatus(req.GetStatus()), + OperatorType: req.GetOperatorType(), + OperatorUserID: req.GetOperatorUserId(), + Reason: req.GetReason(), + RequestID: req.GetMeta().GetRequestId(), + NowMs: req.GetMeta().GetSentAtMs(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + + return &userv1.SetUserStatusResponse{ + User: toProtoUser(result.User), + RevokedSessionCount: result.RevokedSessionCount, + AccessTokenRevoked: result.AccessTokenRevoked, + AccessTokenRevokeError: result.AccessTokenError, + ImKicked: result.IMKicked, + ImKickError: result.IMKickError, + RoomEvicted: result.RoomEvicted, + RoomId: result.RoomID, + RtcKicked: result.RTCKicked, + RtcKickError: result.RTCKickError, + RoomEvictError: result.RoomEvictError, + }, nil +} + // RecordProfileVisit 记录访问足迹;重复访问只刷新访问次数和最后访问时间。 func (s *Server) RecordProfileVisit(ctx context.Context, req *userv1.RecordProfileVisitRequest) (*userv1.RecordProfileVisitResponse, error) { ctx = contextWithApp(ctx, req.GetMeta()) diff --git a/services/wallet-service/deploy/mysql/initdb/001_wallet_service.sql b/services/wallet-service/deploy/mysql/initdb/001_wallet_service.sql index d6eddff9..1ee84122 100644 --- a/services/wallet-service/deploy/mysql/initdb/001_wallet_service.sql +++ b/services/wallet-service/deploy/mysql/initdb/001_wallet_service.sql @@ -127,6 +127,37 @@ CREATE TABLE IF NOT EXISTS wallet_recharge_records ( KEY idx_wallet_recharge_records_region_time (app_code, target_region_id, created_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE IF NOT EXISTS wallet_recharge_products ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + product_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + product_code VARCHAR(128) NULL, + product_name VARCHAR(128) NOT NULL, + description VARCHAR(512) NOT NULL DEFAULT '', + platform VARCHAR(16) NOT NULL, + channel VARCHAR(32) NOT NULL, + currency_code VARCHAR(8) NOT NULL DEFAULT 'USDT', + amount_micro BIGINT NOT NULL, + coin_amount BIGINT NOT NULL, + resource_asset_type VARCHAR(32) NOT NULL DEFAULT 'COIN', + status VARCHAR(32) NOT NULL, + sort_order INT NOT NULL DEFAULT 0, + created_by_user_id BIGINT NULL, + updated_by_user_id BIGINT NULL, + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + UNIQUE KEY uk_wallet_recharge_products_code (app_code, product_code), + KEY idx_wallet_recharge_products_scope (app_code, platform, status, amount_micro, product_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS wallet_recharge_product_regions ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + product_id BIGINT NOT NULL, + region_id BIGINT NOT NULL, + created_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, product_id, region_id), + KEY idx_wallet_recharge_product_regions_region (app_code, region_id, product_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CREATE TABLE IF NOT EXISTS coin_seller_stock_records ( app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', stock_id VARCHAR(96) NOT NULL, diff --git a/services/wallet-service/internal/domain/ledger/ledger.go b/services/wallet-service/internal/domain/ledger/ledger.go index a8bf02ac..bfc3cdcd 100644 --- a/services/wallet-service/internal/domain/ledger/ledger.go +++ b/services/wallet-service/internal/domain/ledger/ledger.go @@ -20,6 +20,18 @@ const ( StockTypeCoinCompensation = "coin_compensation" // PaidCurrencyUSDT 是首版币商进货支持的唯一线下付款币种。 PaidCurrencyUSDT = "USDT" + // RechargeProductStatusActive 表示内购商品已上架,可进入 App 充值页。 + RechargeProductStatusActive = "active" + // RechargeProductStatusDisabled 表示内购商品未上架,仅后台可见。 + RechargeProductStatusDisabled = "disabled" + // RechargeProductPlatformAndroid 表示 Google Play 侧内购商品。 + RechargeProductPlatformAndroid = "android" + // RechargeProductPlatformIOS 表示 Apple IAP 侧内购商品。 + RechargeProductPlatformIOS = "ios" + // RechargeChannelGoogle 是 android 平台内购渠道标识。 + RechargeChannelGoogle = "google" + // RechargeChannelApple 是 iOS 平台内购渠道标识。 + RechargeChannelApple = "apple" // WithdrawalStatusPending 表示主播美元余额提现已提交,等待后台人工审核和线下转账。 WithdrawalStatusPending = "pending" @@ -177,15 +189,52 @@ type WalletValueSummary struct { // RechargeProduct 是用户充值页读取的充值档位。 type RechargeProduct struct { - ProductID int64 - ProductCode string - Channel string - CurrencyCode string - CoinAmount int64 - AmountMinor int64 - PolicyVersion string - Enabled bool - SortOrder int32 + AppCode string + ProductID int64 + ProductCode string + ProductName string + Description string + Platform string + Channel string + CurrencyCode string + AmountMicro int64 + AmountMinor int64 + CoinAmount int64 + PolicyVersion string + Enabled bool + Status string + SortOrder int32 + RegionIDs []int64 + ResourceAssetType string + CreatedByUserID int64 + UpdatedByUserID int64 + CreatedAtMS int64 + UpdatedAtMS int64 +} + +// ListRechargeProductsQuery 是后台内购商品配置列表的筛选条件。 +type ListRechargeProductsQuery struct { + AppCode string + Status string + Platform string + RegionID int64 + Keyword string + Page int32 + PageSize int32 +} + +// RechargeProductCommand 是后台创建或更新内购商品配置的完整事实输入。 +type RechargeProductCommand struct { + AppCode string + ProductID int64 + AmountMicro int64 + CoinAmount int64 + ProductName string + Description string + Platform string + RegionIDs []int64 + Enabled bool + OperatorUserID int64 } // DiamondExchangeRule 是钻石兑换金币或余额的固定规则投影。 @@ -401,6 +450,39 @@ func NormalizeCoinSellerStockType(stockType string) string { } } +func NormalizeRechargeProductStatus(status string) string { + switch strings.ToLower(strings.TrimSpace(status)) { + case RechargeProductStatusActive: + return RechargeProductStatusActive + case RechargeProductStatusDisabled: + return RechargeProductStatusDisabled + default: + return "" + } +} + +func NormalizeRechargeProductPlatform(platform string) string { + switch strings.ToLower(strings.TrimSpace(platform)) { + case RechargeProductPlatformAndroid: + return RechargeProductPlatformAndroid + case RechargeProductPlatformIOS: + return RechargeProductPlatformIOS + default: + return "" + } +} + +func RechargeChannelForPlatform(platform string) string { + switch NormalizeRechargeProductPlatform(platform) { + case RechargeProductPlatformAndroid: + return RechargeChannelGoogle + case RechargeProductPlatformIOS: + return RechargeChannelApple + default: + return "" + } +} + func NormalizeGameOpType(opType string) string { switch strings.ToLower(strings.TrimSpace(opType)) { case GameOpDebit: diff --git a/services/wallet-service/internal/domain/resource/resource.go b/services/wallet-service/internal/domain/resource/resource.go index 183725be..87a75719 100644 --- a/services/wallet-service/internal/domain/resource/resource.go +++ b/services/wallet-service/internal/domain/resource/resource.go @@ -8,6 +8,7 @@ import ( const ( TypeAvatarFrame = "avatar_frame" + TypeProfileCard = "profile_card" TypeCoin = "coin" TypeVehicle = "vehicle" TypeChatBubble = "chat_bubble" @@ -342,7 +343,7 @@ func NormalizeGrantSource(value string) string { func ValidResourceType(value string) bool { switch strings.ToLower(strings.TrimSpace(value)) { - case TypeAvatarFrame, TypeCoin, TypeVehicle, TypeChatBubble, TypeBadge, TypeFloatingScreen, TypeGift: + case TypeAvatarFrame, TypeProfileCard, TypeCoin, TypeVehicle, TypeChatBubble, TypeBadge, TypeFloatingScreen, TypeGift: return true default: return false diff --git a/services/wallet-service/internal/domain/resource/resource_test.go b/services/wallet-service/internal/domain/resource/resource_test.go new file mode 100644 index 00000000..e7f46133 --- /dev/null +++ b/services/wallet-service/internal/domain/resource/resource_test.go @@ -0,0 +1,9 @@ +package resource + +import "testing" + +func TestProfileCardIsValidResourceType(t *testing.T) { + if !ValidResourceType(TypeProfileCard) { + t.Fatalf("profile_card must be accepted as a configured resource type") + } +} diff --git a/services/wallet-service/internal/service/wallet/service.go b/services/wallet-service/internal/service/wallet/service.go index 1dfac5f3..45ed29f5 100644 --- a/services/wallet-service/internal/service/wallet/service.go +++ b/services/wallet-service/internal/service/wallet/service.go @@ -22,7 +22,11 @@ type Repository interface { ListRechargeBills(ctx context.Context, query ledger.ListRechargeBillsQuery) ([]ledger.RechargeBill, int64, error) GetWalletOverview(ctx context.Context, userID int64) (ledger.WalletOverview, error) GetWalletValueSummary(ctx context.Context, userID int64) (ledger.WalletValueSummary, error) - ListRechargeProducts(ctx context.Context, userID int64, regionID int64) ([]ledger.RechargeProduct, []string, error) + ListRechargeProducts(ctx context.Context, userID int64, regionID int64, platform string) ([]ledger.RechargeProduct, []string, error) + ListAdminRechargeProducts(ctx context.Context, query ledger.ListRechargeProductsQuery) ([]ledger.RechargeProduct, int64, error) + CreateRechargeProduct(ctx context.Context, command ledger.RechargeProductCommand) (ledger.RechargeProduct, error) + UpdateRechargeProduct(ctx context.Context, command ledger.RechargeProductCommand) (ledger.RechargeProduct, error) + DeleteRechargeProduct(ctx context.Context, appCode string, productID int64) error GetDiamondExchangeConfig(ctx context.Context, userID int64) ([]ledger.DiamondExchangeRule, error) ListWalletTransactions(ctx context.Context, query ledger.ListWalletTransactionsQuery) ([]ledger.WalletTransaction, int64, error) ApplyWithdrawal(ctx context.Context, command ledger.WithdrawalCommand) (ledger.WithdrawalRequest, ledger.AssetBalance, error) @@ -286,15 +290,81 @@ func (s *Service) GetWalletValueSummary(ctx context.Context, userID int64) (ledg } // ListRechargeProducts 返回区域化充值档位;region_id 必须由 gateway 从 user-service 资料解析。 -func (s *Service) ListRechargeProducts(ctx context.Context, userID int64, regionID int64) ([]ledger.RechargeProduct, []string, error) { +func (s *Service) ListRechargeProducts(ctx context.Context, userID int64, regionID int64, platform string) ([]ledger.RechargeProduct, []string, error) { if userID <= 0 || regionID <= 0 { return nil, nil, xerr.New(xerr.InvalidArgument, "user_id and region_id are required") } + if strings.TrimSpace(platform) != "" { + platform = ledger.NormalizeRechargeProductPlatform(platform) + if platform == "" { + return nil, nil, xerr.New(xerr.InvalidArgument, "platform is invalid") + } + } if s.repository == nil { return nil, nil, xerr.New(xerr.Unavailable, "wallet repository is not configured") } ctx = appcode.WithContext(ctx, appcode.FromContext(ctx)) - return s.repository.ListRechargeProducts(ctx, userID, regionID) + return s.repository.ListRechargeProducts(ctx, userID, regionID, platform) +} + +// ListAdminRechargeProducts 返回后台配置列表;后台入口负责 RBAC 和审计。 +func (s *Service) ListAdminRechargeProducts(ctx context.Context, query ledger.ListRechargeProductsQuery) ([]ledger.RechargeProduct, int64, error) { + if s.repository == nil { + return nil, 0, xerr.New(xerr.Unavailable, "wallet repository is not configured") + } + query.AppCode = appcode.Normalize(query.AppCode) + if strings.TrimSpace(query.Status) != "" { + query.Status = ledger.NormalizeRechargeProductStatus(query.Status) + if query.Status == "" { + return nil, 0, xerr.New(xerr.InvalidArgument, "status is invalid") + } + } + if strings.TrimSpace(query.Platform) != "" { + query.Platform = ledger.NormalizeRechargeProductPlatform(query.Platform) + if query.Platform == "" { + return nil, 0, xerr.New(xerr.InvalidArgument, "platform is invalid") + } + } + ctx = appcode.WithContext(ctx, query.AppCode) + return s.repository.ListAdminRechargeProducts(ctx, query) +} + +// CreateRechargeProduct 创建内购商品配置;首版充值资源只允许发 COIN。 +func (s *Service) CreateRechargeProduct(ctx context.Context, command ledger.RechargeProductCommand) (ledger.RechargeProduct, error) { + if s.repository == nil { + return ledger.RechargeProduct{}, xerr.New(xerr.Unavailable, "wallet repository is not configured") + } + command.AppCode = appcode.Normalize(command.AppCode) + if err := validateRechargeProductCommand(command, false); err != nil { + return ledger.RechargeProduct{}, err + } + ctx = appcode.WithContext(ctx, command.AppCode) + return s.repository.CreateRechargeProduct(ctx, command) +} + +// UpdateRechargeProduct 覆盖内购商品配置和支持区域,避免状态散落在后台库。 +func (s *Service) UpdateRechargeProduct(ctx context.Context, command ledger.RechargeProductCommand) (ledger.RechargeProduct, error) { + if s.repository == nil { + return ledger.RechargeProduct{}, xerr.New(xerr.Unavailable, "wallet repository is not configured") + } + command.AppCode = appcode.Normalize(command.AppCode) + if err := validateRechargeProductCommand(command, true); err != nil { + return ledger.RechargeProduct{}, err + } + ctx = appcode.WithContext(ctx, command.AppCode) + return s.repository.UpdateRechargeProduct(ctx, command) +} + +// DeleteRechargeProduct 删除尚未接入 provider order 的配置事实;订单实现后这里需要先做引用检查。 +func (s *Service) DeleteRechargeProduct(ctx context.Context, appCode string, productID int64) error { + if productID <= 0 { + return xerr.New(xerr.InvalidArgument, "product_id is required") + } + if s.repository == nil { + return xerr.New(xerr.Unavailable, "wallet repository is not configured") + } + ctx = appcode.WithContext(ctx, appcode.Normalize(appCode)) + return s.repository.DeleteRechargeProduct(ctx, appcode.FromContext(ctx), productID) } // GetDiamondExchangeConfig 返回当前 App 支持的钻石兑换规则。 @@ -380,3 +450,35 @@ func (s *Service) PurchaseVip(ctx context.Context, command ledger.PurchaseVipCom ctx = appcode.WithContext(ctx, command.AppCode) return s.repository.PurchaseVip(ctx, command) } + +func validateRechargeProductCommand(command ledger.RechargeProductCommand, requireProductID bool) error { + if requireProductID && command.ProductID <= 0 { + return xerr.New(xerr.InvalidArgument, "product_id is required") + } + if command.AmountMicro <= 0 || command.CoinAmount <= 0 || command.OperatorUserID <= 0 { + return xerr.New(xerr.InvalidArgument, "recharge product amount and operator are required") + } + if strings.TrimSpace(command.ProductName) == "" || len([]rune(strings.TrimSpace(command.ProductName))) > 128 { + return xerr.New(xerr.InvalidArgument, "product_name is invalid") + } + if len([]rune(strings.TrimSpace(command.Description))) > 512 { + return xerr.New(xerr.InvalidArgument, "description is too long") + } + if ledger.NormalizeRechargeProductPlatform(command.Platform) == "" { + return xerr.New(xerr.InvalidArgument, "platform is invalid") + } + if len(command.RegionIDs) == 0 { + return xerr.New(xerr.InvalidArgument, "region_ids are required") + } + seen := make(map[int64]struct{}, len(command.RegionIDs)) + for _, regionID := range command.RegionIDs { + if regionID <= 0 { + return xerr.New(xerr.InvalidArgument, "region_id is invalid") + } + if _, ok := seen[regionID]; ok { + return xerr.New(xerr.InvalidArgument, "region_id is duplicated") + } + seen[regionID] = struct{}{} + } + return nil +} diff --git a/services/wallet-service/internal/service/wallet/service_test.go b/services/wallet-service/internal/service/wallet/service_test.go index 81aaaf0e..a65cce11 100644 --- a/services/wallet-service/internal/service/wallet/service_test.go +++ b/services/wallet-service/internal/service/wallet/service_test.go @@ -1223,6 +1223,101 @@ func TestWalletOverviewAndDiamondExchangeConfigComeFromWalletService(t *testing. } } +// TestRechargeProductsAreConfiguredByPlatformRegionAndStatus 锁定内购配置由 wallet-service 持久化并按平台、区域和上架态投放。 +func TestRechargeProductsAreConfiguredByPlatformRegionAndStatus(t *testing.T) { + repository := mysqltest.NewRepository(t) + svc := walletservice.New(repository) + + product, err := svc.CreateRechargeProduct(context.Background(), ledger.RechargeProductCommand{ + AppCode: "lalu", + AmountMicro: 1500000, + CoinAmount: 1500, + ProductName: "1500 Coins", + Description: "coin pack", + Platform: ledger.RechargeProductPlatformAndroid, + RegionIDs: []int64{1002, 1001}, + Enabled: true, + OperatorUserID: 90001, + }) + if err != nil { + t.Fatalf("CreateRechargeProduct failed: %v", err) + } + if product.ProductID <= 0 || product.ProductCode == "" || product.Channel != ledger.RechargeChannelGoogle { + t.Fatalf("created product identifiers mismatch: %+v", product) + } + if len(product.RegionIDs) != 2 || product.RegionIDs[0] != 1001 || product.RegionIDs[1] != 1002 { + t.Fatalf("created product regions mismatch: %+v", product.RegionIDs) + } + + products, channels, err := svc.ListRechargeProducts(context.Background(), 53001, 1001, ledger.RechargeProductPlatformAndroid) + if err != nil { + t.Fatalf("ListRechargeProducts android failed: %v", err) + } + if len(products) != 1 || products[0].ProductName != "1500 Coins" || products[0].CoinAmount != 1500 || products[0].AmountMicro != 1500000 { + t.Fatalf("android recharge product mismatch: products=%+v", products) + } + if len(channels) != 1 || channels[0] != ledger.RechargeChannelGoogle { + t.Fatalf("android recharge channels mismatch: %+v", channels) + } + + iosProducts, _, err := svc.ListRechargeProducts(context.Background(), 53001, 1001, ledger.RechargeProductPlatformIOS) + if err != nil { + t.Fatalf("ListRechargeProducts ios failed: %v", err) + } + if len(iosProducts) != 0 { + t.Fatalf("ios list must not include android product: %+v", iosProducts) + } + + _, err = svc.UpdateRechargeProduct(context.Background(), ledger.RechargeProductCommand{ + AppCode: "lalu", + ProductID: product.ProductID, + AmountMicro: 2500000, + CoinAmount: 2600, + ProductName: "2600 Coins", + Description: "updated pack", + Platform: ledger.RechargeProductPlatformAndroid, + RegionIDs: []int64{1002}, + Enabled: false, + OperatorUserID: 90002, + }) + if err != nil { + t.Fatalf("UpdateRechargeProduct failed: %v", err) + } + + inactiveProducts, _, err := svc.ListRechargeProducts(context.Background(), 53001, 1002, ledger.RechargeProductPlatformAndroid) + if err != nil { + t.Fatalf("ListRechargeProducts inactive failed: %v", err) + } + if len(inactiveProducts) != 0 { + t.Fatalf("disabled product must not be exposed to app: %+v", inactiveProducts) + } + + adminProducts, total, err := svc.ListAdminRechargeProducts(context.Background(), ledger.ListRechargeProductsQuery{ + AppCode: "lalu", + Status: ledger.RechargeProductStatusDisabled, + RegionID: 1002, + Page: 1, + PageSize: 10, + }) + if err != nil { + t.Fatalf("ListAdminRechargeProducts failed: %v", err) + } + if total != 1 || len(adminProducts) != 1 || adminProducts[0].Enabled || adminProducts[0].CoinAmount != 2600 { + t.Fatalf("admin disabled product mismatch: total=%d products=%+v", total, adminProducts) + } + + if err := svc.DeleteRechargeProduct(context.Background(), "lalu", product.ProductID); err != nil { + t.Fatalf("DeleteRechargeProduct failed: %v", err) + } + remaining, total, err := svc.ListAdminRechargeProducts(context.Background(), ledger.ListRechargeProductsQuery{AppCode: "lalu", Page: 1, PageSize: 10}) + if err != nil { + t.Fatalf("ListAdminRechargeProducts after delete failed: %v", err) + } + if total != 0 || len(remaining) != 0 { + t.Fatalf("deleted product must disappear: total=%d products=%+v", total, remaining) + } +} + func TestApplyGameCoinChangeDebitCreditAndIdempotency(t *testing.T) { repository := mysqltest.NewRepository(t) repository.SetBalance(88001, 500) diff --git a/services/wallet-service/internal/storage/mysql/app_wallet_repository.go b/services/wallet-service/internal/storage/mysql/app_wallet_repository.go index 1bac04c0..fc397e90 100644 --- a/services/wallet-service/internal/storage/mysql/app_wallet_repository.go +++ b/services/wallet-service/internal/storage/mysql/app_wallet_repository.go @@ -51,57 +51,6 @@ func (r *Repository) GetWalletValueSummary(ctx context.Context, userID int64) (l }, nil } -// ListRechargeProducts 把区域充值政策投影成 App 可展示的充值档位。 -func (r *Repository) ListRechargeProducts(ctx context.Context, _ int64, regionID int64) ([]ledger.RechargeProduct, []string, error) { - if r == nil || r.db == nil { - return nil, nil, xerr.New(xerr.Unavailable, "mysql repository is not configured") - } - app := appcode.FromContext(ctx) - nowMs := time.Now().UnixMilli() - rows, err := r.db.QueryContext(ctx, ` - SELECT policy_id, policy_version, currency_code, coin_amount, usd_minor_amount - FROM wallet_recharge_policies - WHERE app_code = ? AND region_id = ? AND status = 'active' - AND effective_from_ms <= ? AND (effective_to_ms IS NULL OR effective_to_ms > ?) - ORDER BY usd_minor_amount ASC, policy_id ASC`, - app, regionID, nowMs, nowMs, - ) - if err != nil { - return nil, nil, err - } - defer rows.Close() - - channels := []string{"google", "apple", "third_party", "coin_seller"} - products := make([]ledger.RechargeProduct, 0) - for rows.Next() { - var policyID int64 - var version string - var currency string - var coinAmount int64 - var amountMinor int64 - if err := rows.Scan(&policyID, &version, ¤cy, &coinAmount, &amountMinor); err != nil { - return nil, nil, err - } - for _, channel := range channels[:3] { - products = append(products, ledger.RechargeProduct{ - ProductID: policyID, - ProductCode: fmt.Sprintf("%s_%d", channel, policyID), - Channel: channel, - CurrencyCode: currency, - CoinAmount: coinAmount, - AmountMinor: amountMinor, - PolicyVersion: version, - Enabled: true, - SortOrder: int32(len(products) + 1), - }) - } - } - if err := rows.Err(); err != nil { - return nil, nil, err - } - return products, channels, nil -} - // GetDiamondExchangeConfig 返回后台配置的钻石兑换规则,未配置时返回空列表而不是 gateway 默认值。 func (r *Repository) GetDiamondExchangeConfig(ctx context.Context, _ int64) ([]ledger.DiamondExchangeRule, error) { if r == nil || r.db == nil { diff --git a/services/wallet-service/internal/storage/mysql/recharge_product_repository.go b/services/wallet-service/internal/storage/mysql/recharge_product_repository.go new file mode 100644 index 00000000..875f0d02 --- /dev/null +++ b/services/wallet-service/internal/storage/mysql/recharge_product_repository.go @@ -0,0 +1,456 @@ +package mysql + +import ( + "context" + "database/sql" + "errors" + "fmt" + "sort" + "strings" + "time" + + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + "hyapp/services/wallet-service/internal/domain/ledger" + + mysqlDriver "github.com/go-sql-driver/mysql" +) + +// ListRechargeProducts 返回 App 当前区域和平台可购买的内购商品;只读取已上架配置。 +func (r *Repository) ListRechargeProducts(ctx context.Context, _ int64, regionID int64, platform string) ([]ledger.RechargeProduct, []string, error) { + if r == nil || r.db == nil { + return nil, nil, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + app := appcode.FromContext(ctx) + platform = ledger.NormalizeRechargeProductPlatform(platform) + where := ` + WHERE p.app_code = ? AND p.status = ? AND pr.region_id = ?` + args := []any{app, ledger.RechargeProductStatusActive, regionID} + if platform != "" { + where += ` AND p.platform = ?` + args = append(args, platform) + } + rows, err := r.db.QueryContext(ctx, rechargeProductSelectSQL()+` + JOIN wallet_recharge_product_regions pr + ON pr.app_code = p.app_code AND pr.product_id = p.product_id + `+where+` + ORDER BY p.amount_micro ASC, p.product_id ASC`, args...) + if err != nil { + return nil, nil, err + } + defer rows.Close() + + products := make([]ledger.RechargeProduct, 0) + channels := make([]string, 0, 2) + seenChannels := map[string]struct{}{} + for rows.Next() { + product, err := scanRechargeProduct(rows) + if err != nil { + return nil, nil, err + } + product.RegionIDs = []int64{regionID} + products = append(products, product) + if product.Channel != "" { + if _, ok := seenChannels[product.Channel]; !ok { + seenChannels[product.Channel] = struct{}{} + channels = append(channels, product.Channel) + } + } + } + return products, channels, rows.Err() +} + +// ListAdminRechargeProducts 返回后台内购配置分页列表,并带出支持区域集合。 +func (r *Repository) ListAdminRechargeProducts(ctx context.Context, query ledger.ListRechargeProductsQuery) ([]ledger.RechargeProduct, 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) + query.AppCode = appcode.FromContext(ctx) + query = normalizeRechargeProductQuery(query) + where, args := rechargeProductWhereSQL(query) + total, err := r.countRechargeProducts(ctx, where, args...) + if err != nil { + return nil, 0, err + } + rows, err := r.db.QueryContext(ctx, rechargeProductSelectSQL()+` + `+where+` + ORDER BY p.product_id DESC + LIMIT ? OFFSET ?`, + append(args, query.PageSize, resourceOffset(query.Page, query.PageSize))..., + ) + if err != nil { + return nil, 0, err + } + defer rows.Close() + + products := make([]ledger.RechargeProduct, 0, query.PageSize) + for rows.Next() { + product, err := scanRechargeProduct(rows) + if err != nil { + return nil, 0, err + } + products = append(products, product) + } + if err := rows.Err(); err != nil { + return nil, 0, err + } + if err := r.attachRechargeProductRegions(ctx, r.db, query.AppCode, products); err != nil { + return nil, 0, err + } + return products, total, nil +} + +// CreateRechargeProduct 写入内购商品和区域映射,product_code 由商品 ID 派生保持稳定。 +func (r *Repository) CreateRechargeProduct(ctx context.Context, command ledger.RechargeProductCommand) (ledger.RechargeProduct, error) { + if r == nil || r.db == nil { + return ledger.RechargeProduct{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + ctx = contextWithCommandApp(ctx, command.AppCode) + command = normalizeRechargeProductCommand(command) + command.AppCode = appcode.FromContext(ctx) + + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return ledger.RechargeProduct{}, err + } + defer func() { _ = tx.Rollback() }() + + nowMs := time.Now().UnixMilli() + result, err := tx.ExecContext(ctx, ` + INSERT INTO wallet_recharge_products ( + app_code, product_name, description, platform, channel, currency_code, amount_micro, + coin_amount, resource_asset_type, status, sort_order, created_by_user_id, updated_by_user_id, + created_at_ms, updated_at_ms + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + command.AppCode, command.ProductName, command.Description, command.Platform, + ledger.RechargeChannelForPlatform(command.Platform), ledger.PaidCurrencyUSDT, command.AmountMicro, + command.CoinAmount, ledger.AssetCoin, productStatus(command.Enabled), 0, + command.OperatorUserID, command.OperatorUserID, nowMs, nowMs, + ) + if err != nil { + return ledger.RechargeProduct{}, mapRechargeProductWriteError(err) + } + productID, err := result.LastInsertId() + if err != nil { + return ledger.RechargeProduct{}, err + } + productCode := fmt.Sprintf("iap_%s_%d", command.Platform, productID) + if _, err := tx.ExecContext(ctx, ` + UPDATE wallet_recharge_products + SET product_code = ? + WHERE app_code = ? AND product_id = ?`, + productCode, command.AppCode, productID, + ); err != nil { + return ledger.RechargeProduct{}, mapRechargeProductWriteError(err) + } + if err := replaceRechargeProductRegions(ctx, tx, command.AppCode, productID, command.RegionIDs, nowMs); err != nil { + return ledger.RechargeProduct{}, err + } + if err := tx.Commit(); err != nil { + return ledger.RechargeProduct{}, err + } + return r.GetRechargeProduct(ctx, command.AppCode, productID) +} + +// UpdateRechargeProduct 覆盖商品展示、价格、平台、上架状态和区域映射。 +func (r *Repository) UpdateRechargeProduct(ctx context.Context, command ledger.RechargeProductCommand) (ledger.RechargeProduct, error) { + if r == nil || r.db == nil { + return ledger.RechargeProduct{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + ctx = contextWithCommandApp(ctx, command.AppCode) + command = normalizeRechargeProductCommand(command) + command.AppCode = appcode.FromContext(ctx) + + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return ledger.RechargeProduct{}, err + } + defer func() { _ = tx.Rollback() }() + + nowMs := time.Now().UnixMilli() + result, err := tx.ExecContext(ctx, ` + UPDATE wallet_recharge_products + SET product_name = ?, description = ?, platform = ?, channel = ?, currency_code = ?, + amount_micro = ?, coin_amount = ?, resource_asset_type = ?, status = ?, + updated_by_user_id = ?, updated_at_ms = ? + WHERE app_code = ? AND product_id = ?`, + command.ProductName, command.Description, command.Platform, ledger.RechargeChannelForPlatform(command.Platform), + ledger.PaidCurrencyUSDT, command.AmountMicro, command.CoinAmount, ledger.AssetCoin, productStatus(command.Enabled), + command.OperatorUserID, nowMs, command.AppCode, command.ProductID, + ) + if err != nil { + return ledger.RechargeProduct{}, mapRechargeProductWriteError(err) + } + if affected, err := result.RowsAffected(); err != nil { + return ledger.RechargeProduct{}, err + } else if affected == 0 { + var matched int + err := tx.QueryRowContext(ctx, ` + SELECT 1 + FROM wallet_recharge_products + WHERE app_code = ? AND product_id = ?`, + command.AppCode, command.ProductID, + ).Scan(&matched) + if errors.Is(err, sql.ErrNoRows) { + return ledger.RechargeProduct{}, xerr.New(xerr.NotFound, "recharge product not found") + } + if err != nil { + return ledger.RechargeProduct{}, err + } + } + if err := replaceRechargeProductRegions(ctx, tx, command.AppCode, command.ProductID, command.RegionIDs, nowMs); err != nil { + return ledger.RechargeProduct{}, err + } + if err := tx.Commit(); err != nil { + return ledger.RechargeProduct{}, err + } + return r.GetRechargeProduct(ctx, command.AppCode, command.ProductID) +} + +// DeleteRechargeProduct 删除商品配置和区域映射;当前 provider 订单未落表,因此不保留软删除历史。 +func (r *Repository) DeleteRechargeProduct(ctx context.Context, appCode string, productID int64) error { + if r == nil || r.db == nil { + return xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + ctx = contextWithCommandApp(ctx, appCode) + appCode = appcode.FromContext(ctx) + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return err + } + defer func() { _ = tx.Rollback() }() + if _, err := tx.ExecContext(ctx, ` + DELETE FROM wallet_recharge_product_regions + WHERE app_code = ? AND product_id = ?`, + appCode, productID, + ); err != nil { + return err + } + result, err := tx.ExecContext(ctx, ` + DELETE FROM wallet_recharge_products + WHERE app_code = ? AND product_id = ?`, + appCode, productID, + ) + if err != nil { + return err + } + if affected, err := result.RowsAffected(); err != nil { + return err + } else if affected == 0 { + return xerr.New(xerr.NotFound, "recharge product not found") + } + return tx.Commit() +} + +func (r *Repository) GetRechargeProduct(ctx context.Context, appCode string, productID int64) (ledger.RechargeProduct, error) { + ctx = contextWithCommandApp(ctx, appCode) + appCode = appcode.FromContext(ctx) + product, err := scanRechargeProduct(r.db.QueryRowContext(ctx, rechargeProductSelectSQL()+` + WHERE p.app_code = ? AND p.product_id = ?`, + appCode, productID, + )) + if errors.Is(err, sql.ErrNoRows) { + return ledger.RechargeProduct{}, xerr.New(xerr.NotFound, "recharge product not found") + } + if err != nil { + return ledger.RechargeProduct{}, err + } + products := []ledger.RechargeProduct{product} + if err := r.attachRechargeProductRegions(ctx, r.db, appCode, products); err != nil { + return ledger.RechargeProduct{}, err + } + return products[0], nil +} + +func rechargeProductSelectSQL() string { + return ` + SELECT p.app_code, p.product_id, COALESCE(p.product_code, ''), p.product_name, + p.description, p.platform, p.channel, p.currency_code, p.amount_micro, + p.coin_amount, p.resource_asset_type, p.status, p.sort_order, + p.created_by_user_id, p.updated_by_user_id, p.created_at_ms, p.updated_at_ms + FROM wallet_recharge_products p + ` +} + +func scanRechargeProduct(scanner scanTarget) (ledger.RechargeProduct, error) { + var product ledger.RechargeProduct + var createdBy sql.NullInt64 + var updatedBy sql.NullInt64 + if err := scanner.Scan( + &product.AppCode, + &product.ProductID, + &product.ProductCode, + &product.ProductName, + &product.Description, + &product.Platform, + &product.Channel, + &product.CurrencyCode, + &product.AmountMicro, + &product.CoinAmount, + &product.ResourceAssetType, + &product.Status, + &product.SortOrder, + &createdBy, + &updatedBy, + &product.CreatedAtMS, + &product.UpdatedAtMS, + ); err != nil { + return ledger.RechargeProduct{}, err + } + if product.ProductCode == "" && product.ProductID > 0 { + product.ProductCode = fmt.Sprintf("iap_%s_%d", product.Platform, product.ProductID) + } + if product.Channel == "" { + product.Channel = ledger.RechargeChannelForPlatform(product.Platform) + } + product.AmountMinor = product.AmountMicro + product.Enabled = product.Status == ledger.RechargeProductStatusActive + if createdBy.Valid { + product.CreatedByUserID = createdBy.Int64 + } + if updatedBy.Valid { + product.UpdatedByUserID = updatedBy.Int64 + } + return product, nil +} + +func (r *Repository) attachRechargeProductRegions(ctx context.Context, q sqlQuerier, appCode string, products []ledger.RechargeProduct) error { + if len(products) == 0 { + return nil + } + productIDs := make([]any, 0, len(products)) + productByID := make(map[int64]*ledger.RechargeProduct, len(products)) + for index := range products { + productIDs = append(productIDs, products[index].ProductID) + productByID[products[index].ProductID] = &products[index] + } + placeholders := strings.TrimSuffix(strings.Repeat("?,", len(productIDs)), ",") + args := append([]any{appCode}, productIDs...) + rows, err := q.QueryContext(ctx, ` + SELECT product_id, region_id + FROM wallet_recharge_product_regions + WHERE app_code = ? AND product_id IN (`+placeholders+`) + ORDER BY product_id ASC, region_id ASC`, args...) + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var productID int64 + var regionID int64 + if err := rows.Scan(&productID, ®ionID); err != nil { + return err + } + if product := productByID[productID]; product != nil { + product.RegionIDs = append(product.RegionIDs, regionID) + } + } + return rows.Err() +} + +func replaceRechargeProductRegions(ctx context.Context, tx *sql.Tx, appCode string, productID int64, regionIDs []int64, nowMs int64) error { + if _, err := tx.ExecContext(ctx, ` + DELETE FROM wallet_recharge_product_regions + WHERE app_code = ? AND product_id = ?`, + appCode, productID, + ); err != nil { + return err + } + for _, regionID := range regionIDs { + if _, err := tx.ExecContext(ctx, ` + INSERT INTO wallet_recharge_product_regions (app_code, product_id, region_id, created_at_ms) + VALUES (?, ?, ?, ?)`, + appCode, productID, regionID, nowMs, + ); err != nil { + return err + } + } + return nil +} + +func normalizeRechargeProductQuery(query ledger.ListRechargeProductsQuery) ledger.ListRechargeProductsQuery { + query.Status = ledger.NormalizeRechargeProductStatus(query.Status) + query.Platform = ledger.NormalizeRechargeProductPlatform(query.Platform) + query.Keyword = strings.TrimSpace(query.Keyword) + query.Page, query.PageSize = normalizePage(query.Page, query.PageSize) + return query +} + +func rechargeProductWhereSQL(query ledger.ListRechargeProductsQuery) (string, []any) { + where := `WHERE p.app_code = ?` + args := []any{query.AppCode} + if query.Status != "" { + where += ` AND p.status = ?` + args = append(args, query.Status) + } + if query.Platform != "" { + where += ` AND p.platform = ?` + args = append(args, query.Platform) + } + if query.RegionID > 0 { + where += ` AND EXISTS ( + SELECT 1 FROM wallet_recharge_product_regions pr + WHERE pr.app_code = p.app_code AND pr.product_id = p.product_id AND pr.region_id = ? + )` + args = append(args, query.RegionID) + } + if query.Keyword != "" { + like := "%" + query.Keyword + "%" + where += ` AND (p.product_code LIKE ? OR p.product_name LIKE ? OR p.description LIKE ?)` + args = append(args, like, like, like) + } + return where, args +} + +func (r *Repository) countRechargeProducts(ctx context.Context, where string, args ...any) (int64, error) { + var total int64 + err := r.db.QueryRowContext(ctx, ` + SELECT COUNT(*) + FROM wallet_recharge_products p + `+where, + args..., + ).Scan(&total) + return total, err +} + +func normalizeRechargeProductCommand(command ledger.RechargeProductCommand) ledger.RechargeProductCommand { + command.AppCode = appcode.Normalize(command.AppCode) + command.ProductName = strings.TrimSpace(command.ProductName) + command.Description = strings.TrimSpace(command.Description) + command.Platform = ledger.NormalizeRechargeProductPlatform(command.Platform) + command.RegionIDs = normalizeRechargeProductRegions(command.RegionIDs) + return command +} + +func normalizeRechargeProductRegions(regionIDs []int64) []int64 { + seen := make(map[int64]struct{}, len(regionIDs)) + out := make([]int64, 0, len(regionIDs)) + for _, regionID := range regionIDs { + if regionID <= 0 { + continue + } + if _, ok := seen[regionID]; ok { + continue + } + seen[regionID] = struct{}{} + out = append(out, regionID) + } + sort.Slice(out, func(i, j int) bool { return out[i] < out[j] }) + return out +} + +func productStatus(enabled bool) string { + if enabled { + return ledger.RechargeProductStatusActive + } + return ledger.RechargeProductStatusDisabled +} + +func mapRechargeProductWriteError(err error) error { + var mysqlErr *mysqlDriver.MySQLError + if errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 { + return xerr.New(xerr.Conflict, "recharge product already exists") + } + return err +} diff --git a/services/wallet-service/internal/storage/mysql/resource_repository.go b/services/wallet-service/internal/storage/mysql/resource_repository.go index f6edfa8b..663accc3 100644 --- a/services/wallet-service/internal/storage/mysql/resource_repository.go +++ b/services/wallet-service/internal/storage/mysql/resource_repository.go @@ -2273,7 +2273,7 @@ func validateActiveResourceGroupResource(resource resourcedomain.Resource) error func isEquipableResourceType(resourceType string) bool { switch resourcedomain.NormalizeResourceType(resourceType) { - case resourcedomain.TypeAvatarFrame, resourcedomain.TypeVehicle, resourcedomain.TypeChatBubble, resourcedomain.TypeBadge: + case resourcedomain.TypeAvatarFrame, resourcedomain.TypeProfileCard, resourcedomain.TypeVehicle, resourcedomain.TypeChatBubble, resourcedomain.TypeBadge: return true default: return false diff --git a/services/wallet-service/internal/storage/mysql/resource_repository_test.go b/services/wallet-service/internal/storage/mysql/resource_repository_test.go new file mode 100644 index 00000000..9fcb011c --- /dev/null +++ b/services/wallet-service/internal/storage/mysql/resource_repository_test.go @@ -0,0 +1,13 @@ +package mysql + +import ( + "testing" + + resourcedomain "hyapp/services/wallet-service/internal/domain/resource" +) + +func TestProfileCardResourceIsEquipable(t *testing.T) { + if !isEquipableResourceType(resourcedomain.TypeProfileCard) { + t.Fatalf("profile_card resources must use the equipment slot just like other profile decorations") + } +} diff --git a/services/wallet-service/internal/transport/grpc/server.go b/services/wallet-service/internal/transport/grpc/server.go index 8f4aa8e9..453c64cc 100644 --- a/services/wallet-service/internal/transport/grpc/server.go +++ b/services/wallet-service/internal/transport/grpc/server.go @@ -104,27 +104,89 @@ func (s *Server) GetWalletValueSummary(ctx context.Context, req *walletv1.GetWal // ListRechargeProducts 返回当前用户区域可用的充值渠道和档位。 func (s *Server) ListRechargeProducts(ctx context.Context, req *walletv1.ListRechargeProductsRequest) (*walletv1.ListRechargeProductsResponse, error) { ctx = appcode.WithContext(ctx, req.GetAppCode()) - products, channels, err := s.svc.ListRechargeProducts(ctx, req.GetUserId(), req.GetRegionId()) + products, channels, err := s.svc.ListRechargeProducts(ctx, req.GetUserId(), req.GetRegionId(), req.GetPlatform()) if err != nil { return nil, xerr.ToGRPCError(err) } resp := &walletv1.ListRechargeProductsResponse{Channels: channels, Products: make([]*walletv1.RechargeProduct, 0, len(products))} for _, product := range products { - resp.Products = append(resp.Products, &walletv1.RechargeProduct{ - ProductId: product.ProductID, - ProductCode: product.ProductCode, - Channel: product.Channel, - CurrencyCode: product.CurrencyCode, - CoinAmount: product.CoinAmount, - AmountMinor: product.AmountMinor, - PolicyVersion: product.PolicyVersion, - Enabled: product.Enabled, - SortOrder: product.SortOrder, - }) + resp.Products = append(resp.Products, rechargeProductToProto(product)) } return resp, nil } +// ListAdminRechargeProducts 返回后台内购配置列表。 +func (s *Server) ListAdminRechargeProducts(ctx context.Context, req *walletv1.ListAdminRechargeProductsRequest) (*walletv1.ListAdminRechargeProductsResponse, error) { + ctx = appcode.WithContext(ctx, req.GetAppCode()) + products, total, err := s.svc.ListAdminRechargeProducts(ctx, ledger.ListRechargeProductsQuery{ + AppCode: req.GetAppCode(), + Status: req.GetStatus(), + Platform: req.GetPlatform(), + RegionID: req.GetRegionId(), + Keyword: req.GetKeyword(), + Page: req.GetPage(), + PageSize: req.GetPageSize(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + resp := &walletv1.ListAdminRechargeProductsResponse{Products: make([]*walletv1.RechargeProduct, 0, len(products)), Total: total} + for _, product := range products { + resp.Products = append(resp.Products, rechargeProductToProto(product)) + } + return resp, nil +} + +// CreateRechargeProduct 创建后台内购商品配置。 +func (s *Server) CreateRechargeProduct(ctx context.Context, req *walletv1.CreateRechargeProductRequest) (*walletv1.RechargeProductResponse, error) { + ctx = appcode.WithContext(ctx, req.GetAppCode()) + product, err := s.svc.CreateRechargeProduct(ctx, ledger.RechargeProductCommand{ + AppCode: req.GetAppCode(), + AmountMicro: req.GetAmountMicro(), + CoinAmount: req.GetCoinAmount(), + ProductName: req.GetProductName(), + Description: req.GetDescription(), + Platform: req.GetPlatform(), + RegionIDs: req.GetRegionIds(), + Enabled: req.GetEnabled(), + OperatorUserID: req.GetOperatorUserId(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &walletv1.RechargeProductResponse{Product: rechargeProductToProto(product)}, nil +} + +// UpdateRechargeProduct 修改后台内购商品配置。 +func (s *Server) UpdateRechargeProduct(ctx context.Context, req *walletv1.UpdateRechargeProductRequest) (*walletv1.RechargeProductResponse, error) { + ctx = appcode.WithContext(ctx, req.GetAppCode()) + product, err := s.svc.UpdateRechargeProduct(ctx, ledger.RechargeProductCommand{ + AppCode: req.GetAppCode(), + ProductID: req.GetProductId(), + AmountMicro: req.GetAmountMicro(), + CoinAmount: req.GetCoinAmount(), + ProductName: req.GetProductName(), + Description: req.GetDescription(), + Platform: req.GetPlatform(), + RegionIDs: req.GetRegionIds(), + Enabled: req.GetEnabled(), + OperatorUserID: req.GetOperatorUserId(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &walletv1.RechargeProductResponse{Product: rechargeProductToProto(product)}, nil +} + +// DeleteRechargeProduct 删除后台内购商品配置。 +func (s *Server) DeleteRechargeProduct(ctx context.Context, req *walletv1.DeleteRechargeProductRequest) (*walletv1.DeleteRechargeProductResponse, error) { + ctx = appcode.WithContext(ctx, req.GetAppCode()) + if err := s.svc.DeleteRechargeProduct(ctx, req.GetAppCode(), req.GetProductId()); err != nil { + return nil, xerr.ToGRPCError(err) + } + return &walletv1.DeleteRechargeProductResponse{Deleted: true}, nil +} + // GetDiamondExchangeConfig 返回钻石兑换配置。 func (s *Server) GetDiamondExchangeConfig(ctx context.Context, req *walletv1.GetDiamondExchangeConfigRequest) (*walletv1.GetDiamondExchangeConfigResponse, error) { ctx = appcode.WithContext(ctx, req.GetAppCode()) @@ -146,6 +208,32 @@ func (s *Server) GetDiamondExchangeConfig(ctx context.Context, req *walletv1.Get return resp, nil } +func rechargeProductToProto(product ledger.RechargeProduct) *walletv1.RechargeProduct { + return &walletv1.RechargeProduct{ + AppCode: product.AppCode, + ProductId: product.ProductID, + ProductCode: product.ProductCode, + ProductName: product.ProductName, + Description: product.Description, + Platform: product.Platform, + Channel: product.Channel, + CurrencyCode: product.CurrencyCode, + AmountMicro: product.AmountMicro, + AmountMinor: product.AmountMinor, + CoinAmount: product.CoinAmount, + PolicyVersion: product.PolicyVersion, + Status: product.Status, + Enabled: product.Enabled, + SortOrder: product.SortOrder, + RegionIds: product.RegionIDs, + ResourceAssetType: product.ResourceAssetType, + CreatedByUserId: product.CreatedByUserID, + UpdatedByUserId: product.UpdatedByUserID, + CreatedAtMs: product.CreatedAtMS, + UpdatedAtMs: product.UpdatedAtMS, + } +} + // ListWalletTransactions 返回当前用户钱包流水。 func (s *Server) ListWalletTransactions(ctx context.Context, req *walletv1.ListWalletTransactionsRequest) (*walletv1.ListWalletTransactionsResponse, error) { ctx = appcode.WithContext(ctx, req.GetAppCode())