diff --git a/api/proto/activity/v1/activity.pb.go b/api/proto/activity/v1/activity.pb.go index 5ff1de55..5e525387 100644 --- a/api/proto/activity/v1/activity.pb.go +++ b/api/proto/activity/v1/activity.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v5.29.2 +// protoc-gen-go v1.35.1 +// protoc v5.27.3 // source: proto/activity/v1/activity.proto package activityv1 @@ -35,11 +35,9 @@ type RequestMeta struct { func (x *RequestMeta) Reset() { *x = RequestMeta{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_activity_v1_activity_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_activity_v1_activity_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RequestMeta) String() string { @@ -50,7 +48,7 @@ func (*RequestMeta) ProtoMessage() {} func (x *RequestMeta) ProtoReflect() protoreflect.Message { mi := &file_proto_activity_v1_activity_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -111,11 +109,9 @@ type PingActivityRequest struct { func (x *PingActivityRequest) Reset() { *x = PingActivityRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_activity_v1_activity_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_activity_v1_activity_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingActivityRequest) String() string { @@ -126,7 +122,7 @@ func (*PingActivityRequest) ProtoMessage() {} func (x *PingActivityRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_activity_v1_activity_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -160,11 +156,9 @@ type PingActivityResponse struct { func (x *PingActivityResponse) Reset() { *x = PingActivityResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_activity_v1_activity_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_activity_v1_activity_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PingActivityResponse) String() string { @@ -175,7 +169,7 @@ func (*PingActivityResponse) ProtoMessage() {} func (x *PingActivityResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_activity_v1_activity_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -216,11 +210,9 @@ type GetActivityStatusRequest struct { func (x *GetActivityStatusRequest) Reset() { *x = GetActivityStatusRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_activity_v1_activity_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_activity_v1_activity_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetActivityStatusRequest) String() string { @@ -231,7 +223,7 @@ func (*GetActivityStatusRequest) ProtoMessage() {} func (x *GetActivityStatusRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_activity_v1_activity_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -272,11 +264,9 @@ type GetActivityStatusResponse struct { func (x *GetActivityStatusResponse) Reset() { *x = GetActivityStatusResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_activity_v1_activity_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_activity_v1_activity_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetActivityStatusResponse) String() string { @@ -287,7 +277,7 @@ func (*GetActivityStatusResponse) ProtoMessage() {} func (x *GetActivityStatusResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_activity_v1_activity_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -316,6 +306,1222 @@ func (x *GetActivityStatusResponse) GetStatus() string { return "" } +// MessageTabSection 是 App 消息 tab 的一个分区摘要。 +type MessageTabSection struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Section string `protobuf:"bytes,1,opt,name=section,proto3" json:"section,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + UnreadCount int64 `protobuf:"varint,3,opt,name=unread_count,json=unreadCount,proto3" json:"unread_count,omitempty"` + Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"` +} + +func (x *MessageTabSection) Reset() { + *x = MessageTabSection{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MessageTabSection) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageTabSection) ProtoMessage() {} + +func (x *MessageTabSection) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[5] + 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 MessageTabSection.ProtoReflect.Descriptor instead. +func (*MessageTabSection) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{5} +} + +func (x *MessageTabSection) GetSection() string { + if x != nil { + return x.Section + } + return "" +} + +func (x *MessageTabSection) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *MessageTabSection) GetUnreadCount() int64 { + if x != nil { + return x.UnreadCount + } + return 0 +} + +func (x *MessageTabSection) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +// ListMessageTabsRequest 查询当前用户消息 tab 摘要。 +type ListMessageTabsRequest 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 *ListMessageTabsRequest) Reset() { + *x = ListMessageTabsRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListMessageTabsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListMessageTabsRequest) ProtoMessage() {} + +func (x *ListMessageTabsRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[6] + 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 ListMessageTabsRequest.ProtoReflect.Descriptor instead. +func (*ListMessageTabsRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{6} +} + +func (x *ListMessageTabsRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *ListMessageTabsRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +// ListMessageTabsResponse 固定返回 user/system/activity 三个分区。 +type ListMessageTabsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Sections []*MessageTabSection `protobuf:"bytes,1,rep,name=sections,proto3" json:"sections,omitempty"` +} + +func (x *ListMessageTabsResponse) Reset() { + *x = ListMessageTabsResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListMessageTabsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListMessageTabsResponse) ProtoMessage() {} + +func (x *ListMessageTabsResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[7] + 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 ListMessageTabsResponse.ProtoReflect.Descriptor instead. +func (*ListMessageTabsResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{7} +} + +func (x *ListMessageTabsResponse) GetSections() []*MessageTabSection { + if x != nil { + return x.Sections + } + return nil +} + +// InboxMessage 是 system/activity 分区列表可展示的消息快照。 +type InboxMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageId string `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` + Section string `protobuf:"bytes,2,opt,name=section,proto3" json:"section,omitempty"` + Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"` + Summary string `protobuf:"bytes,4,opt,name=summary,proto3" json:"summary,omitempty"` + Body string `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` + IconUrl string `protobuf:"bytes,6,opt,name=icon_url,json=iconUrl,proto3" json:"icon_url,omitempty"` + ImageUrl string `protobuf:"bytes,7,opt,name=image_url,json=imageUrl,proto3" json:"image_url,omitempty"` + ActionType string `protobuf:"bytes,8,opt,name=action_type,json=actionType,proto3" json:"action_type,omitempty"` + ActionParam string `protobuf:"bytes,9,opt,name=action_param,json=actionParam,proto3" json:"action_param,omitempty"` + Read bool `protobuf:"varint,10,opt,name=read,proto3" json:"read,omitempty"` + SentAtMs int64 `protobuf:"varint,11,opt,name=sent_at_ms,json=sentAtMs,proto3" json:"sent_at_ms,omitempty"` +} + +func (x *InboxMessage) Reset() { + *x = InboxMessage{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InboxMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InboxMessage) ProtoMessage() {} + +func (x *InboxMessage) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[8] + 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 InboxMessage.ProtoReflect.Descriptor instead. +func (*InboxMessage) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{8} +} + +func (x *InboxMessage) GetMessageId() string { + if x != nil { + return x.MessageId + } + return "" +} + +func (x *InboxMessage) GetSection() string { + if x != nil { + return x.Section + } + return "" +} + +func (x *InboxMessage) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *InboxMessage) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *InboxMessage) GetBody() string { + if x != nil { + return x.Body + } + return "" +} + +func (x *InboxMessage) GetIconUrl() string { + if x != nil { + return x.IconUrl + } + return "" +} + +func (x *InboxMessage) GetImageUrl() string { + if x != nil { + return x.ImageUrl + } + return "" +} + +func (x *InboxMessage) GetActionType() string { + if x != nil { + return x.ActionType + } + return "" +} + +func (x *InboxMessage) GetActionParam() string { + if x != nil { + return x.ActionParam + } + return "" +} + +func (x *InboxMessage) GetRead() bool { + if x != nil { + return x.Read + } + return false +} + +func (x *InboxMessage) GetSentAtMs() int64 { + if x != nil { + return x.SentAtMs + } + return 0 +} + +// ListInboxMessagesRequest 按 section 和游标分页读取当前用户 inbox。 +type ListInboxMessagesRequest 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"` + Section string `protobuf:"bytes,3,opt,name=section,proto3" json:"section,omitempty"` + PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + PageToken string `protobuf:"bytes,5,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` +} + +func (x *ListInboxMessagesRequest) Reset() { + *x = ListInboxMessagesRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListInboxMessagesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListInboxMessagesRequest) ProtoMessage() {} + +func (x *ListInboxMessagesRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[9] + 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 ListInboxMessagesRequest.ProtoReflect.Descriptor instead. +func (*ListInboxMessagesRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{9} +} + +func (x *ListInboxMessagesRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *ListInboxMessagesRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *ListInboxMessagesRequest) GetSection() string { + if x != nil { + return x.Section + } + return "" +} + +func (x *ListInboxMessagesRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListInboxMessagesRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +// ListInboxMessagesResponse 返回当前页列表和下一页不透明游标。 +type ListInboxMessagesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Section string `protobuf:"bytes,1,opt,name=section,proto3" json:"section,omitempty"` + Items []*InboxMessage `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` + NextPageToken string `protobuf:"bytes,3,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListInboxMessagesResponse) Reset() { + *x = ListInboxMessagesResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListInboxMessagesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListInboxMessagesResponse) ProtoMessage() {} + +func (x *ListInboxMessagesResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_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 ListInboxMessagesResponse.ProtoReflect.Descriptor instead. +func (*ListInboxMessagesResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{10} +} + +func (x *ListInboxMessagesResponse) GetSection() string { + if x != nil { + return x.Section + } + return "" +} + +func (x *ListInboxMessagesResponse) GetItems() []*InboxMessage { + if x != nil { + return x.Items + } + return nil +} + +func (x *ListInboxMessagesResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// MarkInboxMessageReadRequest 标记单条消息已读。 +type MarkInboxMessageReadRequest 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"` + MessageId string `protobuf:"bytes,3,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` +} + +func (x *MarkInboxMessageReadRequest) Reset() { + *x = MarkInboxMessageReadRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MarkInboxMessageReadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkInboxMessageReadRequest) ProtoMessage() {} + +func (x *MarkInboxMessageReadRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[11] + 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 MarkInboxMessageReadRequest.ProtoReflect.Descriptor instead. +func (*MarkInboxMessageReadRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{11} +} + +func (x *MarkInboxMessageReadRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *MarkInboxMessageReadRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *MarkInboxMessageReadRequest) GetMessageId() string { + if x != nil { + return x.MessageId + } + return "" +} + +// MarkInboxMessageReadResponse 返回消息首次已读时间;重复请求不覆盖该时间。 +type MarkInboxMessageReadResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageId string `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` + Read bool `protobuf:"varint,2,opt,name=read,proto3" json:"read,omitempty"` + ReadAtMs int64 `protobuf:"varint,3,opt,name=read_at_ms,json=readAtMs,proto3" json:"read_at_ms,omitempty"` +} + +func (x *MarkInboxMessageReadResponse) Reset() { + *x = MarkInboxMessageReadResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MarkInboxMessageReadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkInboxMessageReadResponse) ProtoMessage() {} + +func (x *MarkInboxMessageReadResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[12] + 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 MarkInboxMessageReadResponse.ProtoReflect.Descriptor instead. +func (*MarkInboxMessageReadResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{12} +} + +func (x *MarkInboxMessageReadResponse) GetMessageId() string { + if x != nil { + return x.MessageId + } + return "" +} + +func (x *MarkInboxMessageReadResponse) GetRead() bool { + if x != nil { + return x.Read + } + return false +} + +func (x *MarkInboxMessageReadResponse) GetReadAtMs() int64 { + if x != nil { + return x.ReadAtMs + } + return 0 +} + +// MarkInboxSectionReadRequest 标记一个 section 下当前可见未读消息全部已读。 +type MarkInboxSectionReadRequest 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"` + Section string `protobuf:"bytes,3,opt,name=section,proto3" json:"section,omitempty"` +} + +func (x *MarkInboxSectionReadRequest) Reset() { + *x = MarkInboxSectionReadRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MarkInboxSectionReadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkInboxSectionReadRequest) ProtoMessage() {} + +func (x *MarkInboxSectionReadRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[13] + 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 MarkInboxSectionReadRequest.ProtoReflect.Descriptor instead. +func (*MarkInboxSectionReadRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{13} +} + +func (x *MarkInboxSectionReadRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *MarkInboxSectionReadRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *MarkInboxSectionReadRequest) GetSection() string { + if x != nil { + return x.Section + } + return "" +} + +// MarkInboxSectionReadResponse 返回本次实际变更的消息数量。 +type MarkInboxSectionReadResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Section string `protobuf:"bytes,1,opt,name=section,proto3" json:"section,omitempty"` + ReadCount int64 `protobuf:"varint,2,opt,name=read_count,json=readCount,proto3" json:"read_count,omitempty"` +} + +func (x *MarkInboxSectionReadResponse) Reset() { + *x = MarkInboxSectionReadResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MarkInboxSectionReadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkInboxSectionReadResponse) ProtoMessage() {} + +func (x *MarkInboxSectionReadResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[14] + 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 MarkInboxSectionReadResponse.ProtoReflect.Descriptor instead. +func (*MarkInboxSectionReadResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{14} +} + +func (x *MarkInboxSectionReadResponse) GetSection() string { + if x != nil { + return x.Section + } + return "" +} + +func (x *MarkInboxSectionReadResponse) GetReadCount() int64 { + if x != nil { + return x.ReadCount + } + return 0 +} + +// DeleteInboxMessageRequest 删除当前用户可见消息,删除是用户侧隐藏。 +type DeleteInboxMessageRequest 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"` + MessageId string `protobuf:"bytes,3,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` +} + +func (x *DeleteInboxMessageRequest) Reset() { + *x = DeleteInboxMessageRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteInboxMessageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteInboxMessageRequest) ProtoMessage() {} + +func (x *DeleteInboxMessageRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteInboxMessageRequest.ProtoReflect.Descriptor instead. +func (*DeleteInboxMessageRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{15} +} + +func (x *DeleteInboxMessageRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *DeleteInboxMessageRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *DeleteInboxMessageRequest) GetMessageId() string { + if x != nil { + return x.MessageId + } + return "" +} + +// DeleteInboxMessageResponse 返回被隐藏的消息 ID。 +type DeleteInboxMessageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageId string `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` + Deleted bool `protobuf:"varint,2,opt,name=deleted,proto3" json:"deleted,omitempty"` +} + +func (x *DeleteInboxMessageResponse) Reset() { + *x = DeleteInboxMessageResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteInboxMessageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteInboxMessageResponse) ProtoMessage() {} + +func (x *DeleteInboxMessageResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteInboxMessageResponse.ProtoReflect.Descriptor instead. +func (*DeleteInboxMessageResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{16} +} + +func (x *DeleteInboxMessageResponse) GetMessageId() string { + if x != nil { + return x.MessageId + } + return "" +} + +func (x *DeleteInboxMessageResponse) GetDeleted() bool { + if x != nil { + return x.Deleted + } + return false +} + +// CreateInboxMessageRequest 是生产者入箱命令;producer_event_id 是幂等键。 +type CreateInboxMessageRequest 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"` + Producer string `protobuf:"bytes,3,opt,name=producer,proto3" json:"producer,omitempty"` + ProducerEventId string `protobuf:"bytes,4,opt,name=producer_event_id,json=producerEventId,proto3" json:"producer_event_id,omitempty"` + ProducerEventType string `protobuf:"bytes,5,opt,name=producer_event_type,json=producerEventType,proto3" json:"producer_event_type,omitempty"` + MessageType string `protobuf:"bytes,6,opt,name=message_type,json=messageType,proto3" json:"message_type,omitempty"` + AggregateType string `protobuf:"bytes,7,opt,name=aggregate_type,json=aggregateType,proto3" json:"aggregate_type,omitempty"` + AggregateId string `protobuf:"bytes,8,opt,name=aggregate_id,json=aggregateId,proto3" json:"aggregate_id,omitempty"` + TemplateId string `protobuf:"bytes,9,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + TemplateVersion string `protobuf:"bytes,10,opt,name=template_version,json=templateVersion,proto3" json:"template_version,omitempty"` + Title string `protobuf:"bytes,11,opt,name=title,proto3" json:"title,omitempty"` + Summary string `protobuf:"bytes,12,opt,name=summary,proto3" json:"summary,omitempty"` + Body string `protobuf:"bytes,13,opt,name=body,proto3" json:"body,omitempty"` + IconUrl string `protobuf:"bytes,14,opt,name=icon_url,json=iconUrl,proto3" json:"icon_url,omitempty"` + ImageUrl string `protobuf:"bytes,15,opt,name=image_url,json=imageUrl,proto3" json:"image_url,omitempty"` + ActionType string `protobuf:"bytes,16,opt,name=action_type,json=actionType,proto3" json:"action_type,omitempty"` + ActionParam string `protobuf:"bytes,17,opt,name=action_param,json=actionParam,proto3" json:"action_param,omitempty"` + Priority int32 `protobuf:"varint,18,opt,name=priority,proto3" json:"priority,omitempty"` + SentAtMs int64 `protobuf:"varint,19,opt,name=sent_at_ms,json=sentAtMs,proto3" json:"sent_at_ms,omitempty"` + ExpireAtMs int64 `protobuf:"varint,20,opt,name=expire_at_ms,json=expireAtMs,proto3" json:"expire_at_ms,omitempty"` + MetadataJson string `protobuf:"bytes,21,opt,name=metadata_json,json=metadataJson,proto3" json:"metadata_json,omitempty"` +} + +func (x *CreateInboxMessageRequest) Reset() { + *x = CreateInboxMessageRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateInboxMessageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateInboxMessageRequest) ProtoMessage() {} + +func (x *CreateInboxMessageRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateInboxMessageRequest.ProtoReflect.Descriptor instead. +func (*CreateInboxMessageRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{17} +} + +func (x *CreateInboxMessageRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *CreateInboxMessageRequest) GetTargetUserId() int64 { + if x != nil { + return x.TargetUserId + } + return 0 +} + +func (x *CreateInboxMessageRequest) GetProducer() string { + if x != nil { + return x.Producer + } + return "" +} + +func (x *CreateInboxMessageRequest) GetProducerEventId() string { + if x != nil { + return x.ProducerEventId + } + return "" +} + +func (x *CreateInboxMessageRequest) GetProducerEventType() string { + if x != nil { + return x.ProducerEventType + } + return "" +} + +func (x *CreateInboxMessageRequest) GetMessageType() string { + if x != nil { + return x.MessageType + } + return "" +} + +func (x *CreateInboxMessageRequest) GetAggregateType() string { + if x != nil { + return x.AggregateType + } + return "" +} + +func (x *CreateInboxMessageRequest) GetAggregateId() string { + if x != nil { + return x.AggregateId + } + return "" +} + +func (x *CreateInboxMessageRequest) GetTemplateId() string { + if x != nil { + return x.TemplateId + } + return "" +} + +func (x *CreateInboxMessageRequest) GetTemplateVersion() string { + if x != nil { + return x.TemplateVersion + } + return "" +} + +func (x *CreateInboxMessageRequest) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *CreateInboxMessageRequest) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *CreateInboxMessageRequest) GetBody() string { + if x != nil { + return x.Body + } + return "" +} + +func (x *CreateInboxMessageRequest) GetIconUrl() string { + if x != nil { + return x.IconUrl + } + return "" +} + +func (x *CreateInboxMessageRequest) GetImageUrl() string { + if x != nil { + return x.ImageUrl + } + return "" +} + +func (x *CreateInboxMessageRequest) GetActionType() string { + if x != nil { + return x.ActionType + } + return "" +} + +func (x *CreateInboxMessageRequest) GetActionParam() string { + if x != nil { + return x.ActionParam + } + return "" +} + +func (x *CreateInboxMessageRequest) GetPriority() int32 { + if x != nil { + return x.Priority + } + return 0 +} + +func (x *CreateInboxMessageRequest) GetSentAtMs() int64 { + if x != nil { + return x.SentAtMs + } + return 0 +} + +func (x *CreateInboxMessageRequest) GetExpireAtMs() int64 { + if x != nil { + return x.ExpireAtMs + } + return 0 +} + +func (x *CreateInboxMessageRequest) GetMetadataJson() string { + if x != nil { + return x.MetadataJson + } + return "" +} + +// CreateInboxMessageResponse 返回入箱结果;重复同一 producer_event_id 时 created=false。 +type CreateInboxMessageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageId string `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` + Created bool `protobuf:"varint,2,opt,name=created,proto3" json:"created,omitempty"` +} + +func (x *CreateInboxMessageResponse) Reset() { + *x = CreateInboxMessageResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateInboxMessageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateInboxMessageResponse) ProtoMessage() {} + +func (x *CreateInboxMessageResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateInboxMessageResponse.ProtoReflect.Descriptor instead. +func (*CreateInboxMessageResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{18} +} + +func (x *CreateInboxMessageResponse) GetMessageId() string { + if x != nil { + return x.MessageId + } + return "" +} + +func (x *CreateInboxMessageResponse) GetCreated() bool { + if x != nil { + return x.Created + } + return false +} + +// CreateFanoutJobRequest 创建后台 fanout 任务;command_id 是后台命令幂等键。 +type CreateFanoutJobRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + CommandId string `protobuf:"bytes,2,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + MessageType string `protobuf:"bytes,3,opt,name=message_type,json=messageType,proto3" json:"message_type,omitempty"` + TargetScope string `protobuf:"bytes,4,opt,name=target_scope,json=targetScope,proto3" json:"target_scope,omitempty"` + TargetFilterJson string `protobuf:"bytes,5,opt,name=target_filter_json,json=targetFilterJson,proto3" json:"target_filter_json,omitempty"` + TemplateSnapshotJson string `protobuf:"bytes,6,opt,name=template_snapshot_json,json=templateSnapshotJson,proto3" json:"template_snapshot_json,omitempty"` + BatchSize int32 `protobuf:"varint,7,opt,name=batch_size,json=batchSize,proto3" json:"batch_size,omitempty"` + CreatedBy string `protobuf:"bytes,8,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` +} + +func (x *CreateFanoutJobRequest) Reset() { + *x = CreateFanoutJobRequest{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateFanoutJobRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateFanoutJobRequest) ProtoMessage() {} + +func (x *CreateFanoutJobRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateFanoutJobRequest.ProtoReflect.Descriptor instead. +func (*CreateFanoutJobRequest) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{19} +} + +func (x *CreateFanoutJobRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *CreateFanoutJobRequest) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +func (x *CreateFanoutJobRequest) GetMessageType() string { + if x != nil { + return x.MessageType + } + return "" +} + +func (x *CreateFanoutJobRequest) GetTargetScope() string { + if x != nil { + return x.TargetScope + } + return "" +} + +func (x *CreateFanoutJobRequest) GetTargetFilterJson() string { + if x != nil { + return x.TargetFilterJson + } + return "" +} + +func (x *CreateFanoutJobRequest) GetTemplateSnapshotJson() string { + if x != nil { + return x.TemplateSnapshotJson + } + return "" +} + +func (x *CreateFanoutJobRequest) GetBatchSize() int32 { + if x != nil { + return x.BatchSize + } + return 0 +} + +func (x *CreateFanoutJobRequest) GetCreatedBy() string { + if x != nil { + return x.CreatedBy + } + return "" +} + +// CreateFanoutJobResponse 返回 fanout job 幂等创建结果。 +type CreateFanoutJobResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + Created bool `protobuf:"varint,3,opt,name=created,proto3" json:"created,omitempty"` +} + +func (x *CreateFanoutJobResponse) Reset() { + *x = CreateFanoutJobResponse{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateFanoutJobResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateFanoutJobResponse) ProtoMessage() {} + +func (x *CreateFanoutJobResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[20] + 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 CreateFanoutJobResponse.ProtoReflect.Descriptor instead. +func (*CreateFanoutJobResponse) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{20} +} + +func (x *CreateFanoutJobResponse) GetJobId() string { + if x != nil { + return x.JobId + } + return "" +} + +func (x *CreateFanoutJobResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *CreateFanoutJobResponse) GetCreated() bool { + if x != nil { + return x.Created + } + return false +} + var File_proto_activity_v1_activity_proto protoreflect.FileDescriptor var file_proto_activity_v1_activity_proto_rawDesc = []byte{ @@ -354,6 +1560,191 @@ var file_proto_activity_v1_activity_proto_rawDesc = []byte{ 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x49, 0x64, 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, 0x7e, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x61, 0x62, 0x53, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x6e, 0x72, + 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x22, 0x65, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x61, 0x62, 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, 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, 0x5b, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x61, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x61, 0x62, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb9, 0x02, 0x0a, 0x0c, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x12, + 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, + 0x64, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, + 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x12, + 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x72, 0x65, + 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x65, 0x6e, 0x74, 0x41, 0x74, 0x4d, 0x73, + 0x22, 0xbd, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 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, 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, 0x18, 0x0a, 0x07, 0x73, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 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, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x22, 0x94, 0x01, 0x0a, 0x19, 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, 0x18, + 0x0a, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, + 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, + 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x89, 0x01, 0x0a, 0x1b, 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, 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, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x49, 0x64, 0x22, 0x6f, 0x0a, 0x1c, 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, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x04, 0x72, 0x65, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x61, + 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, + 0x41, 0x74, 0x4d, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x1b, 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, 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, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x57, 0x0a, 0x1c, 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, 0x18, 0x0a, 0x07, 0x73, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x87, 0x01, 0x0a, 0x19, 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, 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, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x22, 0x55, + 0x0a, 0x1a, 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, 0x1d, 0x0a, 0x0a, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0xe7, 0x05, 0x0a, 0x19, 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, 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, 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, 0x1a, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, + 0x72, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x21, 0x0a, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x12, + 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, + 0x64, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, + 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x11, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x0a, 0x0a, 0x73, 0x65, + 0x6e, 0x74, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x73, 0x65, 0x6e, 0x74, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x65, 0x78, 0x70, 0x69, + 0x72, 0x65, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x15, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x22, + 0x55, 0x0a, 0x1a, 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, 0x1d, 0x0a, + 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0xd3, 0x02, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x46, 0x61, 0x6e, 0x6f, 0x75, 0x74, 0x4a, 0x6f, 0x62, 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, 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, 0x21, 0x0a, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x6a, 0x73, + 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x1d, + 0x0a, 0x0a, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x62, 0x0a, 0x17, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x6e, 0x6f, 0x75, 0x74, 0x4a, 0x6f, 0x62, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 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, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 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, @@ -368,10 +1759,62 @@ var file_proto_activity_v1_activity_proto_rawDesc = []byte{ 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, 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, + 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, 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, 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, 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 ( @@ -386,26 +1829,65 @@ 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, 5) +var file_proto_activity_v1_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 21) 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 + (*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 } var file_proto_activity_v1_activity_proto_depIdxs = []int32{ - 0, // 0: hyapp.activity.v1.PingActivityRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 0, // 1: hyapp.activity.v1.GetActivityStatusRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 1, // 2: hyapp.activity.v1.ActivityService.PingActivity:input_type -> hyapp.activity.v1.PingActivityRequest - 3, // 3: hyapp.activity.v1.ActivityService.GetActivityStatus:input_type -> hyapp.activity.v1.GetActivityStatusRequest - 2, // 4: hyapp.activity.v1.ActivityService.PingActivity:output_type -> hyapp.activity.v1.PingActivityResponse - 4, // 5: hyapp.activity.v1.ActivityService.GetActivityStatus:output_type -> hyapp.activity.v1.GetActivityStatusResponse - 4, // [4:6] is the sub-list for method output_type - 2, // [2:4] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 0, // 0: hyapp.activity.v1.PingActivityRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 0, // 1: hyapp.activity.v1.GetActivityStatusRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 0, // 2: hyapp.activity.v1.ListMessageTabsRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 5, // 3: hyapp.activity.v1.ListMessageTabsResponse.sections:type_name -> hyapp.activity.v1.MessageTabSection + 0, // 4: hyapp.activity.v1.ListInboxMessagesRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 8, // 5: hyapp.activity.v1.ListInboxMessagesResponse.items:type_name -> hyapp.activity.v1.InboxMessage + 0, // 6: hyapp.activity.v1.MarkInboxMessageReadRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 0, // 7: hyapp.activity.v1.MarkInboxSectionReadRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 0, // 8: hyapp.activity.v1.DeleteInboxMessageRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 0, // 9: hyapp.activity.v1.CreateInboxMessageRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 0, // 10: hyapp.activity.v1.CreateFanoutJobRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 1, // 11: hyapp.activity.v1.ActivityService.PingActivity:input_type -> hyapp.activity.v1.PingActivityRequest + 3, // 12: hyapp.activity.v1.ActivityService.GetActivityStatus:input_type -> hyapp.activity.v1.GetActivityStatusRequest + 6, // 13: hyapp.activity.v1.MessageInboxService.ListMessageTabs:input_type -> hyapp.activity.v1.ListMessageTabsRequest + 9, // 14: hyapp.activity.v1.MessageInboxService.ListInboxMessages:input_type -> hyapp.activity.v1.ListInboxMessagesRequest + 11, // 15: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:input_type -> hyapp.activity.v1.MarkInboxMessageReadRequest + 13, // 16: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:input_type -> hyapp.activity.v1.MarkInboxSectionReadRequest + 15, // 17: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:input_type -> hyapp.activity.v1.DeleteInboxMessageRequest + 17, // 18: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:input_type -> hyapp.activity.v1.CreateInboxMessageRequest + 19, // 19: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:input_type -> hyapp.activity.v1.CreateFanoutJobRequest + 2, // 20: hyapp.activity.v1.ActivityService.PingActivity:output_type -> hyapp.activity.v1.PingActivityResponse + 4, // 21: hyapp.activity.v1.ActivityService.GetActivityStatus:output_type -> hyapp.activity.v1.GetActivityStatusResponse + 7, // 22: hyapp.activity.v1.MessageInboxService.ListMessageTabs:output_type -> hyapp.activity.v1.ListMessageTabsResponse + 10, // 23: hyapp.activity.v1.MessageInboxService.ListInboxMessages:output_type -> hyapp.activity.v1.ListInboxMessagesResponse + 12, // 24: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:output_type -> hyapp.activity.v1.MarkInboxMessageReadResponse + 14, // 25: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:output_type -> hyapp.activity.v1.MarkInboxSectionReadResponse + 16, // 26: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:output_type -> hyapp.activity.v1.DeleteInboxMessageResponse + 18, // 27: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:output_type -> hyapp.activity.v1.CreateInboxMessageResponse + 20, // 28: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:output_type -> hyapp.activity.v1.CreateFanoutJobResponse + 20, // [20:29] is the sub-list for method output_type + 11, // [11:20] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_proto_activity_v1_activity_proto_init() } @@ -413,77 +1895,15 @@ func file_proto_activity_v1_activity_proto_init() { if File_proto_activity_v1_activity_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_proto_activity_v1_activity_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*RequestMeta); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_activity_v1_activity_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*PingActivityRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_activity_v1_activity_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*PingActivityResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_activity_v1_activity_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*GetActivityStatusRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_activity_v1_activity_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*GetActivityStatusResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_activity_v1_activity_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 21, NumExtensions: 0, - NumServices: 1, + NumServices: 2, }, 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 350d1edb..8b77b678 100644 --- a/api/proto/activity/v1/activity.proto +++ b/api/proto/activity/v1/activity.proto @@ -36,8 +36,159 @@ message GetActivityStatusResponse { string status = 2; } +// MessageTabSection 是 App 消息 tab 的一个分区摘要。 +message MessageTabSection { + string section = 1; + string title = 2; + int64 unread_count = 3; + string source = 4; +} + +// ListMessageTabsRequest 查询当前用户消息 tab 摘要。 +message ListMessageTabsRequest { + RequestMeta meta = 1; + int64 user_id = 2; +} + +// ListMessageTabsResponse 固定返回 user/system/activity 三个分区。 +message ListMessageTabsResponse { + repeated MessageTabSection sections = 1; +} + +// InboxMessage 是 system/activity 分区列表可展示的消息快照。 +message InboxMessage { + string message_id = 1; + string section = 2; + string title = 3; + string summary = 4; + string body = 5; + string icon_url = 6; + string image_url = 7; + string action_type = 8; + string action_param = 9; + bool read = 10; + int64 sent_at_ms = 11; +} + +// ListInboxMessagesRequest 按 section 和游标分页读取当前用户 inbox。 +message ListInboxMessagesRequest { + RequestMeta meta = 1; + int64 user_id = 2; + string section = 3; + int32 page_size = 4; + string page_token = 5; +} + +// ListInboxMessagesResponse 返回当前页列表和下一页不透明游标。 +message ListInboxMessagesResponse { + string section = 1; + repeated InboxMessage items = 2; + string next_page_token = 3; +} + +// MarkInboxMessageReadRequest 标记单条消息已读。 +message MarkInboxMessageReadRequest { + RequestMeta meta = 1; + int64 user_id = 2; + string message_id = 3; +} + +// MarkInboxMessageReadResponse 返回消息首次已读时间;重复请求不覆盖该时间。 +message MarkInboxMessageReadResponse { + string message_id = 1; + bool read = 2; + int64 read_at_ms = 3; +} + +// MarkInboxSectionReadRequest 标记一个 section 下当前可见未读消息全部已读。 +message MarkInboxSectionReadRequest { + RequestMeta meta = 1; + int64 user_id = 2; + string section = 3; +} + +// MarkInboxSectionReadResponse 返回本次实际变更的消息数量。 +message MarkInboxSectionReadResponse { + string section = 1; + int64 read_count = 2; +} + +// DeleteInboxMessageRequest 删除当前用户可见消息,删除是用户侧隐藏。 +message DeleteInboxMessageRequest { + RequestMeta meta = 1; + int64 user_id = 2; + string message_id = 3; +} + +// DeleteInboxMessageResponse 返回被隐藏的消息 ID。 +message DeleteInboxMessageResponse { + string message_id = 1; + bool deleted = 2; +} + +// CreateInboxMessageRequest 是生产者入箱命令;producer_event_id 是幂等键。 +message CreateInboxMessageRequest { + RequestMeta meta = 1; + int64 target_user_id = 2; + string producer = 3; + string producer_event_id = 4; + string producer_event_type = 5; + string message_type = 6; + string aggregate_type = 7; + string aggregate_id = 8; + string template_id = 9; + string template_version = 10; + string title = 11; + string summary = 12; + string body = 13; + string icon_url = 14; + string image_url = 15; + string action_type = 16; + string action_param = 17; + int32 priority = 18; + int64 sent_at_ms = 19; + int64 expire_at_ms = 20; + string metadata_json = 21; +} + +// CreateInboxMessageResponse 返回入箱结果;重复同一 producer_event_id 时 created=false。 +message CreateInboxMessageResponse { + string message_id = 1; + bool created = 2; +} + +// CreateFanoutJobRequest 创建后台 fanout 任务;command_id 是后台命令幂等键。 +message CreateFanoutJobRequest { + RequestMeta meta = 1; + string command_id = 2; + string message_type = 3; + string target_scope = 4; + string target_filter_json = 5; + string template_snapshot_json = 6; + int32 batch_size = 7; + string created_by = 8; +} + +// CreateFanoutJobResponse 返回 fanout job 幂等创建结果。 +message CreateFanoutJobResponse { + string job_id = 1; + string status = 2; + bool created = 3; +} + // ActivityService 只暴露同步查询,不把事件消费伪装成 RPC。 service ActivityService { rpc PingActivity(PingActivityRequest) returns (PingActivityResponse); rpc GetActivityStatus(GetActivityStatusRequest) returns (GetActivityStatusResponse); } + +// MessageInboxService 拥有 App system/activity 个人 inbox 事实。 +service MessageInboxService { + rpc ListMessageTabs(ListMessageTabsRequest) returns (ListMessageTabsResponse); + rpc ListInboxMessages(ListInboxMessagesRequest) returns (ListInboxMessagesResponse); + rpc MarkInboxMessageRead(MarkInboxMessageReadRequest) returns (MarkInboxMessageReadResponse); + rpc MarkInboxSectionRead(MarkInboxSectionReadRequest) returns (MarkInboxSectionReadResponse); + rpc DeleteInboxMessage(DeleteInboxMessageRequest) returns (DeleteInboxMessageResponse); + rpc CreateInboxMessage(CreateInboxMessageRequest) returns (CreateInboxMessageResponse); + rpc CreateFanoutJob(CreateFanoutJobRequest) returns (CreateFanoutJobResponse); +} diff --git a/api/proto/activity/v1/activity_grpc.pb.go b/api/proto/activity/v1/activity_grpc.pb.go index 0249d3eb..e4404141 100644 --- a/api/proto/activity/v1/activity_grpc.pb.go +++ b/api/proto/activity/v1/activity_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v5.29.2 +// - protoc v5.27.3 // source: proto/activity/v1/activity.proto package activityv1 @@ -161,3 +161,337 @@ var ActivityService_ServiceDesc = grpc.ServiceDesc{ Streams: []grpc.StreamDesc{}, Metadata: "proto/activity/v1/activity.proto", } + +const ( + MessageInboxService_ListMessageTabs_FullMethodName = "/hyapp.activity.v1.MessageInboxService/ListMessageTabs" + MessageInboxService_ListInboxMessages_FullMethodName = "/hyapp.activity.v1.MessageInboxService/ListInboxMessages" + MessageInboxService_MarkInboxMessageRead_FullMethodName = "/hyapp.activity.v1.MessageInboxService/MarkInboxMessageRead" + MessageInboxService_MarkInboxSectionRead_FullMethodName = "/hyapp.activity.v1.MessageInboxService/MarkInboxSectionRead" + MessageInboxService_DeleteInboxMessage_FullMethodName = "/hyapp.activity.v1.MessageInboxService/DeleteInboxMessage" + MessageInboxService_CreateInboxMessage_FullMethodName = "/hyapp.activity.v1.MessageInboxService/CreateInboxMessage" + MessageInboxService_CreateFanoutJob_FullMethodName = "/hyapp.activity.v1.MessageInboxService/CreateFanoutJob" +) + +// MessageInboxServiceClient is the client API for MessageInboxService 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. +// +// MessageInboxService 拥有 App system/activity 个人 inbox 事实。 +type MessageInboxServiceClient interface { + ListMessageTabs(ctx context.Context, in *ListMessageTabsRequest, opts ...grpc.CallOption) (*ListMessageTabsResponse, error) + ListInboxMessages(ctx context.Context, in *ListInboxMessagesRequest, opts ...grpc.CallOption) (*ListInboxMessagesResponse, error) + MarkInboxMessageRead(ctx context.Context, in *MarkInboxMessageReadRequest, opts ...grpc.CallOption) (*MarkInboxMessageReadResponse, error) + MarkInboxSectionRead(ctx context.Context, in *MarkInboxSectionReadRequest, opts ...grpc.CallOption) (*MarkInboxSectionReadResponse, error) + DeleteInboxMessage(ctx context.Context, in *DeleteInboxMessageRequest, opts ...grpc.CallOption) (*DeleteInboxMessageResponse, error) + CreateInboxMessage(ctx context.Context, in *CreateInboxMessageRequest, opts ...grpc.CallOption) (*CreateInboxMessageResponse, error) + CreateFanoutJob(ctx context.Context, in *CreateFanoutJobRequest, opts ...grpc.CallOption) (*CreateFanoutJobResponse, error) +} + +type messageInboxServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewMessageInboxServiceClient(cc grpc.ClientConnInterface) MessageInboxServiceClient { + return &messageInboxServiceClient{cc} +} + +func (c *messageInboxServiceClient) ListMessageTabs(ctx context.Context, in *ListMessageTabsRequest, opts ...grpc.CallOption) (*ListMessageTabsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListMessageTabsResponse) + err := c.cc.Invoke(ctx, MessageInboxService_ListMessageTabs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageInboxServiceClient) ListInboxMessages(ctx context.Context, in *ListInboxMessagesRequest, opts ...grpc.CallOption) (*ListInboxMessagesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListInboxMessagesResponse) + err := c.cc.Invoke(ctx, MessageInboxService_ListInboxMessages_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageInboxServiceClient) MarkInboxMessageRead(ctx context.Context, in *MarkInboxMessageReadRequest, opts ...grpc.CallOption) (*MarkInboxMessageReadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(MarkInboxMessageReadResponse) + err := c.cc.Invoke(ctx, MessageInboxService_MarkInboxMessageRead_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageInboxServiceClient) MarkInboxSectionRead(ctx context.Context, in *MarkInboxSectionReadRequest, opts ...grpc.CallOption) (*MarkInboxSectionReadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(MarkInboxSectionReadResponse) + err := c.cc.Invoke(ctx, MessageInboxService_MarkInboxSectionRead_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageInboxServiceClient) DeleteInboxMessage(ctx context.Context, in *DeleteInboxMessageRequest, opts ...grpc.CallOption) (*DeleteInboxMessageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteInboxMessageResponse) + err := c.cc.Invoke(ctx, MessageInboxService_DeleteInboxMessage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageInboxServiceClient) CreateInboxMessage(ctx context.Context, in *CreateInboxMessageRequest, opts ...grpc.CallOption) (*CreateInboxMessageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateInboxMessageResponse) + err := c.cc.Invoke(ctx, MessageInboxService_CreateInboxMessage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageInboxServiceClient) CreateFanoutJob(ctx context.Context, in *CreateFanoutJobRequest, opts ...grpc.CallOption) (*CreateFanoutJobResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateFanoutJobResponse) + err := c.cc.Invoke(ctx, MessageInboxService_CreateFanoutJob_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MessageInboxServiceServer is the server API for MessageInboxService service. +// All implementations must embed UnimplementedMessageInboxServiceServer +// for forward compatibility. +// +// MessageInboxService 拥有 App system/activity 个人 inbox 事实。 +type MessageInboxServiceServer interface { + ListMessageTabs(context.Context, *ListMessageTabsRequest) (*ListMessageTabsResponse, error) + ListInboxMessages(context.Context, *ListInboxMessagesRequest) (*ListInboxMessagesResponse, error) + MarkInboxMessageRead(context.Context, *MarkInboxMessageReadRequest) (*MarkInboxMessageReadResponse, error) + MarkInboxSectionRead(context.Context, *MarkInboxSectionReadRequest) (*MarkInboxSectionReadResponse, error) + DeleteInboxMessage(context.Context, *DeleteInboxMessageRequest) (*DeleteInboxMessageResponse, error) + CreateInboxMessage(context.Context, *CreateInboxMessageRequest) (*CreateInboxMessageResponse, error) + CreateFanoutJob(context.Context, *CreateFanoutJobRequest) (*CreateFanoutJobResponse, error) + mustEmbedUnimplementedMessageInboxServiceServer() +} + +// UnimplementedMessageInboxServiceServer 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 UnimplementedMessageInboxServiceServer struct{} + +func (UnimplementedMessageInboxServiceServer) ListMessageTabs(context.Context, *ListMessageTabsRequest) (*ListMessageTabsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListMessageTabs not implemented") +} +func (UnimplementedMessageInboxServiceServer) ListInboxMessages(context.Context, *ListInboxMessagesRequest) (*ListInboxMessagesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListInboxMessages not implemented") +} +func (UnimplementedMessageInboxServiceServer) MarkInboxMessageRead(context.Context, *MarkInboxMessageReadRequest) (*MarkInboxMessageReadResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MarkInboxMessageRead not implemented") +} +func (UnimplementedMessageInboxServiceServer) MarkInboxSectionRead(context.Context, *MarkInboxSectionReadRequest) (*MarkInboxSectionReadResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MarkInboxSectionRead not implemented") +} +func (UnimplementedMessageInboxServiceServer) DeleteInboxMessage(context.Context, *DeleteInboxMessageRequest) (*DeleteInboxMessageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteInboxMessage not implemented") +} +func (UnimplementedMessageInboxServiceServer) CreateInboxMessage(context.Context, *CreateInboxMessageRequest) (*CreateInboxMessageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateInboxMessage not implemented") +} +func (UnimplementedMessageInboxServiceServer) CreateFanoutJob(context.Context, *CreateFanoutJobRequest) (*CreateFanoutJobResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateFanoutJob not implemented") +} +func (UnimplementedMessageInboxServiceServer) mustEmbedUnimplementedMessageInboxServiceServer() {} +func (UnimplementedMessageInboxServiceServer) testEmbeddedByValue() {} + +// UnsafeMessageInboxServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MessageInboxServiceServer will +// result in compilation errors. +type UnsafeMessageInboxServiceServer interface { + mustEmbedUnimplementedMessageInboxServiceServer() +} + +func RegisterMessageInboxServiceServer(s grpc.ServiceRegistrar, srv MessageInboxServiceServer) { + // If the following call pancis, it indicates UnimplementedMessageInboxServiceServer 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(&MessageInboxService_ServiceDesc, srv) +} + +func _MessageInboxService_ListMessageTabs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListMessageTabsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageInboxServiceServer).ListMessageTabs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MessageInboxService_ListMessageTabs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageInboxServiceServer).ListMessageTabs(ctx, req.(*ListMessageTabsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageInboxService_ListInboxMessages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListInboxMessagesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageInboxServiceServer).ListInboxMessages(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MessageInboxService_ListInboxMessages_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageInboxServiceServer).ListInboxMessages(ctx, req.(*ListInboxMessagesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageInboxService_MarkInboxMessageRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MarkInboxMessageReadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageInboxServiceServer).MarkInboxMessageRead(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MessageInboxService_MarkInboxMessageRead_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageInboxServiceServer).MarkInboxMessageRead(ctx, req.(*MarkInboxMessageReadRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageInboxService_MarkInboxSectionRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MarkInboxSectionReadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageInboxServiceServer).MarkInboxSectionRead(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MessageInboxService_MarkInboxSectionRead_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageInboxServiceServer).MarkInboxSectionRead(ctx, req.(*MarkInboxSectionReadRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageInboxService_DeleteInboxMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteInboxMessageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageInboxServiceServer).DeleteInboxMessage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MessageInboxService_DeleteInboxMessage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageInboxServiceServer).DeleteInboxMessage(ctx, req.(*DeleteInboxMessageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageInboxService_CreateInboxMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateInboxMessageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageInboxServiceServer).CreateInboxMessage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MessageInboxService_CreateInboxMessage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageInboxServiceServer).CreateInboxMessage(ctx, req.(*CreateInboxMessageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageInboxService_CreateFanoutJob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateFanoutJobRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageInboxServiceServer).CreateFanoutJob(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MessageInboxService_CreateFanoutJob_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageInboxServiceServer).CreateFanoutJob(ctx, req.(*CreateFanoutJobRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// MessageInboxService_ServiceDesc is the grpc.ServiceDesc for MessageInboxService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var MessageInboxService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "hyapp.activity.v1.MessageInboxService", + HandlerType: (*MessageInboxServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListMessageTabs", + Handler: _MessageInboxService_ListMessageTabs_Handler, + }, + { + MethodName: "ListInboxMessages", + Handler: _MessageInboxService_ListInboxMessages_Handler, + }, + { + MethodName: "MarkInboxMessageRead", + Handler: _MessageInboxService_MarkInboxMessageRead_Handler, + }, + { + MethodName: "MarkInboxSectionRead", + Handler: _MessageInboxService_MarkInboxSectionRead_Handler, + }, + { + MethodName: "DeleteInboxMessage", + Handler: _MessageInboxService_DeleteInboxMessage_Handler, + }, + { + MethodName: "CreateInboxMessage", + Handler: _MessageInboxService_CreateInboxMessage_Handler, + }, + { + MethodName: "CreateFanoutJob", + Handler: _MessageInboxService_CreateFanoutJob_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 0ac4ffc4..86067e1c 100644 --- a/api/proto/events/room/v1/events.pb.go +++ b/api/proto/events/room/v1/events.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v7.34.1 +// protoc-gen-go v1.35.1 +// protoc v5.27.3 // source: proto/events/room/v1/events.proto package roomeventsv1 @@ -38,11 +38,9 @@ type EventEnvelope struct { func (x *EventEnvelope) Reset() { *x = EventEnvelope{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *EventEnvelope) String() string { @@ -53,7 +51,7 @@ func (*EventEnvelope) ProtoMessage() {} func (x *EventEnvelope) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -135,11 +133,9 @@ type RoomCreated struct { func (x *RoomCreated) Reset() { *x = RoomCreated{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomCreated) String() string { @@ -150,7 +146,7 @@ func (*RoomCreated) ProtoMessage() {} func (x *RoomCreated) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -226,11 +222,9 @@ type RoomUserJoined struct { func (x *RoomUserJoined) Reset() { *x = RoomUserJoined{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomUserJoined) String() string { @@ -241,7 +235,7 @@ func (*RoomUserJoined) ProtoMessage() {} func (x *RoomUserJoined) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -281,11 +275,9 @@ type RoomUserLeft struct { func (x *RoomUserLeft) Reset() { *x = RoomUserLeft{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomUserLeft) String() string { @@ -296,7 +288,7 @@ func (*RoomUserLeft) ProtoMessage() {} func (x *RoomUserLeft) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -330,11 +322,9 @@ type RoomClosed struct { func (x *RoomClosed) Reset() { *x = RoomClosed{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomClosed) String() string { @@ -345,7 +335,7 @@ func (*RoomClosed) ProtoMessage() {} func (x *RoomClosed) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -397,11 +387,9 @@ type RoomMicChanged struct { func (x *RoomMicChanged) Reset() { *x = RoomMicChanged{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomMicChanged) String() string { @@ -412,7 +400,7 @@ func (*RoomMicChanged) ProtoMessage() {} func (x *RoomMicChanged) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -510,11 +498,9 @@ type RoomMicSeatLocked struct { func (x *RoomMicSeatLocked) Reset() { *x = RoomMicSeatLocked{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomMicSeatLocked) String() string { @@ -525,7 +511,7 @@ func (*RoomMicSeatLocked) ProtoMessage() {} func (x *RoomMicSeatLocked) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -573,11 +559,9 @@ type RoomChatEnabledChanged struct { func (x *RoomChatEnabledChanged) Reset() { *x = RoomChatEnabledChanged{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomChatEnabledChanged) String() string { @@ -588,7 +572,7 @@ func (*RoomChatEnabledChanged) ProtoMessage() {} func (x *RoomChatEnabledChanged) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -630,11 +614,9 @@ type RoomAdminChanged struct { func (x *RoomAdminChanged) Reset() { *x = RoomAdminChanged{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomAdminChanged) String() string { @@ -645,7 +627,7 @@ func (*RoomAdminChanged) ProtoMessage() {} func (x *RoomAdminChanged) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -694,11 +676,9 @@ type RoomHostTransferred struct { func (x *RoomHostTransferred) Reset() { *x = RoomHostTransferred{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomHostTransferred) String() string { @@ -709,7 +689,7 @@ func (*RoomHostTransferred) ProtoMessage() {} func (x *RoomHostTransferred) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -758,11 +738,9 @@ type RoomUserMuted struct { func (x *RoomUserMuted) Reset() { *x = RoomUserMuted{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomUserMuted) String() string { @@ -773,7 +751,7 @@ func (*RoomUserMuted) ProtoMessage() {} func (x *RoomUserMuted) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -821,11 +799,9 @@ type RoomUserKicked struct { func (x *RoomUserKicked) Reset() { *x = RoomUserKicked{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomUserKicked) String() string { @@ -836,7 +812,7 @@ func (*RoomUserKicked) ProtoMessage() {} func (x *RoomUserKicked) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -877,11 +853,9 @@ type RoomUserUnbanned struct { func (x *RoomUserUnbanned) Reset() { *x = RoomUserUnbanned{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomUserUnbanned) String() string { @@ -892,7 +866,7 @@ func (*RoomUserUnbanned) ProtoMessage() {} func (x *RoomUserUnbanned) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -937,11 +911,9 @@ type RoomGiftSent struct { func (x *RoomGiftSent) Reset() { *x = RoomGiftSent{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomGiftSent) String() string { @@ -952,7 +924,7 @@ func (*RoomGiftSent) ProtoMessage() {} func (x *RoomGiftSent) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1021,11 +993,9 @@ type RoomHeatChanged struct { func (x *RoomHeatChanged) Reset() { *x = RoomHeatChanged{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomHeatChanged) String() string { @@ -1036,7 +1006,7 @@ func (*RoomHeatChanged) ProtoMessage() {} func (x *RoomHeatChanged) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1078,11 +1048,9 @@ type RoomRankChanged struct { func (x *RoomRankChanged) Reset() { *x = RoomRankChanged{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_events_room_v1_events_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomRankChanged) String() string { @@ -1093,7 +1061,7 @@ func (*RoomRankChanged) ProtoMessage() {} func (x *RoomRankChanged) ProtoReflect() protoreflect.Message { mi := &file_proto_events_room_v1_events_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1321,200 +1289,6 @@ func file_proto_events_room_v1_events_proto_init() { if File_proto_events_room_v1_events_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_proto_events_room_v1_events_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*EventEnvelope); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*RoomCreated); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*RoomUserJoined); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*RoomUserLeft); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*RoomClosed); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*RoomMicChanged); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*RoomMicSeatLocked); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*RoomChatEnabledChanged); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*RoomAdminChanged); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*RoomHostTransferred); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*RoomUserMuted); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*RoomUserKicked); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*RoomUserUnbanned); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*RoomGiftSent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*RoomHeatChanged); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_events_room_v1_events_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*RoomRankChanged); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/api/proto/room/v1/room.pb.go b/api/proto/room/v1/room.pb.go index 18a620c5..68279e73 100644 --- a/api/proto/room/v1/room.pb.go +++ b/api/proto/room/v1/room.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v7.34.1 +// protoc-gen-go v1.35.1 +// protoc v5.27.3 // source: proto/room/v1/room.proto package roomv1 @@ -41,11 +41,9 @@ type RequestMeta struct { func (x *RequestMeta) Reset() { *x = RequestMeta{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RequestMeta) String() string { @@ -56,7 +54,7 @@ func (*RequestMeta) ProtoMessage() {} func (x *RequestMeta) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -140,11 +138,9 @@ type CommandResult struct { func (x *CommandResult) Reset() { *x = CommandResult{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CommandResult) String() string { @@ -155,7 +151,7 @@ func (*CommandResult) ProtoMessage() {} func (x *CommandResult) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -205,11 +201,9 @@ type RoomUser struct { func (x *RoomUser) Reset() { *x = RoomUser{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomUser) String() string { @@ -220,7 +214,7 @@ func (*RoomUser) ProtoMessage() {} func (x *RoomUser) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -286,11 +280,9 @@ type SeatState struct { func (x *SeatState) Reset() { *x = SeatState{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SeatState) String() string { @@ -301,7 +293,7 @@ func (*SeatState) ProtoMessage() {} func (x *SeatState) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -386,11 +378,9 @@ type RankItem struct { func (x *RankItem) Reset() { *x = RankItem{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RankItem) String() string { @@ -401,7 +391,7 @@ func (*RankItem) ProtoMessage() {} func (x *RankItem) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -471,11 +461,9 @@ type RoomSnapshot struct { func (x *RoomSnapshot) Reset() { *x = RoomSnapshot{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomSnapshot) String() string { @@ -486,7 +474,7 @@ func (*RoomSnapshot) ProtoMessage() {} func (x *RoomSnapshot) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -647,11 +635,9 @@ type CreateRoomRequest struct { func (x *CreateRoomRequest) Reset() { *x = CreateRoomRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateRoomRequest) String() string { @@ -662,7 +648,7 @@ func (*CreateRoomRequest) ProtoMessage() {} func (x *CreateRoomRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -745,11 +731,9 @@ type CreateRoomResponse struct { func (x *CreateRoomResponse) Reset() { *x = CreateRoomResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateRoomResponse) String() string { @@ -760,7 +744,7 @@ func (*CreateRoomResponse) ProtoMessage() {} func (x *CreateRoomResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -801,11 +785,9 @@ type JoinRoomRequest struct { func (x *JoinRoomRequest) Reset() { *x = JoinRoomRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *JoinRoomRequest) String() string { @@ -816,7 +798,7 @@ func (*JoinRoomRequest) ProtoMessage() {} func (x *JoinRoomRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -858,11 +840,9 @@ type JoinRoomResponse struct { func (x *JoinRoomResponse) Reset() { *x = JoinRoomResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *JoinRoomResponse) String() string { @@ -873,7 +853,7 @@ func (*JoinRoomResponse) ProtoMessage() {} func (x *JoinRoomResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -921,11 +901,9 @@ type RoomHeartbeatRequest struct { func (x *RoomHeartbeatRequest) Reset() { *x = RoomHeartbeatRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomHeartbeatRequest) String() string { @@ -936,7 +914,7 @@ func (*RoomHeartbeatRequest) ProtoMessage() {} func (x *RoomHeartbeatRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -971,11 +949,9 @@ type RoomHeartbeatResponse struct { func (x *RoomHeartbeatResponse) Reset() { *x = RoomHeartbeatResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomHeartbeatResponse) String() string { @@ -986,7 +962,7 @@ func (*RoomHeartbeatResponse) ProtoMessage() {} func (x *RoomHeartbeatResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1033,11 +1009,9 @@ type LeaveRoomRequest struct { func (x *LeaveRoomRequest) Reset() { *x = LeaveRoomRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LeaveRoomRequest) String() string { @@ -1048,7 +1022,7 @@ func (*LeaveRoomRequest) ProtoMessage() {} func (x *LeaveRoomRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1082,11 +1056,9 @@ type LeaveRoomResponse struct { func (x *LeaveRoomResponse) Reset() { *x = LeaveRoomResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LeaveRoomResponse) String() string { @@ -1097,7 +1069,7 @@ func (*LeaveRoomResponse) ProtoMessage() {} func (x *LeaveRoomResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1138,11 +1110,9 @@ type CloseRoomRequest struct { func (x *CloseRoomRequest) Reset() { *x = CloseRoomRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CloseRoomRequest) String() string { @@ -1153,7 +1123,7 @@ func (*CloseRoomRequest) ProtoMessage() {} func (x *CloseRoomRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1194,11 +1164,9 @@ type CloseRoomResponse struct { func (x *CloseRoomResponse) Reset() { *x = CloseRoomResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CloseRoomResponse) String() string { @@ -1209,7 +1177,7 @@ func (*CloseRoomResponse) ProtoMessage() {} func (x *CloseRoomResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1250,11 +1218,9 @@ type MicUpRequest struct { func (x *MicUpRequest) Reset() { *x = MicUpRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MicUpRequest) String() string { @@ -1265,7 +1231,7 @@ func (*MicUpRequest) ProtoMessage() {} func (x *MicUpRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1309,11 +1275,9 @@ type MicUpResponse struct { func (x *MicUpResponse) Reset() { *x = MicUpResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MicUpResponse) String() string { @@ -1324,7 +1288,7 @@ func (*MicUpResponse) ProtoMessage() {} func (x *MicUpResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1388,11 +1352,9 @@ type MicDownRequest struct { func (x *MicDownRequest) Reset() { *x = MicDownRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MicDownRequest) String() string { @@ -1403,7 +1365,7 @@ func (*MicDownRequest) ProtoMessage() {} func (x *MicDownRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1452,11 +1414,9 @@ type MicDownResponse struct { func (x *MicDownResponse) Reset() { *x = MicDownResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MicDownResponse) String() string { @@ -1467,7 +1427,7 @@ func (*MicDownResponse) ProtoMessage() {} func (x *MicDownResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1516,11 +1476,9 @@ type ChangeMicSeatRequest struct { func (x *ChangeMicSeatRequest) Reset() { *x = ChangeMicSeatRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ChangeMicSeatRequest) String() string { @@ -1531,7 +1489,7 @@ func (*ChangeMicSeatRequest) ProtoMessage() {} func (x *ChangeMicSeatRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1579,11 +1537,9 @@ type ChangeMicSeatResponse struct { func (x *ChangeMicSeatResponse) Reset() { *x = ChangeMicSeatResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ChangeMicSeatResponse) String() string { @@ -1594,7 +1550,7 @@ func (*ChangeMicSeatResponse) ProtoMessage() {} func (x *ChangeMicSeatResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1641,11 +1597,9 @@ type ConfirmMicPublishingRequest struct { func (x *ConfirmMicPublishingRequest) Reset() { *x = ConfirmMicPublishingRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ConfirmMicPublishingRequest) String() string { @@ -1656,7 +1610,7 @@ func (*ConfirmMicPublishingRequest) ProtoMessage() {} func (x *ConfirmMicPublishingRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1726,11 +1680,9 @@ type ConfirmMicPublishingResponse struct { func (x *ConfirmMicPublishingResponse) Reset() { *x = ConfirmMicPublishingResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ConfirmMicPublishingResponse) String() string { @@ -1741,7 +1693,7 @@ func (*ConfirmMicPublishingResponse) ProtoMessage() {} func (x *ConfirmMicPublishingResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1795,11 +1747,9 @@ type ApplyRTCEventRequest struct { func (x *ApplyRTCEventRequest) Reset() { *x = ApplyRTCEventRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ApplyRTCEventRequest) String() string { @@ -1810,7 +1760,7 @@ func (*ApplyRTCEventRequest) ProtoMessage() {} func (x *ApplyRTCEventRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1887,11 +1837,9 @@ type ApplyRTCEventResponse struct { func (x *ApplyRTCEventResponse) Reset() { *x = ApplyRTCEventResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ApplyRTCEventResponse) String() string { @@ -1902,7 +1850,7 @@ func (*ApplyRTCEventResponse) ProtoMessage() {} func (x *ApplyRTCEventResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1951,11 +1899,9 @@ type SetMicSeatLockRequest struct { func (x *SetMicSeatLockRequest) Reset() { *x = SetMicSeatLockRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetMicSeatLockRequest) String() string { @@ -1966,7 +1912,7 @@ func (*SetMicSeatLockRequest) ProtoMessage() {} func (x *SetMicSeatLockRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2014,11 +1960,9 @@ type SetMicSeatLockResponse struct { func (x *SetMicSeatLockResponse) Reset() { *x = SetMicSeatLockResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetMicSeatLockResponse) String() string { @@ -2029,7 +1973,7 @@ func (*SetMicSeatLockResponse) ProtoMessage() {} func (x *SetMicSeatLockResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2070,11 +2014,9 @@ type SetChatEnabledRequest struct { func (x *SetChatEnabledRequest) Reset() { *x = SetChatEnabledRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetChatEnabledRequest) String() string { @@ -2085,7 +2027,7 @@ func (*SetChatEnabledRequest) ProtoMessage() {} func (x *SetChatEnabledRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2126,11 +2068,9 @@ type SetChatEnabledResponse struct { func (x *SetChatEnabledResponse) Reset() { *x = SetChatEnabledResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetChatEnabledResponse) String() string { @@ -2141,7 +2081,7 @@ func (*SetChatEnabledResponse) ProtoMessage() {} func (x *SetChatEnabledResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2183,11 +2123,9 @@ type SetRoomAdminRequest struct { func (x *SetRoomAdminRequest) Reset() { *x = SetRoomAdminRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetRoomAdminRequest) String() string { @@ -2198,7 +2136,7 @@ func (*SetRoomAdminRequest) ProtoMessage() {} func (x *SetRoomAdminRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2246,11 +2184,9 @@ type SetRoomAdminResponse struct { func (x *SetRoomAdminResponse) Reset() { *x = SetRoomAdminResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetRoomAdminResponse) String() string { @@ -2261,7 +2197,7 @@ func (*SetRoomAdminResponse) ProtoMessage() {} func (x *SetRoomAdminResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2302,11 +2238,9 @@ type TransferRoomHostRequest struct { func (x *TransferRoomHostRequest) Reset() { *x = TransferRoomHostRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[32] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TransferRoomHostRequest) String() string { @@ -2317,7 +2251,7 @@ func (*TransferRoomHostRequest) ProtoMessage() {} func (x *TransferRoomHostRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[32] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2358,11 +2292,9 @@ type TransferRoomHostResponse struct { func (x *TransferRoomHostResponse) Reset() { *x = TransferRoomHostResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TransferRoomHostResponse) String() string { @@ -2373,7 +2305,7 @@ func (*TransferRoomHostResponse) ProtoMessage() {} func (x *TransferRoomHostResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2415,11 +2347,9 @@ type MuteUserRequest struct { func (x *MuteUserRequest) Reset() { *x = MuteUserRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MuteUserRequest) String() string { @@ -2430,7 +2360,7 @@ func (*MuteUserRequest) ProtoMessage() {} func (x *MuteUserRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2478,11 +2408,9 @@ type MuteUserResponse struct { func (x *MuteUserResponse) Reset() { *x = MuteUserResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MuteUserResponse) String() string { @@ -2493,7 +2421,7 @@ func (*MuteUserResponse) ProtoMessage() {} func (x *MuteUserResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[35] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2534,11 +2462,9 @@ type KickUserRequest struct { func (x *KickUserRequest) Reset() { *x = KickUserRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *KickUserRequest) String() string { @@ -2549,7 +2475,7 @@ func (*KickUserRequest) ProtoMessage() {} func (x *KickUserRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[36] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2590,11 +2516,9 @@ type KickUserResponse struct { func (x *KickUserResponse) Reset() { *x = KickUserResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *KickUserResponse) String() string { @@ -2605,7 +2529,7 @@ func (*KickUserResponse) ProtoMessage() {} func (x *KickUserResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[37] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2646,11 +2570,9 @@ type UnbanUserRequest struct { func (x *UnbanUserRequest) Reset() { *x = UnbanUserRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[38] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UnbanUserRequest) String() string { @@ -2661,7 +2583,7 @@ func (*UnbanUserRequest) ProtoMessage() {} func (x *UnbanUserRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[38] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2702,11 +2624,9 @@ type UnbanUserResponse struct { func (x *UnbanUserResponse) Reset() { *x = UnbanUserResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UnbanUserResponse) String() string { @@ -2717,7 +2637,7 @@ func (*UnbanUserResponse) ProtoMessage() {} func (x *UnbanUserResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[39] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2760,11 +2680,9 @@ type SendGiftRequest struct { func (x *SendGiftRequest) Reset() { *x = SendGiftRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[40] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SendGiftRequest) String() string { @@ -2775,7 +2693,7 @@ func (*SendGiftRequest) ProtoMessage() {} func (x *SendGiftRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[40] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2833,11 +2751,9 @@ type SendGiftResponse struct { func (x *SendGiftResponse) Reset() { *x = SendGiftResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[41] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SendGiftResponse) String() string { @@ -2848,7 +2764,7 @@ func (*SendGiftResponse) ProtoMessage() {} func (x *SendGiftResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[41] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2911,11 +2827,9 @@ type CheckSpeakPermissionRequest struct { func (x *CheckSpeakPermissionRequest) Reset() { *x = CheckSpeakPermissionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[42] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CheckSpeakPermissionRequest) String() string { @@ -2926,7 +2840,7 @@ func (*CheckSpeakPermissionRequest) ProtoMessage() {} func (x *CheckSpeakPermissionRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[42] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2975,11 +2889,9 @@ type CheckSpeakPermissionResponse struct { func (x *CheckSpeakPermissionResponse) Reset() { *x = CheckSpeakPermissionResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CheckSpeakPermissionResponse) String() string { @@ -2990,7 +2902,7 @@ func (*CheckSpeakPermissionResponse) ProtoMessage() {} func (x *CheckSpeakPermissionResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[43] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3041,11 +2953,9 @@ type VerifyRoomPresenceRequest struct { func (x *VerifyRoomPresenceRequest) Reset() { *x = VerifyRoomPresenceRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[44] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *VerifyRoomPresenceRequest) String() string { @@ -3056,7 +2966,7 @@ func (*VerifyRoomPresenceRequest) ProtoMessage() {} func (x *VerifyRoomPresenceRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[44] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3119,11 +3029,9 @@ type VerifyRoomPresenceResponse struct { func (x *VerifyRoomPresenceResponse) Reset() { *x = VerifyRoomPresenceResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[45] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *VerifyRoomPresenceResponse) String() string { @@ -3134,7 +3042,7 @@ func (*VerifyRoomPresenceResponse) ProtoMessage() {} func (x *VerifyRoomPresenceResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[45] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3188,11 +3096,9 @@ type ListRoomsRequest struct { func (x *ListRoomsRequest) Reset() { *x = ListRoomsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[46] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListRoomsRequest) String() string { @@ -3203,7 +3109,7 @@ func (*ListRoomsRequest) ProtoMessage() {} func (x *ListRoomsRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[46] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3291,11 +3197,9 @@ type RoomListItem struct { func (x *RoomListItem) Reset() { *x = RoomListItem{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[47] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoomListItem) String() string { @@ -3306,7 +3210,7 @@ func (*RoomListItem) ProtoMessage() {} func (x *RoomListItem) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[47] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3431,11 +3335,9 @@ type ListRoomsResponse struct { func (x *ListRoomsResponse) Reset() { *x = ListRoomsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[48] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_room_v1_room_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListRoomsResponse) String() string { @@ -3446,7 +3348,7 @@ func (*ListRoomsResponse) ProtoMessage() {} func (x *ListRoomsResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_room_v1_room_proto_msgTypes[48] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3475,6 +3377,289 @@ func (x *ListRoomsResponse) GetNextCursor() string { return "" } +// GetCurrentRoomRequest 查询当前用户是否仍有可恢复的房间 presence。 +// 该查询必须由 gateway 写入鉴权后的 user_id,客户端不能提交 user_id。 +type GetCurrentRoomRequest 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 *GetCurrentRoomRequest) Reset() { + *x = GetCurrentRoomRequest{} + mi := &file_proto_room_v1_room_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCurrentRoomRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCurrentRoomRequest) ProtoMessage() {} + +func (x *GetCurrentRoomRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_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 GetCurrentRoomRequest.ProtoReflect.Descriptor instead. +func (*GetCurrentRoomRequest) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{49} +} + +func (x *GetCurrentRoomRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *GetCurrentRoomRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +// GetCurrentRoomResponse 是 App 启动、回前台和网络恢复时的房间恢复探测结果。 +// 它只表达是否需要恢复,不会隐式 JoinRoom 或刷新 presence。 +type GetCurrentRoomResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HasCurrentRoom bool `protobuf:"varint,1,opt,name=has_current_room,json=hasCurrentRoom,proto3" json:"has_current_room,omitempty"` + RoomId string `protobuf:"bytes,2,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + RoomVersion int64 `protobuf:"varint,3,opt,name=room_version,json=roomVersion,proto3" json:"room_version,omitempty"` + Role string `protobuf:"bytes,4,opt,name=role,proto3" json:"role,omitempty"` + MicSessionId string `protobuf:"bytes,5,opt,name=mic_session_id,json=micSessionId,proto3" json:"mic_session_id,omitempty"` + PublishState string `protobuf:"bytes,6,opt,name=publish_state,json=publishState,proto3" json:"publish_state,omitempty"` + NeedJoinImGroup bool `protobuf:"varint,7,opt,name=need_join_im_group,json=needJoinImGroup,proto3" json:"need_join_im_group,omitempty"` + NeedRtcToken bool `protobuf:"varint,8,opt,name=need_rtc_token,json=needRtcToken,proto3" json:"need_rtc_token,omitempty"` + ServerTimeMs int64 `protobuf:"varint,9,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"` +} + +func (x *GetCurrentRoomResponse) Reset() { + *x = GetCurrentRoomResponse{} + mi := &file_proto_room_v1_room_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCurrentRoomResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCurrentRoomResponse) ProtoMessage() {} + +func (x *GetCurrentRoomResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_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 GetCurrentRoomResponse.ProtoReflect.Descriptor instead. +func (*GetCurrentRoomResponse) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{50} +} + +func (x *GetCurrentRoomResponse) GetHasCurrentRoom() bool { + if x != nil { + return x.HasCurrentRoom + } + return false +} + +func (x *GetCurrentRoomResponse) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *GetCurrentRoomResponse) GetRoomVersion() int64 { + if x != nil { + return x.RoomVersion + } + return 0 +} + +func (x *GetCurrentRoomResponse) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +func (x *GetCurrentRoomResponse) GetMicSessionId() string { + if x != nil { + return x.MicSessionId + } + return "" +} + +func (x *GetCurrentRoomResponse) GetPublishState() string { + if x != nil { + return x.PublishState + } + return "" +} + +func (x *GetCurrentRoomResponse) GetNeedJoinImGroup() bool { + if x != nil { + return x.NeedJoinImGroup + } + return false +} + +func (x *GetCurrentRoomResponse) GetNeedRtcToken() bool { + if x != nil { + return x.NeedRtcToken + } + return false +} + +func (x *GetCurrentRoomResponse) GetServerTimeMs() int64 { + if x != nil { + return x.ServerTimeMs + } + return 0 +} + +// GetRoomSnapshotRequest 主动读取当前房间完整快照。 +// 该查询必须由 gateway 写入鉴权后的 viewer_user_id,客户端不能提交 viewer_user_id。 +type GetRoomSnapshotRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + RoomId string `protobuf:"bytes,2,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + ViewerUserId int64 `protobuf:"varint,3,opt,name=viewer_user_id,json=viewerUserId,proto3" json:"viewer_user_id,omitempty"` +} + +func (x *GetRoomSnapshotRequest) Reset() { + *x = GetRoomSnapshotRequest{} + mi := &file_proto_room_v1_room_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRoomSnapshotRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRoomSnapshotRequest) ProtoMessage() {} + +func (x *GetRoomSnapshotRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_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 GetRoomSnapshotRequest.ProtoReflect.Descriptor instead. +func (*GetRoomSnapshotRequest) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{51} +} + +func (x *GetRoomSnapshotRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *GetRoomSnapshotRequest) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *GetRoomSnapshotRequest) GetViewerUserId() int64 { + if x != nil { + return x.ViewerUserId + } + return 0 +} + +// GetRoomSnapshotResponse 返回 Room Cell 当前快照;只读,不刷新 presence。 +type GetRoomSnapshotResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Room *RoomSnapshot `protobuf:"bytes,1,opt,name=room,proto3" json:"room,omitempty"` + ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"` +} + +func (x *GetRoomSnapshotResponse) Reset() { + *x = GetRoomSnapshotResponse{} + mi := &file_proto_room_v1_room_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRoomSnapshotResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRoomSnapshotResponse) ProtoMessage() {} + +func (x *GetRoomSnapshotResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_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 GetRoomSnapshotResponse.ProtoReflect.Descriptor instead. +func (*GetRoomSnapshotResponse) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{52} +} + +func (x *GetRoomSnapshotResponse) GetRoom() *RoomSnapshot { + if x != nil { + return x.Room + } + return nil +} + +func (x *GetRoomSnapshotResponse) GetServerTimeMs() int64 { + if x != nil { + return x.ServerTimeMs + } + return 0 +} + var File_proto_room_v1_room_proto protoreflect.FileDescriptor var file_proto_room_v1_room_proto_rawDesc = []byte{ @@ -3988,129 +4173,184 @@ var file_proto_room_v1_room_proto_rawDesc = []byte{ 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, 0x32, 0x9a, 0x0c, 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, 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, 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, + 0x6f, 0x72, 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, 0x32, 0x9a, 0x0c, 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, 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, - 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, 0x62, 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, 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, + 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, 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, 0xa3, 0x02, 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, 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, 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 ( @@ -4125,7 +4365,7 @@ func file_proto_room_v1_room_proto_rawDescGZIP() []byte { return file_proto_room_v1_room_proto_rawDescData } -var file_proto_room_v1_room_proto_msgTypes = make([]protoimpl.MessageInfo, 50) +var file_proto_room_v1_room_proto_msgTypes = make([]protoimpl.MessageInfo, 54) var file_proto_room_v1_room_proto_goTypes = []any{ (*RequestMeta)(nil), // 0: hyapp.room.v1.RequestMeta (*CommandResult)(nil), // 1: hyapp.room.v1.CommandResult @@ -4176,13 +4416,17 @@ var file_proto_room_v1_room_proto_goTypes = []any{ (*ListRoomsRequest)(nil), // 46: hyapp.room.v1.ListRoomsRequest (*RoomListItem)(nil), // 47: hyapp.room.v1.RoomListItem (*ListRoomsResponse)(nil), // 48: hyapp.room.v1.ListRoomsResponse - nil, // 49: hyapp.room.v1.RoomSnapshot.RoomExtEntry + (*GetCurrentRoomRequest)(nil), // 49: hyapp.room.v1.GetCurrentRoomRequest + (*GetCurrentRoomResponse)(nil), // 50: hyapp.room.v1.GetCurrentRoomResponse + (*GetRoomSnapshotRequest)(nil), // 51: hyapp.room.v1.GetRoomSnapshotRequest + (*GetRoomSnapshotResponse)(nil), // 52: hyapp.room.v1.GetRoomSnapshotResponse + nil, // 53: hyapp.room.v1.RoomSnapshot.RoomExtEntry } var file_proto_room_v1_room_proto_depIdxs = []int32{ 3, // 0: hyapp.room.v1.RoomSnapshot.mic_seats:type_name -> hyapp.room.v1.SeatState 2, // 1: hyapp.room.v1.RoomSnapshot.online_users:type_name -> hyapp.room.v1.RoomUser 4, // 2: hyapp.room.v1.RoomSnapshot.gift_rank:type_name -> hyapp.room.v1.RankItem - 49, // 3: hyapp.room.v1.RoomSnapshot.room_ext:type_name -> hyapp.room.v1.RoomSnapshot.RoomExtEntry + 53, // 3: hyapp.room.v1.RoomSnapshot.room_ext:type_name -> hyapp.room.v1.RoomSnapshot.RoomExtEntry 0, // 4: hyapp.room.v1.CreateRoomRequest.meta:type_name -> hyapp.room.v1.RequestMeta 1, // 5: hyapp.room.v1.CreateRoomResponse.result:type_name -> hyapp.room.v1.CommandResult 5, // 6: hyapp.room.v1.CreateRoomResponse.room:type_name -> hyapp.room.v1.RoomSnapshot @@ -4242,53 +4486,60 @@ var file_proto_room_v1_room_proto_depIdxs = []int32{ 5, // 60: hyapp.room.v1.SendGiftResponse.room:type_name -> hyapp.room.v1.RoomSnapshot 0, // 61: hyapp.room.v1.ListRoomsRequest.meta:type_name -> hyapp.room.v1.RequestMeta 47, // 62: hyapp.room.v1.ListRoomsResponse.rooms:type_name -> hyapp.room.v1.RoomListItem - 6, // 63: hyapp.room.v1.RoomCommandService.CreateRoom:input_type -> hyapp.room.v1.CreateRoomRequest - 8, // 64: hyapp.room.v1.RoomCommandService.JoinRoom:input_type -> hyapp.room.v1.JoinRoomRequest - 10, // 65: hyapp.room.v1.RoomCommandService.RoomHeartbeat:input_type -> hyapp.room.v1.RoomHeartbeatRequest - 12, // 66: hyapp.room.v1.RoomCommandService.LeaveRoom:input_type -> hyapp.room.v1.LeaveRoomRequest - 14, // 67: hyapp.room.v1.RoomCommandService.CloseRoom:input_type -> hyapp.room.v1.CloseRoomRequest - 16, // 68: hyapp.room.v1.RoomCommandService.MicUp:input_type -> hyapp.room.v1.MicUpRequest - 18, // 69: hyapp.room.v1.RoomCommandService.MicDown:input_type -> hyapp.room.v1.MicDownRequest - 20, // 70: hyapp.room.v1.RoomCommandService.ChangeMicSeat:input_type -> hyapp.room.v1.ChangeMicSeatRequest - 22, // 71: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:input_type -> hyapp.room.v1.ConfirmMicPublishingRequest - 24, // 72: hyapp.room.v1.RoomCommandService.ApplyRTCEvent:input_type -> hyapp.room.v1.ApplyRTCEventRequest - 26, // 73: hyapp.room.v1.RoomCommandService.SetMicSeatLock:input_type -> hyapp.room.v1.SetMicSeatLockRequest - 28, // 74: hyapp.room.v1.RoomCommandService.SetChatEnabled:input_type -> hyapp.room.v1.SetChatEnabledRequest - 30, // 75: hyapp.room.v1.RoomCommandService.SetRoomAdmin:input_type -> hyapp.room.v1.SetRoomAdminRequest - 32, // 76: hyapp.room.v1.RoomCommandService.TransferRoomHost:input_type -> hyapp.room.v1.TransferRoomHostRequest - 34, // 77: hyapp.room.v1.RoomCommandService.MuteUser:input_type -> hyapp.room.v1.MuteUserRequest - 36, // 78: hyapp.room.v1.RoomCommandService.KickUser:input_type -> hyapp.room.v1.KickUserRequest - 38, // 79: hyapp.room.v1.RoomCommandService.UnbanUser:input_type -> hyapp.room.v1.UnbanUserRequest - 40, // 80: hyapp.room.v1.RoomCommandService.SendGift:input_type -> hyapp.room.v1.SendGiftRequest - 42, // 81: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:input_type -> hyapp.room.v1.CheckSpeakPermissionRequest - 44, // 82: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:input_type -> hyapp.room.v1.VerifyRoomPresenceRequest - 46, // 83: hyapp.room.v1.RoomQueryService.ListRooms:input_type -> hyapp.room.v1.ListRoomsRequest - 7, // 84: hyapp.room.v1.RoomCommandService.CreateRoom:output_type -> hyapp.room.v1.CreateRoomResponse - 9, // 85: hyapp.room.v1.RoomCommandService.JoinRoom:output_type -> hyapp.room.v1.JoinRoomResponse - 11, // 86: hyapp.room.v1.RoomCommandService.RoomHeartbeat:output_type -> hyapp.room.v1.RoomHeartbeatResponse - 13, // 87: hyapp.room.v1.RoomCommandService.LeaveRoom:output_type -> hyapp.room.v1.LeaveRoomResponse - 15, // 88: hyapp.room.v1.RoomCommandService.CloseRoom:output_type -> hyapp.room.v1.CloseRoomResponse - 17, // 89: hyapp.room.v1.RoomCommandService.MicUp:output_type -> hyapp.room.v1.MicUpResponse - 19, // 90: hyapp.room.v1.RoomCommandService.MicDown:output_type -> hyapp.room.v1.MicDownResponse - 21, // 91: hyapp.room.v1.RoomCommandService.ChangeMicSeat:output_type -> hyapp.room.v1.ChangeMicSeatResponse - 23, // 92: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:output_type -> hyapp.room.v1.ConfirmMicPublishingResponse - 25, // 93: hyapp.room.v1.RoomCommandService.ApplyRTCEvent:output_type -> hyapp.room.v1.ApplyRTCEventResponse - 27, // 94: hyapp.room.v1.RoomCommandService.SetMicSeatLock:output_type -> hyapp.room.v1.SetMicSeatLockResponse - 29, // 95: hyapp.room.v1.RoomCommandService.SetChatEnabled:output_type -> hyapp.room.v1.SetChatEnabledResponse - 31, // 96: hyapp.room.v1.RoomCommandService.SetRoomAdmin:output_type -> hyapp.room.v1.SetRoomAdminResponse - 33, // 97: hyapp.room.v1.RoomCommandService.TransferRoomHost:output_type -> hyapp.room.v1.TransferRoomHostResponse - 35, // 98: hyapp.room.v1.RoomCommandService.MuteUser:output_type -> hyapp.room.v1.MuteUserResponse - 37, // 99: hyapp.room.v1.RoomCommandService.KickUser:output_type -> hyapp.room.v1.KickUserResponse - 39, // 100: hyapp.room.v1.RoomCommandService.UnbanUser:output_type -> hyapp.room.v1.UnbanUserResponse - 41, // 101: hyapp.room.v1.RoomCommandService.SendGift:output_type -> hyapp.room.v1.SendGiftResponse - 43, // 102: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:output_type -> hyapp.room.v1.CheckSpeakPermissionResponse - 45, // 103: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:output_type -> hyapp.room.v1.VerifyRoomPresenceResponse - 48, // 104: hyapp.room.v1.RoomQueryService.ListRooms:output_type -> hyapp.room.v1.ListRoomsResponse - 84, // [84:105] is the sub-list for method output_type - 63, // [63:84] is the sub-list for method input_type - 63, // [63:63] is the sub-list for extension type_name - 63, // [63:63] is the sub-list for extension extendee - 0, // [0:63] is the sub-list for field type_name + 0, // 63: hyapp.room.v1.GetCurrentRoomRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 0, // 64: hyapp.room.v1.GetRoomSnapshotRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 5, // 65: hyapp.room.v1.GetRoomSnapshotResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 6, // 66: hyapp.room.v1.RoomCommandService.CreateRoom:input_type -> hyapp.room.v1.CreateRoomRequest + 8, // 67: hyapp.room.v1.RoomCommandService.JoinRoom:input_type -> hyapp.room.v1.JoinRoomRequest + 10, // 68: hyapp.room.v1.RoomCommandService.RoomHeartbeat:input_type -> hyapp.room.v1.RoomHeartbeatRequest + 12, // 69: hyapp.room.v1.RoomCommandService.LeaveRoom:input_type -> hyapp.room.v1.LeaveRoomRequest + 14, // 70: hyapp.room.v1.RoomCommandService.CloseRoom:input_type -> hyapp.room.v1.CloseRoomRequest + 16, // 71: hyapp.room.v1.RoomCommandService.MicUp:input_type -> hyapp.room.v1.MicUpRequest + 18, // 72: hyapp.room.v1.RoomCommandService.MicDown:input_type -> hyapp.room.v1.MicDownRequest + 20, // 73: hyapp.room.v1.RoomCommandService.ChangeMicSeat:input_type -> hyapp.room.v1.ChangeMicSeatRequest + 22, // 74: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:input_type -> hyapp.room.v1.ConfirmMicPublishingRequest + 24, // 75: hyapp.room.v1.RoomCommandService.ApplyRTCEvent:input_type -> hyapp.room.v1.ApplyRTCEventRequest + 26, // 76: hyapp.room.v1.RoomCommandService.SetMicSeatLock:input_type -> hyapp.room.v1.SetMicSeatLockRequest + 28, // 77: hyapp.room.v1.RoomCommandService.SetChatEnabled:input_type -> hyapp.room.v1.SetChatEnabledRequest + 30, // 78: hyapp.room.v1.RoomCommandService.SetRoomAdmin:input_type -> hyapp.room.v1.SetRoomAdminRequest + 32, // 79: hyapp.room.v1.RoomCommandService.TransferRoomHost:input_type -> hyapp.room.v1.TransferRoomHostRequest + 34, // 80: hyapp.room.v1.RoomCommandService.MuteUser:input_type -> hyapp.room.v1.MuteUserRequest + 36, // 81: hyapp.room.v1.RoomCommandService.KickUser:input_type -> hyapp.room.v1.KickUserRequest + 38, // 82: hyapp.room.v1.RoomCommandService.UnbanUser:input_type -> hyapp.room.v1.UnbanUserRequest + 40, // 83: hyapp.room.v1.RoomCommandService.SendGift:input_type -> hyapp.room.v1.SendGiftRequest + 42, // 84: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:input_type -> hyapp.room.v1.CheckSpeakPermissionRequest + 44, // 85: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:input_type -> hyapp.room.v1.VerifyRoomPresenceRequest + 46, // 86: hyapp.room.v1.RoomQueryService.ListRooms:input_type -> hyapp.room.v1.ListRoomsRequest + 49, // 87: hyapp.room.v1.RoomQueryService.GetCurrentRoom:input_type -> hyapp.room.v1.GetCurrentRoomRequest + 51, // 88: hyapp.room.v1.RoomQueryService.GetRoomSnapshot:input_type -> hyapp.room.v1.GetRoomSnapshotRequest + 7, // 89: hyapp.room.v1.RoomCommandService.CreateRoom:output_type -> hyapp.room.v1.CreateRoomResponse + 9, // 90: hyapp.room.v1.RoomCommandService.JoinRoom:output_type -> hyapp.room.v1.JoinRoomResponse + 11, // 91: hyapp.room.v1.RoomCommandService.RoomHeartbeat:output_type -> hyapp.room.v1.RoomHeartbeatResponse + 13, // 92: hyapp.room.v1.RoomCommandService.LeaveRoom:output_type -> hyapp.room.v1.LeaveRoomResponse + 15, // 93: hyapp.room.v1.RoomCommandService.CloseRoom:output_type -> hyapp.room.v1.CloseRoomResponse + 17, // 94: hyapp.room.v1.RoomCommandService.MicUp:output_type -> hyapp.room.v1.MicUpResponse + 19, // 95: hyapp.room.v1.RoomCommandService.MicDown:output_type -> hyapp.room.v1.MicDownResponse + 21, // 96: hyapp.room.v1.RoomCommandService.ChangeMicSeat:output_type -> hyapp.room.v1.ChangeMicSeatResponse + 23, // 97: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:output_type -> hyapp.room.v1.ConfirmMicPublishingResponse + 25, // 98: hyapp.room.v1.RoomCommandService.ApplyRTCEvent:output_type -> hyapp.room.v1.ApplyRTCEventResponse + 27, // 99: hyapp.room.v1.RoomCommandService.SetMicSeatLock:output_type -> hyapp.room.v1.SetMicSeatLockResponse + 29, // 100: hyapp.room.v1.RoomCommandService.SetChatEnabled:output_type -> hyapp.room.v1.SetChatEnabledResponse + 31, // 101: hyapp.room.v1.RoomCommandService.SetRoomAdmin:output_type -> hyapp.room.v1.SetRoomAdminResponse + 33, // 102: hyapp.room.v1.RoomCommandService.TransferRoomHost:output_type -> hyapp.room.v1.TransferRoomHostResponse + 35, // 103: hyapp.room.v1.RoomCommandService.MuteUser:output_type -> hyapp.room.v1.MuteUserResponse + 37, // 104: hyapp.room.v1.RoomCommandService.KickUser:output_type -> hyapp.room.v1.KickUserResponse + 39, // 105: hyapp.room.v1.RoomCommandService.UnbanUser:output_type -> hyapp.room.v1.UnbanUserResponse + 41, // 106: hyapp.room.v1.RoomCommandService.SendGift:output_type -> hyapp.room.v1.SendGiftResponse + 43, // 107: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:output_type -> hyapp.room.v1.CheckSpeakPermissionResponse + 45, // 108: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:output_type -> hyapp.room.v1.VerifyRoomPresenceResponse + 48, // 109: hyapp.room.v1.RoomQueryService.ListRooms:output_type -> hyapp.room.v1.ListRoomsResponse + 50, // 110: hyapp.room.v1.RoomQueryService.GetCurrentRoom:output_type -> hyapp.room.v1.GetCurrentRoomResponse + 52, // 111: hyapp.room.v1.RoomQueryService.GetRoomSnapshot:output_type -> hyapp.room.v1.GetRoomSnapshotResponse + 89, // [89:112] is the sub-list for method output_type + 66, // [66:89] is the sub-list for method input_type + 66, // [66:66] is the sub-list for extension type_name + 66, // [66:66] is the sub-list for extension extendee + 0, // [0:66] is the sub-list for field type_name } func init() { file_proto_room_v1_room_proto_init() } @@ -4296,603 +4547,13 @@ func file_proto_room_v1_room_proto_init() { if File_proto_room_v1_room_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_proto_room_v1_room_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*RequestMeta); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*CommandResult); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*RoomUser); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*SeatState); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*RankItem); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*RoomSnapshot); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*CreateRoomRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*CreateRoomResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*JoinRoomRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*JoinRoomResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*RoomHeartbeatRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*RoomHeartbeatResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*LeaveRoomRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*LeaveRoomResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*CloseRoomRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*CloseRoomResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*MicUpRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*MicUpResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*MicDownRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[19].Exporter = func(v any, i int) any { - switch v := v.(*MicDownResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[20].Exporter = func(v any, i int) any { - switch v := v.(*ChangeMicSeatRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[21].Exporter = func(v any, i int) any { - switch v := v.(*ChangeMicSeatResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[22].Exporter = func(v any, i int) any { - switch v := v.(*ConfirmMicPublishingRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[23].Exporter = func(v any, i int) any { - switch v := v.(*ConfirmMicPublishingResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[24].Exporter = func(v any, i int) any { - switch v := v.(*ApplyRTCEventRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[25].Exporter = func(v any, i int) any { - switch v := v.(*ApplyRTCEventResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[26].Exporter = func(v any, i int) any { - switch v := v.(*SetMicSeatLockRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[27].Exporter = func(v any, i int) any { - switch v := v.(*SetMicSeatLockResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[28].Exporter = func(v any, i int) any { - switch v := v.(*SetChatEnabledRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[29].Exporter = func(v any, i int) any { - switch v := v.(*SetChatEnabledResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[30].Exporter = func(v any, i int) any { - switch v := v.(*SetRoomAdminRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[31].Exporter = func(v any, i int) any { - switch v := v.(*SetRoomAdminResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[32].Exporter = func(v any, i int) any { - switch v := v.(*TransferRoomHostRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[33].Exporter = func(v any, i int) any { - switch v := v.(*TransferRoomHostResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[34].Exporter = func(v any, i int) any { - switch v := v.(*MuteUserRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[35].Exporter = func(v any, i int) any { - switch v := v.(*MuteUserResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[36].Exporter = func(v any, i int) any { - switch v := v.(*KickUserRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[37].Exporter = func(v any, i int) any { - switch v := v.(*KickUserResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[38].Exporter = func(v any, i int) any { - switch v := v.(*UnbanUserRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[39].Exporter = func(v any, i int) any { - switch v := v.(*UnbanUserResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[40].Exporter = func(v any, i int) any { - switch v := v.(*SendGiftRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[41].Exporter = func(v any, i int) any { - switch v := v.(*SendGiftResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[42].Exporter = func(v any, i int) any { - switch v := v.(*CheckSpeakPermissionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[43].Exporter = func(v any, i int) any { - switch v := v.(*CheckSpeakPermissionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[44].Exporter = func(v any, i int) any { - switch v := v.(*VerifyRoomPresenceRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[45].Exporter = func(v any, i int) any { - switch v := v.(*VerifyRoomPresenceResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[46].Exporter = func(v any, i int) any { - switch v := v.(*ListRoomsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[47].Exporter = func(v any, i int) any { - switch v := v.(*RoomListItem); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_room_v1_room_proto_msgTypes[48].Exporter = func(v any, i int) any { - switch v := v.(*ListRoomsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_room_v1_room_proto_rawDesc, NumEnums: 0, - NumMessages: 50, + NumMessages: 54, NumExtensions: 0, NumServices: 3, }, diff --git a/api/proto/room/v1/room.proto b/api/proto/room/v1/room.proto index 94231c8f..5951a5b3 100644 --- a/api/proto/room/v1/room.proto +++ b/api/proto/room/v1/room.proto @@ -407,6 +407,41 @@ message ListRoomsResponse { string next_cursor = 2; } +// GetCurrentRoomRequest 查询当前用户是否仍有可恢复的房间 presence。 +// 该查询必须由 gateway 写入鉴权后的 user_id,客户端不能提交 user_id。 +message GetCurrentRoomRequest { + RequestMeta meta = 1; + int64 user_id = 2; +} + +// GetCurrentRoomResponse 是 App 启动、回前台和网络恢复时的房间恢复探测结果。 +// 它只表达是否需要恢复,不会隐式 JoinRoom 或刷新 presence。 +message GetCurrentRoomResponse { + bool has_current_room = 1; + string room_id = 2; + int64 room_version = 3; + string role = 4; + string mic_session_id = 5; + string publish_state = 6; + bool need_join_im_group = 7; + bool need_rtc_token = 8; + int64 server_time_ms = 9; +} + +// GetRoomSnapshotRequest 主动读取当前房间完整快照。 +// 该查询必须由 gateway 写入鉴权后的 viewer_user_id,客户端不能提交 viewer_user_id。 +message GetRoomSnapshotRequest { + RequestMeta meta = 1; + string room_id = 2; + int64 viewer_user_id = 3; +} + +// GetRoomSnapshotResponse 返回 Room Cell 当前快照;只读,不刷新 presence。 +message GetRoomSnapshotResponse { + RoomSnapshot room = 1; + int64 server_time_ms = 2; +} + // RoomCommandService 承载所有会改变房间状态的命令。 service RoomCommandService { rpc CreateRoom(CreateRoomRequest) returns (CreateRoomResponse); @@ -438,4 +473,6 @@ service RoomGuardService { // RoomQueryService 承载不会改变 Room Cell 状态的读模型查询。 service RoomQueryService { rpc ListRooms(ListRoomsRequest) returns (ListRoomsResponse); + rpc GetCurrentRoom(GetCurrentRoomRequest) returns (GetCurrentRoomResponse); + rpc GetRoomSnapshot(GetRoomSnapshotRequest) returns (GetRoomSnapshotResponse); } diff --git a/api/proto/room/v1/room_grpc.pb.go b/api/proto/room/v1/room_grpc.pb.go index 0fddd3e2..97351c21 100644 --- a/api/proto/room/v1/room_grpc.pb.go +++ b/api/proto/room/v1/room_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v7.34.1 +// - protoc v5.27.3 // source: proto/room/v1/room.proto package roomv1 @@ -915,7 +915,9 @@ var RoomGuardService_ServiceDesc = grpc.ServiceDesc{ } const ( - RoomQueryService_ListRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRooms" + RoomQueryService_ListRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRooms" + RoomQueryService_GetCurrentRoom_FullMethodName = "/hyapp.room.v1.RoomQueryService/GetCurrentRoom" + RoomQueryService_GetRoomSnapshot_FullMethodName = "/hyapp.room.v1.RoomQueryService/GetRoomSnapshot" ) // RoomQueryServiceClient is the client API for RoomQueryService service. @@ -925,6 +927,8 @@ const ( // RoomQueryService 承载不会改变 Room Cell 状态的读模型查询。 type RoomQueryServiceClient interface { ListRooms(ctx context.Context, in *ListRoomsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error) + GetCurrentRoom(ctx context.Context, in *GetCurrentRoomRequest, opts ...grpc.CallOption) (*GetCurrentRoomResponse, error) + GetRoomSnapshot(ctx context.Context, in *GetRoomSnapshotRequest, opts ...grpc.CallOption) (*GetRoomSnapshotResponse, error) } type roomQueryServiceClient struct { @@ -945,6 +949,26 @@ func (c *roomQueryServiceClient) ListRooms(ctx context.Context, in *ListRoomsReq return out, nil } +func (c *roomQueryServiceClient) GetCurrentRoom(ctx context.Context, in *GetCurrentRoomRequest, opts ...grpc.CallOption) (*GetCurrentRoomResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetCurrentRoomResponse) + err := c.cc.Invoke(ctx, RoomQueryService_GetCurrentRoom_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *roomQueryServiceClient) GetRoomSnapshot(ctx context.Context, in *GetRoomSnapshotRequest, opts ...grpc.CallOption) (*GetRoomSnapshotResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetRoomSnapshotResponse) + err := c.cc.Invoke(ctx, RoomQueryService_GetRoomSnapshot_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // RoomQueryServiceServer is the server API for RoomQueryService service. // All implementations must embed UnimplementedRoomQueryServiceServer // for forward compatibility. @@ -952,6 +976,8 @@ func (c *roomQueryServiceClient) ListRooms(ctx context.Context, in *ListRoomsReq // RoomQueryService 承载不会改变 Room Cell 状态的读模型查询。 type RoomQueryServiceServer interface { ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) + GetCurrentRoom(context.Context, *GetCurrentRoomRequest) (*GetCurrentRoomResponse, error) + GetRoomSnapshot(context.Context, *GetRoomSnapshotRequest) (*GetRoomSnapshotResponse, error) mustEmbedUnimplementedRoomQueryServiceServer() } @@ -965,6 +991,12 @@ type UnimplementedRoomQueryServiceServer struct{} func (UnimplementedRoomQueryServiceServer) ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListRooms not implemented") } +func (UnimplementedRoomQueryServiceServer) GetCurrentRoom(context.Context, *GetCurrentRoomRequest) (*GetCurrentRoomResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCurrentRoom not implemented") +} +func (UnimplementedRoomQueryServiceServer) GetRoomSnapshot(context.Context, *GetRoomSnapshotRequest) (*GetRoomSnapshotResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRoomSnapshot not implemented") +} func (UnimplementedRoomQueryServiceServer) mustEmbedUnimplementedRoomQueryServiceServer() {} func (UnimplementedRoomQueryServiceServer) testEmbeddedByValue() {} @@ -1004,6 +1036,42 @@ func _RoomQueryService_ListRooms_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _RoomQueryService_GetCurrentRoom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetCurrentRoomRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoomQueryServiceServer).GetCurrentRoom(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RoomQueryService_GetCurrentRoom_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoomQueryServiceServer).GetCurrentRoom(ctx, req.(*GetCurrentRoomRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RoomQueryService_GetRoomSnapshot_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRoomSnapshotRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoomQueryServiceServer).GetRoomSnapshot(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RoomQueryService_GetRoomSnapshot_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoomQueryServiceServer).GetRoomSnapshot(ctx, req.(*GetRoomSnapshotRequest)) + } + return interceptor(ctx, in, info, handler) +} + // RoomQueryService_ServiceDesc is the grpc.ServiceDesc for RoomQueryService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -1015,6 +1083,14 @@ var RoomQueryService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListRooms", Handler: _RoomQueryService_ListRooms_Handler, }, + { + MethodName: "GetCurrentRoom", + Handler: _RoomQueryService_GetCurrentRoom_Handler, + }, + { + MethodName: "GetRoomSnapshot", + Handler: _RoomQueryService_GetRoomSnapshot_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "proto/room/v1/room.proto", diff --git a/api/proto/user/v1/auth.pb.go b/api/proto/user/v1/auth.pb.go index edb1cfe2..5ebee983 100644 --- a/api/proto/user/v1/auth.pb.go +++ b/api/proto/user/v1/auth.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v5.29.2 +// protoc-gen-go v1.35.1 +// protoc v5.27.3 // source: proto/user/v1/auth.proto package userv1 @@ -33,11 +33,9 @@ type LoginPasswordRequest struct { func (x *LoginPasswordRequest) Reset() { *x = LoginPasswordRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LoginPasswordRequest) String() string { @@ -48,7 +46,7 @@ func (*LoginPasswordRequest) ProtoMessage() {} func (x *LoginPasswordRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -114,11 +112,9 @@ type LoginThirdPartyRequest struct { func (x *LoginThirdPartyRequest) Reset() { *x = LoginThirdPartyRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LoginThirdPartyRequest) String() string { @@ -129,7 +125,7 @@ func (*LoginThirdPartyRequest) ProtoMessage() {} func (x *LoginThirdPartyRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -298,11 +294,9 @@ type AuthResponse struct { func (x *AuthResponse) Reset() { *x = AuthResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AuthResponse) String() string { @@ -313,7 +307,7 @@ func (*AuthResponse) ProtoMessage() {} func (x *AuthResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -369,11 +363,9 @@ type SetPasswordRequest struct { func (x *SetPasswordRequest) Reset() { *x = SetPasswordRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetPasswordRequest) String() string { @@ -384,7 +376,7 @@ func (*SetPasswordRequest) ProtoMessage() {} func (x *SetPasswordRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -431,11 +423,9 @@ type SetPasswordResponse struct { func (x *SetPasswordResponse) Reset() { *x = SetPasswordResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetPasswordResponse) String() string { @@ -446,7 +436,7 @@ func (*SetPasswordResponse) ProtoMessage() {} func (x *SetPasswordResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -480,11 +470,9 @@ type RefreshTokenRequest struct { func (x *RefreshTokenRequest) Reset() { *x = RefreshTokenRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RefreshTokenRequest) String() string { @@ -495,7 +483,7 @@ func (*RefreshTokenRequest) ProtoMessage() {} func (x *RefreshTokenRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -535,11 +523,9 @@ type RefreshTokenResponse struct { func (x *RefreshTokenResponse) Reset() { *x = RefreshTokenResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RefreshTokenResponse) String() string { @@ -550,7 +536,7 @@ func (*RefreshTokenResponse) ProtoMessage() {} func (x *RefreshTokenResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -585,11 +571,9 @@ type LogoutRequest struct { func (x *LogoutRequest) Reset() { *x = LogoutRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LogoutRequest) String() string { @@ -600,7 +584,7 @@ func (*LogoutRequest) ProtoMessage() {} func (x *LogoutRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -647,11 +631,9 @@ type LogoutResponse struct { func (x *LogoutResponse) Reset() { *x = LogoutResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_auth_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_auth_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LogoutResponse) String() string { @@ -662,7 +644,7 @@ func (*LogoutResponse) ProtoMessage() {} func (x *LogoutResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_auth_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -874,116 +856,6 @@ func file_proto_user_v1_auth_proto_init() { return } file_proto_user_v1_user_proto_init() - if !protoimpl.UnsafeEnabled { - file_proto_user_v1_auth_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*LoginPasswordRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_auth_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*LoginThirdPartyRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_auth_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*AuthResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_auth_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*SetPasswordRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_auth_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*SetPasswordResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_auth_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*RefreshTokenRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_auth_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*RefreshTokenResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_auth_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*LogoutRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_auth_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*LogoutResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/api/proto/user/v1/auth_grpc.pb.go b/api/proto/user/v1/auth_grpc.pb.go index f3e9c778..f1366f5e 100644 --- a/api/proto/user/v1/auth_grpc.pb.go +++ b/api/proto/user/v1/auth_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v5.29.2 +// - protoc v5.27.3 // source: proto/user/v1/auth.proto package userv1 diff --git a/api/proto/user/v1/host.pb.go b/api/proto/user/v1/host.pb.go index 0f7dca8c..c2445e4b 100644 --- a/api/proto/user/v1/host.pb.go +++ b/api/proto/user/v1/host.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v5.29.2 +// protoc-gen-go v1.35.1 +// protoc v5.27.3 // source: proto/user/v1/host.proto package userv1 @@ -39,11 +39,9 @@ type HostProfile struct { func (x *HostProfile) Reset() { *x = HostProfile{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *HostProfile) String() string { @@ -54,7 +52,7 @@ func (*HostProfile) ProtoMessage() {} func (x *HostProfile) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -153,11 +151,9 @@ type Agency struct { func (x *Agency) Reset() { *x = Agency{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Agency) String() string { @@ -168,7 +164,7 @@ func (*Agency) ProtoMessage() {} func (x *Agency) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -278,11 +274,9 @@ type BDProfile struct { func (x *BDProfile) Reset() { *x = BDProfile{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BDProfile) String() string { @@ -293,7 +287,7 @@ func (*BDProfile) ProtoMessage() {} func (x *BDProfile) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -380,11 +374,9 @@ type CoinSellerProfile struct { func (x *CoinSellerProfile) Reset() { *x = CoinSellerProfile{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CoinSellerProfile) String() string { @@ -395,7 +387,7 @@ func (*CoinSellerProfile) ProtoMessage() {} func (x *CoinSellerProfile) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -474,11 +466,9 @@ type AgencyMembership struct { func (x *AgencyMembership) Reset() { *x = AgencyMembership{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AgencyMembership) String() string { @@ -489,7 +479,7 @@ func (*AgencyMembership) ProtoMessage() {} func (x *AgencyMembership) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -609,11 +599,9 @@ type AgencyApplication struct { func (x *AgencyApplication) Reset() { *x = AgencyApplication{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AgencyApplication) String() string { @@ -624,7 +612,7 @@ func (*AgencyApplication) ProtoMessage() {} func (x *AgencyApplication) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -742,11 +730,9 @@ type RoleInvitation struct { func (x *RoleInvitation) Reset() { *x = RoleInvitation{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RoleInvitation) String() string { @@ -757,7 +743,7 @@ func (*RoleInvitation) ProtoMessage() {} func (x *RoleInvitation) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -897,11 +883,9 @@ type SearchAgenciesRequest struct { func (x *SearchAgenciesRequest) Reset() { *x = SearchAgenciesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SearchAgenciesRequest) String() string { @@ -912,7 +896,7 @@ func (*SearchAgenciesRequest) ProtoMessage() {} func (x *SearchAgenciesRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -965,11 +949,9 @@ type SearchAgenciesResponse struct { func (x *SearchAgenciesResponse) Reset() { *x = SearchAgenciesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SearchAgenciesResponse) String() string { @@ -980,7 +962,7 @@ func (*SearchAgenciesResponse) ProtoMessage() {} func (x *SearchAgenciesResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1015,11 +997,9 @@ type ApplyToAgencyRequest struct { func (x *ApplyToAgencyRequest) Reset() { *x = ApplyToAgencyRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ApplyToAgencyRequest) String() string { @@ -1030,7 +1010,7 @@ func (*ApplyToAgencyRequest) ProtoMessage() {} func (x *ApplyToAgencyRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1083,11 +1063,9 @@ type ApplyToAgencyResponse struct { func (x *ApplyToAgencyResponse) Reset() { *x = ApplyToAgencyResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ApplyToAgencyResponse) String() string { @@ -1098,7 +1076,7 @@ func (*ApplyToAgencyResponse) ProtoMessage() {} func (x *ApplyToAgencyResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1135,11 +1113,9 @@ type ReviewAgencyApplicationRequest struct { func (x *ReviewAgencyApplicationRequest) Reset() { *x = ReviewAgencyApplicationRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReviewAgencyApplicationRequest) String() string { @@ -1150,7 +1126,7 @@ func (*ReviewAgencyApplicationRequest) ProtoMessage() {} func (x *ReviewAgencyApplicationRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1219,11 +1195,9 @@ type ReviewAgencyApplicationResponse struct { func (x *ReviewAgencyApplicationResponse) Reset() { *x = ReviewAgencyApplicationResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReviewAgencyApplicationResponse) String() string { @@ -1234,7 +1208,7 @@ func (*ReviewAgencyApplicationResponse) ProtoMessage() {} func (x *ReviewAgencyApplicationResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1285,11 +1259,9 @@ type KickAgencyHostRequest struct { func (x *KickAgencyHostRequest) Reset() { *x = KickAgencyHostRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *KickAgencyHostRequest) String() string { @@ -1300,7 +1272,7 @@ func (*KickAgencyHostRequest) ProtoMessage() {} func (x *KickAgencyHostRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1368,11 +1340,9 @@ type KickAgencyHostResponse struct { func (x *KickAgencyHostResponse) Reset() { *x = KickAgencyHostResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *KickAgencyHostResponse) String() string { @@ -1383,7 +1353,7 @@ func (*KickAgencyHostResponse) ProtoMessage() {} func (x *KickAgencyHostResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1426,11 +1396,9 @@ type InviteAgencyRequest struct { func (x *InviteAgencyRequest) Reset() { *x = InviteAgencyRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *InviteAgencyRequest) String() string { @@ -1441,7 +1409,7 @@ func (*InviteAgencyRequest) ProtoMessage() {} func (x *InviteAgencyRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1501,11 +1469,9 @@ type InviteAgencyResponse struct { func (x *InviteAgencyResponse) Reset() { *x = InviteAgencyResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *InviteAgencyResponse) String() string { @@ -1516,7 +1482,7 @@ func (*InviteAgencyResponse) ProtoMessage() {} func (x *InviteAgencyResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1551,11 +1517,9 @@ type InviteBDRequest struct { func (x *InviteBDRequest) Reset() { *x = InviteBDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *InviteBDRequest) String() string { @@ -1566,7 +1530,7 @@ func (*InviteBDRequest) ProtoMessage() {} func (x *InviteBDRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1619,11 +1583,9 @@ type InviteBDResponse struct { func (x *InviteBDResponse) Reset() { *x = InviteBDResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *InviteBDResponse) String() string { @@ -1634,7 +1596,7 @@ func (*InviteBDResponse) ProtoMessage() {} func (x *InviteBDResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1671,11 +1633,9 @@ type ProcessRoleInvitationRequest struct { func (x *ProcessRoleInvitationRequest) Reset() { *x = ProcessRoleInvitationRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProcessRoleInvitationRequest) String() string { @@ -1686,7 +1646,7 @@ func (*ProcessRoleInvitationRequest) ProtoMessage() {} func (x *ProcessRoleInvitationRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1757,11 +1717,9 @@ type ProcessRoleInvitationResponse struct { func (x *ProcessRoleInvitationResponse) Reset() { *x = ProcessRoleInvitationResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProcessRoleInvitationResponse) String() string { @@ -1772,7 +1730,7 @@ func (*ProcessRoleInvitationResponse) ProtoMessage() {} func (x *ProcessRoleInvitationResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1833,11 +1791,9 @@ type GetHostProfileRequest struct { func (x *GetHostProfileRequest) Reset() { *x = GetHostProfileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetHostProfileRequest) String() string { @@ -1848,7 +1804,7 @@ func (*GetHostProfileRequest) ProtoMessage() {} func (x *GetHostProfileRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1887,11 +1843,9 @@ type GetHostProfileResponse struct { func (x *GetHostProfileResponse) Reset() { *x = GetHostProfileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetHostProfileResponse) String() string { @@ -1902,7 +1856,7 @@ func (*GetHostProfileResponse) ProtoMessage() {} func (x *GetHostProfileResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1935,11 +1889,9 @@ type GetBDProfileRequest struct { func (x *GetBDProfileRequest) Reset() { *x = GetBDProfileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetBDProfileRequest) String() string { @@ -1950,7 +1902,7 @@ func (*GetBDProfileRequest) ProtoMessage() {} func (x *GetBDProfileRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1989,11 +1941,9 @@ type GetBDProfileResponse struct { func (x *GetBDProfileResponse) Reset() { *x = GetBDProfileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetBDProfileResponse) String() string { @@ -2004,7 +1954,7 @@ func (*GetBDProfileResponse) ProtoMessage() {} func (x *GetBDProfileResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2037,11 +1987,9 @@ type GetCoinSellerProfileRequest struct { func (x *GetCoinSellerProfileRequest) Reset() { *x = GetCoinSellerProfileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetCoinSellerProfileRequest) String() string { @@ -2052,7 +2000,7 @@ func (*GetCoinSellerProfileRequest) ProtoMessage() {} func (x *GetCoinSellerProfileRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2091,11 +2039,9 @@ type GetCoinSellerProfileResponse struct { func (x *GetCoinSellerProfileResponse) Reset() { *x = GetCoinSellerProfileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetCoinSellerProfileResponse) String() string { @@ -2106,7 +2052,7 @@ func (*GetCoinSellerProfileResponse) ProtoMessage() {} func (x *GetCoinSellerProfileResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2140,11 +2086,9 @@ type GetAgencyMembersRequest struct { func (x *GetAgencyMembersRequest) Reset() { *x = GetAgencyMembersRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetAgencyMembersRequest) String() string { @@ -2155,7 +2099,7 @@ func (*GetAgencyMembersRequest) ProtoMessage() {} func (x *GetAgencyMembersRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2201,11 +2145,9 @@ type GetAgencyMembersResponse struct { func (x *GetAgencyMembersResponse) Reset() { *x = GetAgencyMembersResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetAgencyMembersResponse) String() string { @@ -2216,7 +2158,7 @@ func (*GetAgencyMembersResponse) ProtoMessage() {} func (x *GetAgencyMembersResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2250,11 +2192,9 @@ type GetAgencyApplicationsRequest struct { func (x *GetAgencyApplicationsRequest) Reset() { *x = GetAgencyApplicationsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetAgencyApplicationsRequest) String() string { @@ -2265,7 +2205,7 @@ func (*GetAgencyApplicationsRequest) ProtoMessage() {} func (x *GetAgencyApplicationsRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2311,11 +2251,9 @@ type GetAgencyApplicationsResponse struct { func (x *GetAgencyApplicationsResponse) Reset() { *x = GetAgencyApplicationsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetAgencyApplicationsResponse) String() string { @@ -2326,7 +2264,7 @@ func (*GetAgencyApplicationsResponse) ProtoMessage() {} func (x *GetAgencyApplicationsResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2363,11 +2301,9 @@ type CreateBDLeaderRequest struct { func (x *CreateBDLeaderRequest) Reset() { *x = CreateBDLeaderRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateBDLeaderRequest) String() string { @@ -2378,7 +2314,7 @@ func (*CreateBDLeaderRequest) ProtoMessage() {} func (x *CreateBDLeaderRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2445,11 +2381,9 @@ type CreateBDLeaderResponse struct { func (x *CreateBDLeaderResponse) Reset() { *x = CreateBDLeaderResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[32] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateBDLeaderResponse) String() string { @@ -2460,7 +2394,7 @@ func (*CreateBDLeaderResponse) ProtoMessage() {} func (x *CreateBDLeaderResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[32] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2497,11 +2431,9 @@ type CreateBDRequest struct { func (x *CreateBDRequest) Reset() { *x = CreateBDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateBDRequest) String() string { @@ -2512,7 +2444,7 @@ func (*CreateBDRequest) ProtoMessage() {} func (x *CreateBDRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2579,11 +2511,9 @@ type CreateBDResponse struct { func (x *CreateBDResponse) Reset() { *x = CreateBDResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateBDResponse) String() string { @@ -2594,7 +2524,7 @@ func (*CreateBDResponse) ProtoMessage() {} func (x *CreateBDResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2631,11 +2561,9 @@ type SetBDStatusRequest struct { func (x *SetBDStatusRequest) Reset() { *x = SetBDStatusRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetBDStatusRequest) String() string { @@ -2646,7 +2574,7 @@ func (*SetBDStatusRequest) ProtoMessage() {} func (x *SetBDStatusRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[35] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2713,11 +2641,9 @@ type SetBDStatusResponse struct { func (x *SetBDStatusResponse) Reset() { *x = SetBDStatusResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetBDStatusResponse) String() string { @@ -2728,7 +2654,7 @@ func (*SetBDStatusResponse) ProtoMessage() {} func (x *SetBDStatusResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[36] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2764,11 +2690,9 @@ type CreateCoinSellerRequest struct { func (x *CreateCoinSellerRequest) Reset() { *x = CreateCoinSellerRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateCoinSellerRequest) String() string { @@ -2779,7 +2703,7 @@ func (*CreateCoinSellerRequest) ProtoMessage() {} func (x *CreateCoinSellerRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[37] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2839,11 +2763,9 @@ type CreateCoinSellerResponse struct { func (x *CreateCoinSellerResponse) Reset() { *x = CreateCoinSellerResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[38] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateCoinSellerResponse) String() string { @@ -2854,7 +2776,7 @@ func (*CreateCoinSellerResponse) ProtoMessage() {} func (x *CreateCoinSellerResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[38] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2891,11 +2813,9 @@ type SetCoinSellerStatusRequest struct { func (x *SetCoinSellerStatusRequest) Reset() { *x = SetCoinSellerStatusRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetCoinSellerStatusRequest) String() string { @@ -2906,7 +2826,7 @@ func (*SetCoinSellerStatusRequest) ProtoMessage() {} func (x *SetCoinSellerStatusRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[39] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2973,11 +2893,9 @@ type SetCoinSellerStatusResponse struct { func (x *SetCoinSellerStatusResponse) Reset() { *x = SetCoinSellerStatusResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[40] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetCoinSellerStatusResponse) String() string { @@ -2988,7 +2906,7 @@ func (*SetCoinSellerStatusResponse) ProtoMessage() {} func (x *SetCoinSellerStatusResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[40] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3028,11 +2946,9 @@ type CreateAgencyRequest struct { func (x *CreateAgencyRequest) Reset() { *x = CreateAgencyRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[41] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateAgencyRequest) String() string { @@ -3043,7 +2959,7 @@ func (*CreateAgencyRequest) ProtoMessage() {} func (x *CreateAgencyRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[41] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3133,11 +3049,9 @@ type CreateAgencyResponse struct { func (x *CreateAgencyResponse) Reset() { *x = CreateAgencyResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[42] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateAgencyResponse) String() string { @@ -3148,7 +3062,7 @@ func (*CreateAgencyResponse) ProtoMessage() {} func (x *CreateAgencyResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[42] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3198,11 +3112,9 @@ type CloseAgencyRequest struct { func (x *CloseAgencyRequest) Reset() { *x = CloseAgencyRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CloseAgencyRequest) String() string { @@ -3213,7 +3125,7 @@ func (*CloseAgencyRequest) ProtoMessage() {} func (x *CloseAgencyRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[43] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3273,11 +3185,9 @@ type CloseAgencyResponse struct { func (x *CloseAgencyResponse) Reset() { *x = CloseAgencyResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[44] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CloseAgencyResponse) String() string { @@ -3288,7 +3198,7 @@ func (*CloseAgencyResponse) ProtoMessage() {} func (x *CloseAgencyResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[44] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3325,11 +3235,9 @@ type SetAgencyJoinEnabledRequest struct { func (x *SetAgencyJoinEnabledRequest) Reset() { *x = SetAgencyJoinEnabledRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[45] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetAgencyJoinEnabledRequest) String() string { @@ -3340,7 +3248,7 @@ func (*SetAgencyJoinEnabledRequest) ProtoMessage() {} func (x *SetAgencyJoinEnabledRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[45] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3407,11 +3315,9 @@ type SetAgencyJoinEnabledResponse struct { func (x *SetAgencyJoinEnabledResponse) Reset() { *x = SetAgencyJoinEnabledResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_host_proto_msgTypes[46] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_host_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetAgencyJoinEnabledResponse) String() string { @@ -3422,7 +3328,7 @@ func (*SetAgencyJoinEnabledResponse) ProtoMessage() {} func (x *SetAgencyJoinEnabledResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_host_proto_msgTypes[46] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4305,572 +4211,6 @@ func file_proto_user_v1_host_proto_init() { return } file_proto_user_v1_user_proto_init() - if !protoimpl.UnsafeEnabled { - file_proto_user_v1_host_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*HostProfile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*Agency); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*BDProfile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*CoinSellerProfile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*AgencyMembership); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*AgencyApplication); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*RoleInvitation); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*SearchAgenciesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*SearchAgenciesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*ApplyToAgencyRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*ApplyToAgencyResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*ReviewAgencyApplicationRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*ReviewAgencyApplicationResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*KickAgencyHostRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*KickAgencyHostResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*InviteAgencyRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*InviteAgencyResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*InviteBDRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*InviteBDResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[19].Exporter = func(v any, i int) any { - switch v := v.(*ProcessRoleInvitationRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[20].Exporter = func(v any, i int) any { - switch v := v.(*ProcessRoleInvitationResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[21].Exporter = func(v any, i int) any { - switch v := v.(*GetHostProfileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[22].Exporter = func(v any, i int) any { - switch v := v.(*GetHostProfileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[23].Exporter = func(v any, i int) any { - switch v := v.(*GetBDProfileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[24].Exporter = func(v any, i int) any { - switch v := v.(*GetBDProfileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[25].Exporter = func(v any, i int) any { - switch v := v.(*GetCoinSellerProfileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[26].Exporter = func(v any, i int) any { - switch v := v.(*GetCoinSellerProfileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[27].Exporter = func(v any, i int) any { - switch v := v.(*GetAgencyMembersRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[28].Exporter = func(v any, i int) any { - switch v := v.(*GetAgencyMembersResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[29].Exporter = func(v any, i int) any { - switch v := v.(*GetAgencyApplicationsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[30].Exporter = func(v any, i int) any { - switch v := v.(*GetAgencyApplicationsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[31].Exporter = func(v any, i int) any { - switch v := v.(*CreateBDLeaderRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[32].Exporter = func(v any, i int) any { - switch v := v.(*CreateBDLeaderResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[33].Exporter = func(v any, i int) any { - switch v := v.(*CreateBDRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[34].Exporter = func(v any, i int) any { - switch v := v.(*CreateBDResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[35].Exporter = func(v any, i int) any { - switch v := v.(*SetBDStatusRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[36].Exporter = func(v any, i int) any { - switch v := v.(*SetBDStatusResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[37].Exporter = func(v any, i int) any { - switch v := v.(*CreateCoinSellerRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[38].Exporter = func(v any, i int) any { - switch v := v.(*CreateCoinSellerResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[39].Exporter = func(v any, i int) any { - switch v := v.(*SetCoinSellerStatusRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[40].Exporter = func(v any, i int) any { - switch v := v.(*SetCoinSellerStatusResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[41].Exporter = func(v any, i int) any { - switch v := v.(*CreateAgencyRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[42].Exporter = func(v any, i int) any { - switch v := v.(*CreateAgencyResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[43].Exporter = func(v any, i int) any { - switch v := v.(*CloseAgencyRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[44].Exporter = func(v any, i int) any { - switch v := v.(*CloseAgencyResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[45].Exporter = func(v any, i int) any { - switch v := v.(*SetAgencyJoinEnabledRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_host_proto_msgTypes[46].Exporter = func(v any, i int) any { - switch v := v.(*SetAgencyJoinEnabledResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/api/proto/user/v1/host_grpc.pb.go b/api/proto/user/v1/host_grpc.pb.go index f101d280..3002e68e 100644 --- a/api/proto/user/v1/host_grpc.pb.go +++ b/api/proto/user/v1/host_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v5.29.2 +// - protoc v5.27.3 // source: proto/user/v1/host.proto package userv1 diff --git a/api/proto/user/v1/user.pb.go b/api/proto/user/v1/user.pb.go index e74138e3..143ebb04 100644 --- a/api/proto/user/v1/user.pb.go +++ b/api/proto/user/v1/user.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v5.29.2 +// protoc-gen-go v1.35.1 +// protoc v5.27.3 // source: proto/user/v1/user.proto package userv1 @@ -93,11 +93,9 @@ type RequestMeta struct { func (x *RequestMeta) Reset() { *x = RequestMeta{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RequestMeta) String() string { @@ -108,7 +106,7 @@ func (*RequestMeta) ProtoMessage() {} func (x *RequestMeta) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -211,11 +209,9 @@ type App struct { func (x *App) Reset() { *x = App{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *App) String() string { @@ -226,7 +222,7 @@ func (*App) ProtoMessage() {} func (x *App) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -311,11 +307,9 @@ type ResolveAppRequest struct { func (x *ResolveAppRequest) Reset() { *x = ResolveAppRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ResolveAppRequest) String() string { @@ -326,7 +320,7 @@ func (*ResolveAppRequest) ProtoMessage() {} func (x *ResolveAppRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -379,11 +373,9 @@ type ResolveAppResponse struct { func (x *ResolveAppResponse) Reset() { *x = ResolveAppResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ResolveAppResponse) String() string { @@ -394,7 +386,7 @@ func (*ResolveAppResponse) ProtoMessage() {} func (x *ResolveAppResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -453,11 +445,9 @@ type User struct { func (x *User) Reset() { *x = User{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *User) String() string { @@ -468,7 +458,7 @@ func (*User) ProtoMessage() {} func (x *User) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -695,11 +685,9 @@ type AuthToken struct { func (x *AuthToken) Reset() { *x = AuthToken{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AuthToken) String() string { @@ -710,7 +698,7 @@ func (*AuthToken) ProtoMessage() {} func (x *AuthToken) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -828,11 +816,9 @@ type GetUserRequest struct { func (x *GetUserRequest) Reset() { *x = GetUserRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetUserRequest) String() string { @@ -843,7 +829,7 @@ func (*GetUserRequest) ProtoMessage() {} func (x *GetUserRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -883,11 +869,9 @@ type GetUserResponse struct { func (x *GetUserResponse) Reset() { *x = GetUserResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetUserResponse) String() string { @@ -898,7 +882,7 @@ func (*GetUserResponse) ProtoMessage() {} func (x *GetUserResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -932,11 +916,9 @@ type BatchGetUsersRequest struct { func (x *BatchGetUsersRequest) Reset() { *x = BatchGetUsersRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BatchGetUsersRequest) String() string { @@ -947,7 +929,7 @@ func (*BatchGetUsersRequest) ProtoMessage() {} func (x *BatchGetUsersRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -987,11 +969,9 @@ type BatchGetUsersResponse struct { func (x *BatchGetUsersResponse) Reset() { *x = BatchGetUsersResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BatchGetUsersResponse) String() string { @@ -1002,7 +982,7 @@ func (*BatchGetUsersResponse) ProtoMessage() {} func (x *BatchGetUsersResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_user_v1_user_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1024,6 +1004,154 @@ func (x *BatchGetUsersResponse) GetUsers() map[int64]*User { return nil } +// ListUserIDsRequest 给低频后台 fanout/重算任务按 user_id 游标读取目标用户。 +type ListUserIDsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + TargetScope string `protobuf:"bytes,2,opt,name=target_scope,json=targetScope,proto3" json:"target_scope,omitempty"` + CursorUserId int64 `protobuf:"varint,3,opt,name=cursor_user_id,json=cursorUserId,proto3" json:"cursor_user_id,omitempty"` + PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + RegionId int64 `protobuf:"varint,5,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + Country string `protobuf:"bytes,6,opt,name=country,proto3" json:"country,omitempty"` +} + +func (x *ListUserIDsRequest) Reset() { + *x = ListUserIDsRequest{} + mi := &file_proto_user_v1_user_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListUserIDsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUserIDsRequest) ProtoMessage() {} + +func (x *ListUserIDsRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_v1_user_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 ListUserIDsRequest.ProtoReflect.Descriptor instead. +func (*ListUserIDsRequest) Descriptor() ([]byte, []int) { + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{10} +} + +func (x *ListUserIDsRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *ListUserIDsRequest) GetTargetScope() string { + if x != nil { + return x.TargetScope + } + return "" +} + +func (x *ListUserIDsRequest) GetCursorUserId() int64 { + if x != nil { + return x.CursorUserId + } + return 0 +} + +func (x *ListUserIDsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListUserIDsRequest) GetRegionId() int64 { + if x != nil { + return x.RegionId + } + return 0 +} + +func (x *ListUserIDsRequest) GetCountry() string { + if x != nil { + return x.Country + } + return "" +} + +// ListUserIDsResponse 返回一页递增 user_id,调用方必须用 next_cursor_user_id 继续。 +type ListUserIDsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIds []int64 `protobuf:"varint,1,rep,packed,name=user_ids,json=userIds,proto3" json:"user_ids,omitempty"` + NextCursorUserId int64 `protobuf:"varint,2,opt,name=next_cursor_user_id,json=nextCursorUserId,proto3" json:"next_cursor_user_id,omitempty"` + Done bool `protobuf:"varint,3,opt,name=done,proto3" json:"done,omitempty"` +} + +func (x *ListUserIDsResponse) Reset() { + *x = ListUserIDsResponse{} + mi := &file_proto_user_v1_user_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListUserIDsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUserIDsResponse) ProtoMessage() {} + +func (x *ListUserIDsResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_v1_user_proto_msgTypes[11] + 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 ListUserIDsResponse.ProtoReflect.Descriptor instead. +func (*ListUserIDsResponse) Descriptor() ([]byte, []int) { + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{11} +} + +func (x *ListUserIDsResponse) GetUserIds() []int64 { + if x != nil { + return x.UserIds + } + return nil +} + +func (x *ListUserIDsResponse) GetNextCursorUserId() int64 { + if x != nil { + return x.NextCursorUserId + } + return 0 +} + +func (x *ListUserIDsResponse) GetDone() bool { + if x != nil { + return x.Done + } + return false +} + // UpdateUserProfileRequest 修改用户可自助维护的基础资料。 type UpdateUserProfileRequest struct { state protoimpl.MessageState @@ -1040,11 +1168,9 @@ type UpdateUserProfileRequest struct { func (x *UpdateUserProfileRequest) Reset() { *x = UpdateUserProfileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UpdateUserProfileRequest) String() string { @@ -1054,8 +1180,8 @@ func (x *UpdateUserProfileRequest) String() string { func (*UpdateUserProfileRequest) ProtoMessage() {} func (x *UpdateUserProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[12] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1067,7 +1193,7 @@ func (x *UpdateUserProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateUserProfileRequest.ProtoReflect.Descriptor instead. func (*UpdateUserProfileRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{10} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{12} } func (x *UpdateUserProfileRequest) GetMeta() *RequestMeta { @@ -1123,11 +1249,9 @@ type UpdateUserProfileResponse struct { func (x *UpdateUserProfileResponse) Reset() { *x = UpdateUserProfileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UpdateUserProfileResponse) String() string { @@ -1137,8 +1261,8 @@ func (x *UpdateUserProfileResponse) String() string { func (*UpdateUserProfileResponse) ProtoMessage() {} func (x *UpdateUserProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[13] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1150,7 +1274,7 @@ func (x *UpdateUserProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateUserProfileResponse.ProtoReflect.Descriptor instead. func (*UpdateUserProfileResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{11} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{13} } func (x *UpdateUserProfileResponse) GetUser() *User { @@ -1173,11 +1297,9 @@ type ChangeUserCountryRequest struct { func (x *ChangeUserCountryRequest) Reset() { *x = ChangeUserCountryRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ChangeUserCountryRequest) String() string { @@ -1187,8 +1309,8 @@ func (x *ChangeUserCountryRequest) String() string { func (*ChangeUserCountryRequest) ProtoMessage() {} func (x *ChangeUserCountryRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[14] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1200,7 +1322,7 @@ func (x *ChangeUserCountryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeUserCountryRequest.ProtoReflect.Descriptor instead. func (*ChangeUserCountryRequest) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{12} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{14} } func (x *ChangeUserCountryRequest) GetMeta() *RequestMeta { @@ -1236,11 +1358,9 @@ type ChangeUserCountryResponse struct { func (x *ChangeUserCountryResponse) Reset() { *x = ChangeUserCountryResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ChangeUserCountryResponse) String() string { @@ -1250,8 +1370,8 @@ func (x *ChangeUserCountryResponse) String() string { func (*ChangeUserCountryResponse) ProtoMessage() {} func (x *ChangeUserCountryResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[15] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1263,7 +1383,7 @@ func (x *ChangeUserCountryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeUserCountryResponse.ProtoReflect.Descriptor instead. func (*ChangeUserCountryResponse) Descriptor() ([]byte, []int) { - return file_proto_user_v1_user_proto_rawDescGZIP(), []int{13} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{15} } func (x *ChangeUserCountryResponse) GetUser() *User { @@ -1296,11 +1416,9 @@ type CompleteOnboardingRequest struct { func (x *CompleteOnboardingRequest) Reset() { *x = CompleteOnboardingRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CompleteOnboardingRequest) String() string { @@ -1310,8 +1428,8 @@ func (x *CompleteOnboardingRequest) String() string { func (*CompleteOnboardingRequest) ProtoMessage() {} func (x *CompleteOnboardingRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[16] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1323,7 +1441,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{14} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{16} } func (x *CompleteOnboardingRequest) GetMeta() *RequestMeta { @@ -1383,11 +1501,9 @@ type CompleteOnboardingResponse struct { func (x *CompleteOnboardingResponse) Reset() { *x = CompleteOnboardingResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CompleteOnboardingResponse) String() string { @@ -1397,8 +1513,8 @@ func (x *CompleteOnboardingResponse) String() string { func (*CompleteOnboardingResponse) ProtoMessage() {} func (x *CompleteOnboardingResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[17] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1410,7 +1526,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{15} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{17} } func (x *CompleteOnboardingResponse) GetUser() *User { @@ -1448,6 +1564,294 @@ func (x *CompleteOnboardingResponse) GetToken() *AuthToken { return nil } +// BindPushTokenRequest 绑定当前登录用户的系统推送 token。 +// push token 只服务离线触达,不作为登录凭证或设备身份凭证。 +type BindPushTokenRequest 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"` + DeviceId string `protobuf:"bytes,3,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` + PushToken string `protobuf:"bytes,4,opt,name=push_token,json=pushToken,proto3" json:"push_token,omitempty"` + Provider string `protobuf:"bytes,5,opt,name=provider,proto3" json:"provider,omitempty"` + Platform string `protobuf:"bytes,6,opt,name=platform,proto3" json:"platform,omitempty"` + AppVersion string `protobuf:"bytes,7,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"` + Language string `protobuf:"bytes,8,opt,name=language,proto3" json:"language,omitempty"` + Timezone string `protobuf:"bytes,9,opt,name=timezone,proto3" json:"timezone,omitempty"` +} + +func (x *BindPushTokenRequest) Reset() { + *x = BindPushTokenRequest{} + mi := &file_proto_user_v1_user_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BindPushTokenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BindPushTokenRequest) ProtoMessage() {} + +func (x *BindPushTokenRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_v1_user_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BindPushTokenRequest.ProtoReflect.Descriptor instead. +func (*BindPushTokenRequest) Descriptor() ([]byte, []int) { + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{18} +} + +func (x *BindPushTokenRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *BindPushTokenRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *BindPushTokenRequest) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *BindPushTokenRequest) GetPushToken() string { + if x != nil { + return x.PushToken + } + return "" +} + +func (x *BindPushTokenRequest) GetProvider() string { + if x != nil { + return x.Provider + } + return "" +} + +func (x *BindPushTokenRequest) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *BindPushTokenRequest) GetAppVersion() string { + if x != nil { + return x.AppVersion + } + return "" +} + +func (x *BindPushTokenRequest) GetLanguage() string { + if x != nil { + return x.Language + } + return "" +} + +func (x *BindPushTokenRequest) GetTimezone() string { + if x != nil { + return x.Timezone + } + return "" +} + +type BindPushTokenResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Bound bool `protobuf:"varint,1,opt,name=bound,proto3" json:"bound,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,2,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` +} + +func (x *BindPushTokenResponse) Reset() { + *x = BindPushTokenResponse{} + mi := &file_proto_user_v1_user_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BindPushTokenResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BindPushTokenResponse) ProtoMessage() {} + +func (x *BindPushTokenResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_v1_user_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BindPushTokenResponse.ProtoReflect.Descriptor instead. +func (*BindPushTokenResponse) Descriptor() ([]byte, []int) { + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{19} +} + +func (x *BindPushTokenResponse) GetBound() bool { + if x != nil { + return x.Bound + } + return false +} + +func (x *BindPushTokenResponse) GetUpdatedAtMs() int64 { + if x != nil { + return x.UpdatedAtMs + } + return 0 +} + +// DeletePushTokenRequest 删除或失效当前登录用户的系统推送 token。 +// push_token 可为空;为空时按 user_id + device_id 失效该设备的 active token。 +type DeletePushTokenRequest 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"` + DeviceId string `protobuf:"bytes,3,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` + PushToken string `protobuf:"bytes,4,opt,name=push_token,json=pushToken,proto3" json:"push_token,omitempty"` +} + +func (x *DeletePushTokenRequest) Reset() { + *x = DeletePushTokenRequest{} + mi := &file_proto_user_v1_user_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeletePushTokenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePushTokenRequest) ProtoMessage() {} + +func (x *DeletePushTokenRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_v1_user_proto_msgTypes[20] + 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 DeletePushTokenRequest.ProtoReflect.Descriptor instead. +func (*DeletePushTokenRequest) Descriptor() ([]byte, []int) { + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{20} +} + +func (x *DeletePushTokenRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *DeletePushTokenRequest) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *DeletePushTokenRequest) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *DeletePushTokenRequest) GetPushToken() string { + if x != nil { + return x.PushToken + } + return "" +} + +type DeletePushTokenResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,2,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` +} + +func (x *DeletePushTokenResponse) Reset() { + *x = DeletePushTokenResponse{} + mi := &file_proto_user_v1_user_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeletePushTokenResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePushTokenResponse) ProtoMessage() {} + +func (x *DeletePushTokenResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_v1_user_proto_msgTypes[21] + 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 DeletePushTokenResponse.ProtoReflect.Descriptor instead. +func (*DeletePushTokenResponse) Descriptor() ([]byte, []int) { + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{21} +} + +func (x *DeletePushTokenResponse) GetDeleted() bool { + if x != nil { + return x.Deleted + } + return false +} + +func (x *DeletePushTokenResponse) GetUpdatedAtMs() int64 { + if x != nil { + return x.UpdatedAtMs + } + return 0 +} + // Country 是国家主数据投影,客户端和普通用户流程只提交 country_code。 type Country struct { state protoimpl.MessageState @@ -1471,11 +1875,9 @@ type Country struct { func (x *Country) Reset() { *x = Country{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Country) String() string { @@ -1485,8 +1887,8 @@ func (x *Country) String() string { func (*Country) ProtoMessage() {} func (x *Country) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[22] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1498,7 +1900,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{16} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{22} } func (x *Country) GetCountryId() int64 { @@ -1611,11 +2013,9 @@ type Region struct { func (x *Region) Reset() { *x = Region{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Region) String() string { @@ -1625,8 +2025,8 @@ func (x *Region) String() string { func (*Region) ProtoMessage() {} func (x *Region) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[23] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1638,7 +2038,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{17} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{23} } func (x *Region) GetRegionId() int64 { @@ -1715,11 +2115,9 @@ type ListCountriesRequest struct { func (x *ListCountriesRequest) Reset() { *x = ListCountriesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListCountriesRequest) String() string { @@ -1729,8 +2127,8 @@ func (x *ListCountriesRequest) String() string { func (*ListCountriesRequest) ProtoMessage() {} func (x *ListCountriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[24] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1742,7 +2140,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{18} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{24} } func (x *ListCountriesRequest) GetMeta() *RequestMeta { @@ -1769,11 +2167,9 @@ type ListCountriesResponse struct { func (x *ListCountriesResponse) Reset() { *x = ListCountriesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListCountriesResponse) String() string { @@ -1783,8 +2179,8 @@ func (x *ListCountriesResponse) String() string { func (*ListCountriesResponse) ProtoMessage() {} func (x *ListCountriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[25] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1796,7 +2192,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{19} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{25} } func (x *ListCountriesResponse) GetCountries() []*Country { @@ -1826,11 +2222,9 @@ type UpdateCountryRequest struct { func (x *UpdateCountryRequest) Reset() { *x = UpdateCountryRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UpdateCountryRequest) String() string { @@ -1840,8 +2234,8 @@ func (x *UpdateCountryRequest) String() string { func (*UpdateCountryRequest) ProtoMessage() {} func (x *UpdateCountryRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[26] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1853,7 +2247,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{20} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{26} } func (x *UpdateCountryRequest) GetMeta() *RequestMeta { @@ -1936,11 +2330,9 @@ type CountryResponse struct { func (x *CountryResponse) Reset() { *x = CountryResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CountryResponse) String() string { @@ -1950,8 +2342,8 @@ func (x *CountryResponse) String() string { func (*CountryResponse) ProtoMessage() {} func (x *CountryResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[27] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1963,7 +2355,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{21} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{27} } func (x *CountryResponse) GetCountry() *Country { @@ -1983,11 +2375,9 @@ type ListRegistrationCountriesRequest struct { func (x *ListRegistrationCountriesRequest) Reset() { *x = ListRegistrationCountriesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListRegistrationCountriesRequest) String() string { @@ -1997,8 +2387,8 @@ func (x *ListRegistrationCountriesRequest) String() string { func (*ListRegistrationCountriesRequest) ProtoMessage() {} func (x *ListRegistrationCountriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[28] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2010,7 +2400,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{22} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{28} } func (x *ListRegistrationCountriesRequest) GetMeta() *RequestMeta { @@ -2030,11 +2420,9 @@ type ListRegistrationCountriesResponse struct { func (x *ListRegistrationCountriesResponse) Reset() { *x = ListRegistrationCountriesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListRegistrationCountriesResponse) String() string { @@ -2044,8 +2432,8 @@ func (x *ListRegistrationCountriesResponse) String() string { func (*ListRegistrationCountriesResponse) ProtoMessage() {} func (x *ListRegistrationCountriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[29] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2057,7 +2445,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{23} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{29} } func (x *ListRegistrationCountriesResponse) GetCountries() []*Country { @@ -2078,11 +2466,9 @@ type ListRegionsRequest struct { func (x *ListRegionsRequest) Reset() { *x = ListRegionsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListRegionsRequest) String() string { @@ -2092,8 +2478,8 @@ func (x *ListRegionsRequest) String() string { func (*ListRegionsRequest) ProtoMessage() {} func (x *ListRegionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[30] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2105,7 +2491,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{24} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{30} } func (x *ListRegionsRequest) GetMeta() *RequestMeta { @@ -2132,11 +2518,9 @@ type ListRegionsResponse struct { func (x *ListRegionsResponse) Reset() { *x = ListRegionsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListRegionsResponse) String() string { @@ -2146,8 +2530,8 @@ func (x *ListRegionsResponse) String() string { func (*ListRegionsResponse) ProtoMessage() {} func (x *ListRegionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[31] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2159,7 +2543,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{25} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{31} } func (x *ListRegionsResponse) GetRegions() []*Region { @@ -2180,11 +2564,9 @@ type GetRegionRequest struct { func (x *GetRegionRequest) Reset() { *x = GetRegionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetRegionRequest) String() string { @@ -2194,8 +2576,8 @@ func (x *GetRegionRequest) String() string { func (*GetRegionRequest) ProtoMessage() {} func (x *GetRegionRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[32] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2207,7 +2589,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{26} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{32} } func (x *GetRegionRequest) GetMeta() *RequestMeta { @@ -2240,11 +2622,9 @@ type UpdateRegionRequest struct { func (x *UpdateRegionRequest) Reset() { *x = UpdateRegionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UpdateRegionRequest) String() string { @@ -2254,8 +2634,8 @@ func (x *UpdateRegionRequest) String() string { func (*UpdateRegionRequest) ProtoMessage() {} func (x *UpdateRegionRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[33] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2267,7 +2647,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{27} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{33} } func (x *UpdateRegionRequest) GetMeta() *RequestMeta { @@ -2325,11 +2705,9 @@ type ReplaceRegionCountriesRequest struct { func (x *ReplaceRegionCountriesRequest) Reset() { *x = ReplaceRegionCountriesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReplaceRegionCountriesRequest) String() string { @@ -2339,8 +2717,8 @@ func (x *ReplaceRegionCountriesRequest) String() string { func (*ReplaceRegionCountriesRequest) ProtoMessage() {} func (x *ReplaceRegionCountriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[34] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2352,7 +2730,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{28} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{34} } func (x *ReplaceRegionCountriesRequest) GetMeta() *RequestMeta { @@ -2393,11 +2771,9 @@ type RegionResponse struct { func (x *RegionResponse) Reset() { *x = RegionResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RegionResponse) String() string { @@ -2407,8 +2783,8 @@ func (x *RegionResponse) String() string { func (*RegionResponse) ProtoMessage() {} func (x *RegionResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[35] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2420,7 +2796,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{29} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{35} } func (x *RegionResponse) GetRegion() *Region { @@ -2447,11 +2823,9 @@ type UserIdentity struct { func (x *UserIdentity) Reset() { *x = UserIdentity{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UserIdentity) String() string { @@ -2461,8 +2835,8 @@ func (x *UserIdentity) String() string { func (*UserIdentity) ProtoMessage() {} func (x *UserIdentity) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[36] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2474,7 +2848,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{30} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{36} } func (x *UserIdentity) GetUserId() int64 { @@ -2538,11 +2912,9 @@ type GetUserIdentityRequest struct { func (x *GetUserIdentityRequest) Reset() { *x = GetUserIdentityRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetUserIdentityRequest) String() string { @@ -2552,8 +2924,8 @@ func (x *GetUserIdentityRequest) String() string { func (*GetUserIdentityRequest) ProtoMessage() {} func (x *GetUserIdentityRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[37] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2565,7 +2937,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{31} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{37} } func (x *GetUserIdentityRequest) GetMeta() *RequestMeta { @@ -2593,11 +2965,9 @@ type GetUserIdentityResponse struct { func (x *GetUserIdentityResponse) Reset() { *x = GetUserIdentityResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[32] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetUserIdentityResponse) String() string { @@ -2607,8 +2977,8 @@ func (x *GetUserIdentityResponse) String() string { func (*GetUserIdentityResponse) ProtoMessage() {} func (x *GetUserIdentityResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[32] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[38] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2620,7 +2990,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{32} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{38} } func (x *GetUserIdentityResponse) GetIdentity() *UserIdentity { @@ -2642,11 +3012,9 @@ type ResolveDisplayUserIDRequest struct { func (x *ResolveDisplayUserIDRequest) Reset() { *x = ResolveDisplayUserIDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ResolveDisplayUserIDRequest) String() string { @@ -2656,8 +3024,8 @@ func (x *ResolveDisplayUserIDRequest) String() string { func (*ResolveDisplayUserIDRequest) ProtoMessage() {} func (x *ResolveDisplayUserIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[39] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2669,7 +3037,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{33} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{39} } func (x *ResolveDisplayUserIDRequest) GetMeta() *RequestMeta { @@ -2697,11 +3065,9 @@ type ResolveDisplayUserIDResponse struct { func (x *ResolveDisplayUserIDResponse) Reset() { *x = ResolveDisplayUserIDResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ResolveDisplayUserIDResponse) String() string { @@ -2711,8 +3077,8 @@ func (x *ResolveDisplayUserIDResponse) String() string { func (*ResolveDisplayUserIDResponse) ProtoMessage() {} func (x *ResolveDisplayUserIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[40] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2724,7 +3090,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{34} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{40} } func (x *ResolveDisplayUserIDResponse) GetIdentity() *UserIdentity { @@ -2749,11 +3115,9 @@ type ChangeDisplayUserIDRequest struct { func (x *ChangeDisplayUserIDRequest) Reset() { *x = ChangeDisplayUserIDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ChangeDisplayUserIDRequest) String() string { @@ -2763,8 +3127,8 @@ func (x *ChangeDisplayUserIDRequest) String() string { func (*ChangeDisplayUserIDRequest) ProtoMessage() {} func (x *ChangeDisplayUserIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[35] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[41] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2776,7 +3140,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{35} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{41} } func (x *ChangeDisplayUserIDRequest) GetMeta() *RequestMeta { @@ -2825,11 +3189,9 @@ type ChangeDisplayUserIDResponse struct { func (x *ChangeDisplayUserIDResponse) Reset() { *x = ChangeDisplayUserIDResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ChangeDisplayUserIDResponse) String() string { @@ -2839,8 +3201,8 @@ func (x *ChangeDisplayUserIDResponse) String() string { func (*ChangeDisplayUserIDResponse) ProtoMessage() {} func (x *ChangeDisplayUserIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[36] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[42] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2852,7 +3214,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{36} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{42} } func (x *ChangeDisplayUserIDResponse) GetIdentity() *UserIdentity { @@ -2877,11 +3239,9 @@ type ApplyPrettyDisplayUserIDRequest struct { func (x *ApplyPrettyDisplayUserIDRequest) Reset() { *x = ApplyPrettyDisplayUserIDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ApplyPrettyDisplayUserIDRequest) String() string { @@ -2891,8 +3251,8 @@ func (x *ApplyPrettyDisplayUserIDRequest) String() string { func (*ApplyPrettyDisplayUserIDRequest) ProtoMessage() {} func (x *ApplyPrettyDisplayUserIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[37] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[43] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2904,7 +3264,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{37} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{43} } func (x *ApplyPrettyDisplayUserIDRequest) GetMeta() *RequestMeta { @@ -2954,11 +3314,9 @@ type ApplyPrettyDisplayUserIDResponse struct { func (x *ApplyPrettyDisplayUserIDResponse) Reset() { *x = ApplyPrettyDisplayUserIDResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[38] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ApplyPrettyDisplayUserIDResponse) String() string { @@ -2968,8 +3326,8 @@ func (x *ApplyPrettyDisplayUserIDResponse) String() string { func (*ApplyPrettyDisplayUserIDResponse) ProtoMessage() {} func (x *ApplyPrettyDisplayUserIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[38] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[44] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2981,7 +3339,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{38} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{44} } func (x *ApplyPrettyDisplayUserIDResponse) GetIdentity() *UserIdentity { @@ -3011,11 +3369,9 @@ type ExpirePrettyDisplayUserIDRequest struct { func (x *ExpirePrettyDisplayUserIDRequest) Reset() { *x = ExpirePrettyDisplayUserIDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExpirePrettyDisplayUserIDRequest) String() string { @@ -3025,8 +3381,8 @@ func (x *ExpirePrettyDisplayUserIDRequest) String() string { func (*ExpirePrettyDisplayUserIDRequest) ProtoMessage() {} func (x *ExpirePrettyDisplayUserIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[39] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[45] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3038,7 +3394,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{39} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{45} } func (x *ExpirePrettyDisplayUserIDRequest) GetMeta() *RequestMeta { @@ -3073,11 +3429,9 @@ type ExpirePrettyDisplayUserIDResponse struct { func (x *ExpirePrettyDisplayUserIDResponse) Reset() { *x = ExpirePrettyDisplayUserIDResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_user_v1_user_proto_msgTypes[40] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proto_user_v1_user_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExpirePrettyDisplayUserIDResponse) String() string { @@ -3087,8 +3441,8 @@ func (x *ExpirePrettyDisplayUserIDResponse) String() string { func (*ExpirePrettyDisplayUserIDResponse) ProtoMessage() {} func (x *ExpirePrettyDisplayUserIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_user_v1_user_proto_msgTypes[40] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_proto_user_v1_user_proto_msgTypes[46] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3100,7 +3454,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{40} + return file_proto_user_v1_user_proto_rawDescGZIP(), []int{46} } func (x *ExpirePrettyDisplayUserIDResponse) GetIdentity() *UserIdentity { @@ -3288,448 +3642,528 @@ var file_proto_user_v1_user_proto_rawDesc = []byte{ 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 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, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x86, 0x02, - 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 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, 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, 0x1f, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x88, 0x01, - 0x01, 0x12, 0x19, 0x0a, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x02, 0x52, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, - 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x06, - 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x75, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x62, 0x69, 0x72, 0x74, 0x68, 0x42, 0x09, 0x0a, 0x07, 0x5f, - 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x22, 0x44, 0x0a, 0x19, 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, 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, 0x22, 0x7d, 0x0a, 0x18, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 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, 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, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x7e, 0x0a, 0x19, 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, 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, 0x38, 0x0a, 0x19, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x6e, 0x65, 0x78, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xca, 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, 0x22, 0x86, 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, 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, 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, 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, + 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe1, 0x01, + 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 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, 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, + 0x6d, 0x65, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, + 0x63, 0x6f, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x73, 0x6f, + 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0c, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 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, 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, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, + 0x79, 0x22, 0x73, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x73, 0x12, 0x2d, 0x0a, 0x13, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x63, 0x75, 0x72, 0x73, + 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x10, 0x6e, 0x65, 0x78, 0x74, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x22, 0x86, 0x02, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 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, 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, 0x1f, 0x0a, 0x08, + 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, + 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, + 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x62, 0x69, + 0x72, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x05, 0x62, 0x69, 0x72, + 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x88, + 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x42, + 0x09, 0x0a, 0x07, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x62, + 0x69, 0x72, 0x74, 0x68, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x22, + 0x44, 0x0a, 0x19, 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, 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, 0x22, 0x7d, 0x0a, 0x18, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, + 0x73, 0x65, 0x72, 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, 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, + 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x79, 0x22, 0x7e, 0x0a, 0x19, 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, 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, 0x38, 0x0a, 0x19, 0x6e, 0x65, + 0x78, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x6e, + 0x65, 0x78, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, + 0x41, 0x74, 0x4d, 0x73, 0x22, 0xca, 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, 0x22, 0x86, 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, 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, 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, 0xee, 0x03, - 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, 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, 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, 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, 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, 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, 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, + 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, + 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, 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, 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, + 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, 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, 0xc4, 0x04, 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, 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, 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, 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, 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, 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, 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, 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, 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, + 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, 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, 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, + 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, 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 ( @@ -3745,7 +4179,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, 42) +var file_proto_user_v1_user_proto_msgTypes = make([]protoimpl.MessageInfo, 48) var file_proto_user_v1_user_proto_goTypes = []any{ (UserStatus)(0), // 0: hyapp.user.v1.UserStatus (*RequestMeta)(nil), // 1: hyapp.user.v1.RequestMeta @@ -3758,38 +4192,44 @@ var file_proto_user_v1_user_proto_goTypes = []any{ (*GetUserResponse)(nil), // 8: hyapp.user.v1.GetUserResponse (*BatchGetUsersRequest)(nil), // 9: hyapp.user.v1.BatchGetUsersRequest (*BatchGetUsersResponse)(nil), // 10: hyapp.user.v1.BatchGetUsersResponse - (*UpdateUserProfileRequest)(nil), // 11: hyapp.user.v1.UpdateUserProfileRequest - (*UpdateUserProfileResponse)(nil), // 12: hyapp.user.v1.UpdateUserProfileResponse - (*ChangeUserCountryRequest)(nil), // 13: hyapp.user.v1.ChangeUserCountryRequest - (*ChangeUserCountryResponse)(nil), // 14: hyapp.user.v1.ChangeUserCountryResponse - (*CompleteOnboardingRequest)(nil), // 15: hyapp.user.v1.CompleteOnboardingRequest - (*CompleteOnboardingResponse)(nil), // 16: hyapp.user.v1.CompleteOnboardingResponse - (*Country)(nil), // 17: hyapp.user.v1.Country - (*Region)(nil), // 18: hyapp.user.v1.Region - (*ListCountriesRequest)(nil), // 19: hyapp.user.v1.ListCountriesRequest - (*ListCountriesResponse)(nil), // 20: hyapp.user.v1.ListCountriesResponse - (*UpdateCountryRequest)(nil), // 21: hyapp.user.v1.UpdateCountryRequest - (*CountryResponse)(nil), // 22: hyapp.user.v1.CountryResponse - (*ListRegistrationCountriesRequest)(nil), // 23: hyapp.user.v1.ListRegistrationCountriesRequest - (*ListRegistrationCountriesResponse)(nil), // 24: hyapp.user.v1.ListRegistrationCountriesResponse - (*ListRegionsRequest)(nil), // 25: hyapp.user.v1.ListRegionsRequest - (*ListRegionsResponse)(nil), // 26: hyapp.user.v1.ListRegionsResponse - (*GetRegionRequest)(nil), // 27: hyapp.user.v1.GetRegionRequest - (*UpdateRegionRequest)(nil), // 28: hyapp.user.v1.UpdateRegionRequest - (*ReplaceRegionCountriesRequest)(nil), // 29: hyapp.user.v1.ReplaceRegionCountriesRequest - (*RegionResponse)(nil), // 30: hyapp.user.v1.RegionResponse - (*UserIdentity)(nil), // 31: hyapp.user.v1.UserIdentity - (*GetUserIdentityRequest)(nil), // 32: hyapp.user.v1.GetUserIdentityRequest - (*GetUserIdentityResponse)(nil), // 33: hyapp.user.v1.GetUserIdentityResponse - (*ResolveDisplayUserIDRequest)(nil), // 34: hyapp.user.v1.ResolveDisplayUserIDRequest - (*ResolveDisplayUserIDResponse)(nil), // 35: hyapp.user.v1.ResolveDisplayUserIDResponse - (*ChangeDisplayUserIDRequest)(nil), // 36: hyapp.user.v1.ChangeDisplayUserIDRequest - (*ChangeDisplayUserIDResponse)(nil), // 37: hyapp.user.v1.ChangeDisplayUserIDResponse - (*ApplyPrettyDisplayUserIDRequest)(nil), // 38: hyapp.user.v1.ApplyPrettyDisplayUserIDRequest - (*ApplyPrettyDisplayUserIDResponse)(nil), // 39: hyapp.user.v1.ApplyPrettyDisplayUserIDResponse - (*ExpirePrettyDisplayUserIDRequest)(nil), // 40: hyapp.user.v1.ExpirePrettyDisplayUserIDRequest - (*ExpirePrettyDisplayUserIDResponse)(nil), // 41: hyapp.user.v1.ExpirePrettyDisplayUserIDResponse - nil, // 42: hyapp.user.v1.BatchGetUsersResponse.UsersEntry + (*ListUserIDsRequest)(nil), // 11: hyapp.user.v1.ListUserIDsRequest + (*ListUserIDsResponse)(nil), // 12: hyapp.user.v1.ListUserIDsResponse + (*UpdateUserProfileRequest)(nil), // 13: hyapp.user.v1.UpdateUserProfileRequest + (*UpdateUserProfileResponse)(nil), // 14: hyapp.user.v1.UpdateUserProfileResponse + (*ChangeUserCountryRequest)(nil), // 15: hyapp.user.v1.ChangeUserCountryRequest + (*ChangeUserCountryResponse)(nil), // 16: hyapp.user.v1.ChangeUserCountryResponse + (*CompleteOnboardingRequest)(nil), // 17: hyapp.user.v1.CompleteOnboardingRequest + (*CompleteOnboardingResponse)(nil), // 18: hyapp.user.v1.CompleteOnboardingResponse + (*BindPushTokenRequest)(nil), // 19: hyapp.user.v1.BindPushTokenRequest + (*BindPushTokenResponse)(nil), // 20: hyapp.user.v1.BindPushTokenResponse + (*DeletePushTokenRequest)(nil), // 21: hyapp.user.v1.DeletePushTokenRequest + (*DeletePushTokenResponse)(nil), // 22: hyapp.user.v1.DeletePushTokenResponse + (*Country)(nil), // 23: hyapp.user.v1.Country + (*Region)(nil), // 24: hyapp.user.v1.Region + (*ListCountriesRequest)(nil), // 25: hyapp.user.v1.ListCountriesRequest + (*ListCountriesResponse)(nil), // 26: hyapp.user.v1.ListCountriesResponse + (*UpdateCountryRequest)(nil), // 27: hyapp.user.v1.UpdateCountryRequest + (*CountryResponse)(nil), // 28: hyapp.user.v1.CountryResponse + (*ListRegistrationCountriesRequest)(nil), // 29: hyapp.user.v1.ListRegistrationCountriesRequest + (*ListRegistrationCountriesResponse)(nil), // 30: hyapp.user.v1.ListRegistrationCountriesResponse + (*ListRegionsRequest)(nil), // 31: hyapp.user.v1.ListRegionsRequest + (*ListRegionsResponse)(nil), // 32: hyapp.user.v1.ListRegionsResponse + (*GetRegionRequest)(nil), // 33: hyapp.user.v1.GetRegionRequest + (*UpdateRegionRequest)(nil), // 34: hyapp.user.v1.UpdateRegionRequest + (*ReplaceRegionCountriesRequest)(nil), // 35: hyapp.user.v1.ReplaceRegionCountriesRequest + (*RegionResponse)(nil), // 36: hyapp.user.v1.RegionResponse + (*UserIdentity)(nil), // 37: hyapp.user.v1.UserIdentity + (*GetUserIdentityRequest)(nil), // 38: hyapp.user.v1.GetUserIdentityRequest + (*GetUserIdentityResponse)(nil), // 39: hyapp.user.v1.GetUserIdentityResponse + (*ResolveDisplayUserIDRequest)(nil), // 40: hyapp.user.v1.ResolveDisplayUserIDRequest + (*ResolveDisplayUserIDResponse)(nil), // 41: hyapp.user.v1.ResolveDisplayUserIDResponse + (*ChangeDisplayUserIDRequest)(nil), // 42: hyapp.user.v1.ChangeDisplayUserIDRequest + (*ChangeDisplayUserIDResponse)(nil), // 43: hyapp.user.v1.ChangeDisplayUserIDResponse + (*ApplyPrettyDisplayUserIDRequest)(nil), // 44: hyapp.user.v1.ApplyPrettyDisplayUserIDRequest + (*ApplyPrettyDisplayUserIDResponse)(nil), // 45: hyapp.user.v1.ApplyPrettyDisplayUserIDResponse + (*ExpirePrettyDisplayUserIDRequest)(nil), // 46: hyapp.user.v1.ExpirePrettyDisplayUserIDRequest + (*ExpirePrettyDisplayUserIDResponse)(nil), // 47: hyapp.user.v1.ExpirePrettyDisplayUserIDResponse + nil, // 48: 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 @@ -3798,78 +4238,87 @@ var file_proto_user_v1_user_proto_depIdxs = []int32{ 1, // 3: hyapp.user.v1.GetUserRequest.meta:type_name -> hyapp.user.v1.RequestMeta 5, // 4: hyapp.user.v1.GetUserResponse.user:type_name -> hyapp.user.v1.User 1, // 5: hyapp.user.v1.BatchGetUsersRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 42, // 6: hyapp.user.v1.BatchGetUsersResponse.users:type_name -> hyapp.user.v1.BatchGetUsersResponse.UsersEntry - 1, // 7: hyapp.user.v1.UpdateUserProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 5, // 8: hyapp.user.v1.UpdateUserProfileResponse.user:type_name -> hyapp.user.v1.User - 1, // 9: hyapp.user.v1.ChangeUserCountryRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 5, // 10: hyapp.user.v1.ChangeUserCountryResponse.user:type_name -> hyapp.user.v1.User - 1, // 11: hyapp.user.v1.CompleteOnboardingRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 5, // 12: hyapp.user.v1.CompleteOnboardingResponse.user:type_name -> hyapp.user.v1.User - 6, // 13: hyapp.user.v1.CompleteOnboardingResponse.token:type_name -> hyapp.user.v1.AuthToken - 1, // 14: hyapp.user.v1.ListCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 17, // 15: hyapp.user.v1.ListCountriesResponse.countries:type_name -> hyapp.user.v1.Country - 1, // 16: hyapp.user.v1.UpdateCountryRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 17, // 17: hyapp.user.v1.CountryResponse.country:type_name -> hyapp.user.v1.Country - 1, // 18: hyapp.user.v1.ListRegistrationCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 17, // 19: hyapp.user.v1.ListRegistrationCountriesResponse.countries:type_name -> hyapp.user.v1.Country - 1, // 20: hyapp.user.v1.ListRegionsRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 18, // 21: hyapp.user.v1.ListRegionsResponse.regions:type_name -> hyapp.user.v1.Region - 1, // 22: hyapp.user.v1.GetRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 1, // 23: hyapp.user.v1.UpdateRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 1, // 24: hyapp.user.v1.ReplaceRegionCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 18, // 25: hyapp.user.v1.RegionResponse.region:type_name -> hyapp.user.v1.Region - 1, // 26: hyapp.user.v1.GetUserIdentityRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 31, // 27: hyapp.user.v1.GetUserIdentityResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 1, // 28: hyapp.user.v1.ResolveDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 31, // 29: hyapp.user.v1.ResolveDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 1, // 30: hyapp.user.v1.ChangeDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 31, // 31: hyapp.user.v1.ChangeDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 1, // 32: hyapp.user.v1.ApplyPrettyDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 31, // 33: hyapp.user.v1.ApplyPrettyDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 1, // 34: hyapp.user.v1.ExpirePrettyDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta - 31, // 35: hyapp.user.v1.ExpirePrettyDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity - 5, // 36: hyapp.user.v1.BatchGetUsersResponse.UsersEntry.value:type_name -> hyapp.user.v1.User - 7, // 37: hyapp.user.v1.UserService.GetUser:input_type -> hyapp.user.v1.GetUserRequest - 9, // 38: hyapp.user.v1.UserService.BatchGetUsers:input_type -> hyapp.user.v1.BatchGetUsersRequest - 11, // 39: hyapp.user.v1.UserService.UpdateUserProfile:input_type -> hyapp.user.v1.UpdateUserProfileRequest - 13, // 40: hyapp.user.v1.UserService.ChangeUserCountry:input_type -> hyapp.user.v1.ChangeUserCountryRequest - 15, // 41: hyapp.user.v1.UserService.CompleteOnboarding:input_type -> hyapp.user.v1.CompleteOnboardingRequest - 3, // 42: hyapp.user.v1.AppRegistryService.ResolveApp:input_type -> hyapp.user.v1.ResolveAppRequest - 19, // 43: hyapp.user.v1.CountryAdminService.ListCountries:input_type -> hyapp.user.v1.ListCountriesRequest - 21, // 44: hyapp.user.v1.CountryAdminService.UpdateCountry:input_type -> hyapp.user.v1.UpdateCountryRequest - 23, // 45: hyapp.user.v1.CountryQueryService.ListRegistrationCountries:input_type -> hyapp.user.v1.ListRegistrationCountriesRequest - 25, // 46: hyapp.user.v1.RegionAdminService.ListRegions:input_type -> hyapp.user.v1.ListRegionsRequest - 27, // 47: hyapp.user.v1.RegionAdminService.GetRegion:input_type -> hyapp.user.v1.GetRegionRequest - 28, // 48: hyapp.user.v1.RegionAdminService.UpdateRegion:input_type -> hyapp.user.v1.UpdateRegionRequest - 29, // 49: hyapp.user.v1.RegionAdminService.ReplaceRegionCountries:input_type -> hyapp.user.v1.ReplaceRegionCountriesRequest - 32, // 50: hyapp.user.v1.UserIdentityService.GetUserIdentity:input_type -> hyapp.user.v1.GetUserIdentityRequest - 34, // 51: hyapp.user.v1.UserIdentityService.ResolveDisplayUserID:input_type -> hyapp.user.v1.ResolveDisplayUserIDRequest - 36, // 52: hyapp.user.v1.UserIdentityService.ChangeDisplayUserID:input_type -> hyapp.user.v1.ChangeDisplayUserIDRequest - 38, // 53: hyapp.user.v1.UserIdentityService.ApplyPrettyDisplayUserID:input_type -> hyapp.user.v1.ApplyPrettyDisplayUserIDRequest - 40, // 54: hyapp.user.v1.UserIdentityService.ExpirePrettyDisplayUserID:input_type -> hyapp.user.v1.ExpirePrettyDisplayUserIDRequest - 8, // 55: hyapp.user.v1.UserService.GetUser:output_type -> hyapp.user.v1.GetUserResponse - 10, // 56: hyapp.user.v1.UserService.BatchGetUsers:output_type -> hyapp.user.v1.BatchGetUsersResponse - 12, // 57: hyapp.user.v1.UserService.UpdateUserProfile:output_type -> hyapp.user.v1.UpdateUserProfileResponse - 14, // 58: hyapp.user.v1.UserService.ChangeUserCountry:output_type -> hyapp.user.v1.ChangeUserCountryResponse - 16, // 59: hyapp.user.v1.UserService.CompleteOnboarding:output_type -> hyapp.user.v1.CompleteOnboardingResponse - 4, // 60: hyapp.user.v1.AppRegistryService.ResolveApp:output_type -> hyapp.user.v1.ResolveAppResponse - 20, // 61: hyapp.user.v1.CountryAdminService.ListCountries:output_type -> hyapp.user.v1.ListCountriesResponse - 22, // 62: hyapp.user.v1.CountryAdminService.UpdateCountry:output_type -> hyapp.user.v1.CountryResponse - 24, // 63: hyapp.user.v1.CountryQueryService.ListRegistrationCountries:output_type -> hyapp.user.v1.ListRegistrationCountriesResponse - 26, // 64: hyapp.user.v1.RegionAdminService.ListRegions:output_type -> hyapp.user.v1.ListRegionsResponse - 30, // 65: hyapp.user.v1.RegionAdminService.GetRegion:output_type -> hyapp.user.v1.RegionResponse - 30, // 66: hyapp.user.v1.RegionAdminService.UpdateRegion:output_type -> hyapp.user.v1.RegionResponse - 30, // 67: hyapp.user.v1.RegionAdminService.ReplaceRegionCountries:output_type -> hyapp.user.v1.RegionResponse - 33, // 68: hyapp.user.v1.UserIdentityService.GetUserIdentity:output_type -> hyapp.user.v1.GetUserIdentityResponse - 35, // 69: hyapp.user.v1.UserIdentityService.ResolveDisplayUserID:output_type -> hyapp.user.v1.ResolveDisplayUserIDResponse - 37, // 70: hyapp.user.v1.UserIdentityService.ChangeDisplayUserID:output_type -> hyapp.user.v1.ChangeDisplayUserIDResponse - 39, // 71: hyapp.user.v1.UserIdentityService.ApplyPrettyDisplayUserID:output_type -> hyapp.user.v1.ApplyPrettyDisplayUserIDResponse - 41, // 72: hyapp.user.v1.UserIdentityService.ExpirePrettyDisplayUserID:output_type -> hyapp.user.v1.ExpirePrettyDisplayUserIDResponse - 55, // [55:73] is the sub-list for method output_type - 37, // [37:55] 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 + 48, // 6: hyapp.user.v1.BatchGetUsersResponse.users:type_name -> hyapp.user.v1.BatchGetUsersResponse.UsersEntry + 1, // 7: hyapp.user.v1.ListUserIDsRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 8: hyapp.user.v1.UpdateUserProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 5, // 9: hyapp.user.v1.UpdateUserProfileResponse.user:type_name -> hyapp.user.v1.User + 1, // 10: hyapp.user.v1.ChangeUserCountryRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 5, // 11: hyapp.user.v1.ChangeUserCountryResponse.user:type_name -> hyapp.user.v1.User + 1, // 12: hyapp.user.v1.CompleteOnboardingRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 5, // 13: hyapp.user.v1.CompleteOnboardingResponse.user:type_name -> hyapp.user.v1.User + 6, // 14: hyapp.user.v1.CompleteOnboardingResponse.token:type_name -> hyapp.user.v1.AuthToken + 1, // 15: hyapp.user.v1.BindPushTokenRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 16: hyapp.user.v1.DeletePushTokenRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 17: hyapp.user.v1.ListCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 23, // 18: hyapp.user.v1.ListCountriesResponse.countries:type_name -> hyapp.user.v1.Country + 1, // 19: hyapp.user.v1.UpdateCountryRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 23, // 20: hyapp.user.v1.CountryResponse.country:type_name -> hyapp.user.v1.Country + 1, // 21: hyapp.user.v1.ListRegistrationCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 23, // 22: hyapp.user.v1.ListRegistrationCountriesResponse.countries:type_name -> hyapp.user.v1.Country + 1, // 23: hyapp.user.v1.ListRegionsRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 24, // 24: hyapp.user.v1.ListRegionsResponse.regions:type_name -> hyapp.user.v1.Region + 1, // 25: hyapp.user.v1.GetRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 26: hyapp.user.v1.UpdateRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 1, // 27: hyapp.user.v1.ReplaceRegionCountriesRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 24, // 28: hyapp.user.v1.RegionResponse.region:type_name -> hyapp.user.v1.Region + 1, // 29: hyapp.user.v1.GetUserIdentityRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 37, // 30: hyapp.user.v1.GetUserIdentityResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 1, // 31: hyapp.user.v1.ResolveDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 37, // 32: hyapp.user.v1.ResolveDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 1, // 33: hyapp.user.v1.ChangeDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 37, // 34: hyapp.user.v1.ChangeDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 1, // 35: hyapp.user.v1.ApplyPrettyDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 37, // 36: hyapp.user.v1.ApplyPrettyDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 1, // 37: hyapp.user.v1.ExpirePrettyDisplayUserIDRequest.meta:type_name -> hyapp.user.v1.RequestMeta + 37, // 38: hyapp.user.v1.ExpirePrettyDisplayUserIDResponse.identity:type_name -> hyapp.user.v1.UserIdentity + 5, // 39: hyapp.user.v1.BatchGetUsersResponse.UsersEntry.value:type_name -> hyapp.user.v1.User + 7, // 40: hyapp.user.v1.UserService.GetUser:input_type -> hyapp.user.v1.GetUserRequest + 9, // 41: hyapp.user.v1.UserService.BatchGetUsers:input_type -> hyapp.user.v1.BatchGetUsersRequest + 11, // 42: hyapp.user.v1.UserService.ListUserIDs:input_type -> hyapp.user.v1.ListUserIDsRequest + 13, // 43: hyapp.user.v1.UserService.UpdateUserProfile:input_type -> hyapp.user.v1.UpdateUserProfileRequest + 15, // 44: hyapp.user.v1.UserService.ChangeUserCountry:input_type -> hyapp.user.v1.ChangeUserCountryRequest + 17, // 45: hyapp.user.v1.UserService.CompleteOnboarding:input_type -> hyapp.user.v1.CompleteOnboardingRequest + 19, // 46: hyapp.user.v1.UserDeviceService.BindPushToken:input_type -> hyapp.user.v1.BindPushTokenRequest + 21, // 47: hyapp.user.v1.UserDeviceService.DeletePushToken:input_type -> hyapp.user.v1.DeletePushTokenRequest + 3, // 48: hyapp.user.v1.AppRegistryService.ResolveApp:input_type -> hyapp.user.v1.ResolveAppRequest + 25, // 49: hyapp.user.v1.CountryAdminService.ListCountries:input_type -> hyapp.user.v1.ListCountriesRequest + 27, // 50: hyapp.user.v1.CountryAdminService.UpdateCountry:input_type -> hyapp.user.v1.UpdateCountryRequest + 29, // 51: hyapp.user.v1.CountryQueryService.ListRegistrationCountries:input_type -> hyapp.user.v1.ListRegistrationCountriesRequest + 31, // 52: hyapp.user.v1.RegionAdminService.ListRegions:input_type -> hyapp.user.v1.ListRegionsRequest + 33, // 53: hyapp.user.v1.RegionAdminService.GetRegion:input_type -> hyapp.user.v1.GetRegionRequest + 34, // 54: hyapp.user.v1.RegionAdminService.UpdateRegion:input_type -> hyapp.user.v1.UpdateRegionRequest + 35, // 55: hyapp.user.v1.RegionAdminService.ReplaceRegionCountries:input_type -> hyapp.user.v1.ReplaceRegionCountriesRequest + 38, // 56: hyapp.user.v1.UserIdentityService.GetUserIdentity:input_type -> hyapp.user.v1.GetUserIdentityRequest + 40, // 57: hyapp.user.v1.UserIdentityService.ResolveDisplayUserID:input_type -> hyapp.user.v1.ResolveDisplayUserIDRequest + 42, // 58: hyapp.user.v1.UserIdentityService.ChangeDisplayUserID:input_type -> hyapp.user.v1.ChangeDisplayUserIDRequest + 44, // 59: hyapp.user.v1.UserIdentityService.ApplyPrettyDisplayUserID:input_type -> hyapp.user.v1.ApplyPrettyDisplayUserIDRequest + 46, // 60: hyapp.user.v1.UserIdentityService.ExpirePrettyDisplayUserID:input_type -> hyapp.user.v1.ExpirePrettyDisplayUserIDRequest + 8, // 61: hyapp.user.v1.UserService.GetUser:output_type -> hyapp.user.v1.GetUserResponse + 10, // 62: hyapp.user.v1.UserService.BatchGetUsers:output_type -> hyapp.user.v1.BatchGetUsersResponse + 12, // 63: hyapp.user.v1.UserService.ListUserIDs:output_type -> hyapp.user.v1.ListUserIDsResponse + 14, // 64: hyapp.user.v1.UserService.UpdateUserProfile:output_type -> hyapp.user.v1.UpdateUserProfileResponse + 16, // 65: hyapp.user.v1.UserService.ChangeUserCountry:output_type -> hyapp.user.v1.ChangeUserCountryResponse + 18, // 66: hyapp.user.v1.UserService.CompleteOnboarding:output_type -> hyapp.user.v1.CompleteOnboardingResponse + 20, // 67: hyapp.user.v1.UserDeviceService.BindPushToken:output_type -> hyapp.user.v1.BindPushTokenResponse + 22, // 68: hyapp.user.v1.UserDeviceService.DeletePushToken:output_type -> hyapp.user.v1.DeletePushTokenResponse + 4, // 69: hyapp.user.v1.AppRegistryService.ResolveApp:output_type -> hyapp.user.v1.ResolveAppResponse + 26, // 70: hyapp.user.v1.CountryAdminService.ListCountries:output_type -> hyapp.user.v1.ListCountriesResponse + 28, // 71: hyapp.user.v1.CountryAdminService.UpdateCountry:output_type -> hyapp.user.v1.CountryResponse + 30, // 72: hyapp.user.v1.CountryQueryService.ListRegistrationCountries:output_type -> hyapp.user.v1.ListRegistrationCountriesResponse + 32, // 73: hyapp.user.v1.RegionAdminService.ListRegions:output_type -> hyapp.user.v1.ListRegionsResponse + 36, // 74: hyapp.user.v1.RegionAdminService.GetRegion:output_type -> hyapp.user.v1.RegionResponse + 36, // 75: hyapp.user.v1.RegionAdminService.UpdateRegion:output_type -> hyapp.user.v1.RegionResponse + 36, // 76: hyapp.user.v1.RegionAdminService.ReplaceRegionCountries:output_type -> hyapp.user.v1.RegionResponse + 39, // 77: hyapp.user.v1.UserIdentityService.GetUserIdentity:output_type -> hyapp.user.v1.GetUserIdentityResponse + 41, // 78: hyapp.user.v1.UserIdentityService.ResolveDisplayUserID:output_type -> hyapp.user.v1.ResolveDisplayUserIDResponse + 43, // 79: hyapp.user.v1.UserIdentityService.ChangeDisplayUserID:output_type -> hyapp.user.v1.ChangeDisplayUserIDResponse + 45, // 80: hyapp.user.v1.UserIdentityService.ApplyPrettyDisplayUserID:output_type -> hyapp.user.v1.ApplyPrettyDisplayUserIDResponse + 47, // 81: hyapp.user.v1.UserIdentityService.ExpirePrettyDisplayUserID:output_type -> hyapp.user.v1.ExpirePrettyDisplayUserIDResponse + 61, // [61:82] is the sub-list for method output_type + 40, // [40:61] 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_user_v1_user_proto_init() } @@ -3877,511 +4326,17 @@ func file_proto_user_v1_user_proto_init() { if File_proto_user_v1_user_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_proto_user_v1_user_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*RequestMeta); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*App); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*ResolveAppRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*ResolveAppResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*User); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*AuthToken); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*GetUserRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*GetUserResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*BatchGetUsersRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*BatchGetUsersResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*UpdateUserProfileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*UpdateUserProfileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*ChangeUserCountryRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*ChangeUserCountryResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*CompleteOnboardingRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*CompleteOnboardingResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*Country); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*Region); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*ListCountriesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[19].Exporter = func(v any, i int) any { - switch v := v.(*ListCountriesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[20].Exporter = func(v any, i int) any { - switch v := v.(*UpdateCountryRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[21].Exporter = func(v any, i int) any { - switch v := v.(*CountryResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[22].Exporter = func(v any, i int) any { - switch v := v.(*ListRegistrationCountriesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[23].Exporter = func(v any, i int) any { - switch v := v.(*ListRegistrationCountriesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[24].Exporter = func(v any, i int) any { - switch v := v.(*ListRegionsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[25].Exporter = func(v any, i int) any { - switch v := v.(*ListRegionsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[26].Exporter = func(v any, i int) any { - switch v := v.(*GetRegionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[27].Exporter = func(v any, i int) any { - switch v := v.(*UpdateRegionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[28].Exporter = func(v any, i int) any { - switch v := v.(*ReplaceRegionCountriesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[29].Exporter = func(v any, i int) any { - switch v := v.(*RegionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[30].Exporter = func(v any, i int) any { - switch v := v.(*UserIdentity); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[31].Exporter = func(v any, i int) any { - switch v := v.(*GetUserIdentityRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[32].Exporter = func(v any, i int) any { - switch v := v.(*GetUserIdentityResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[33].Exporter = func(v any, i int) any { - switch v := v.(*ResolveDisplayUserIDRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[34].Exporter = func(v any, i int) any { - switch v := v.(*ResolveDisplayUserIDResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[35].Exporter = func(v any, i int) any { - switch v := v.(*ChangeDisplayUserIDRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[36].Exporter = func(v any, i int) any { - switch v := v.(*ChangeDisplayUserIDResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[37].Exporter = func(v any, i int) any { - switch v := v.(*ApplyPrettyDisplayUserIDRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[38].Exporter = func(v any, i int) any { - switch v := v.(*ApplyPrettyDisplayUserIDResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[39].Exporter = func(v any, i int) any { - switch v := v.(*ExpirePrettyDisplayUserIDRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_user_v1_user_proto_msgTypes[40].Exporter = func(v any, i int) any { - switch v := v.(*ExpirePrettyDisplayUserIDResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_proto_user_v1_user_proto_msgTypes[10].OneofWrappers = []any{} - file_proto_user_v1_user_proto_msgTypes[18].OneofWrappers = []any{} + file_proto_user_v1_user_proto_msgTypes[12].OneofWrappers = []any{} + file_proto_user_v1_user_proto_msgTypes[24].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: 42, + NumMessages: 48, NumExtensions: 0, - NumServices: 6, + NumServices: 7, }, GoTypes: file_proto_user_v1_user_proto_goTypes, DependencyIndexes: file_proto_user_v1_user_proto_depIdxs, diff --git a/api/proto/user/v1/user.proto b/api/proto/user/v1/user.proto index 6739ccf0..0fc2b7f4 100644 --- a/api/proto/user/v1/user.proto +++ b/api/proto/user/v1/user.proto @@ -120,6 +120,23 @@ message BatchGetUsersResponse { map users = 1; } +// ListUserIDsRequest 给低频后台 fanout/重算任务按 user_id 游标读取目标用户。 +message ListUserIDsRequest { + RequestMeta meta = 1; + string target_scope = 2; + int64 cursor_user_id = 3; + int32 page_size = 4; + int64 region_id = 5; + string country = 6; +} + +// ListUserIDsResponse 返回一页递增 user_id,调用方必须用 next_cursor_user_id 继续。 +message ListUserIDsResponse { + repeated int64 user_ids = 1; + int64 next_cursor_user_id = 2; + bool done = 3; +} + // UpdateUserProfileRequest 修改用户可自助维护的基础资料。 message UpdateUserProfileRequest { RequestMeta meta = 1; @@ -167,6 +184,39 @@ message CompleteOnboardingResponse { AuthToken token = 5; } +// BindPushTokenRequest 绑定当前登录用户的系统推送 token。 +// push token 只服务离线触达,不作为登录凭证或设备身份凭证。 +message BindPushTokenRequest { + RequestMeta meta = 1; + int64 user_id = 2; + string device_id = 3; + string push_token = 4; + string provider = 5; + string platform = 6; + string app_version = 7; + string language = 8; + string timezone = 9; +} + +message BindPushTokenResponse { + bool bound = 1; + int64 updated_at_ms = 2; +} + +// DeletePushTokenRequest 删除或失效当前登录用户的系统推送 token。 +// push_token 可为空;为空时按 user_id + device_id 失效该设备的 active token。 +message DeletePushTokenRequest { + RequestMeta meta = 1; + int64 user_id = 2; + string device_id = 3; + string push_token = 4; +} + +message DeletePushTokenResponse { + bool deleted = 1; + int64 updated_at_ms = 2; +} + // Country 是国家主数据投影,客户端和普通用户流程只提交 country_code。 message Country { int64 country_id = 1; @@ -345,11 +395,18 @@ message ExpirePrettyDisplayUserIDResponse { service UserService { rpc GetUser(GetUserRequest) returns (GetUserResponse); rpc BatchGetUsers(BatchGetUsersRequest) returns (BatchGetUsersResponse); + rpc ListUserIDs(ListUserIDsRequest) returns (ListUserIDsResponse); rpc UpdateUserProfile(UpdateUserProfileRequest) returns (UpdateUserProfileResponse); rpc ChangeUserCountry(ChangeUserCountryRequest) returns (ChangeUserCountryResponse); rpc CompleteOnboarding(CompleteOnboardingRequest) returns (CompleteOnboardingResponse); } +// UserDeviceService 承载 App 设备推送 token 的绑定和失效。 +service UserDeviceService { + rpc BindPushToken(BindPushTokenRequest) returns (BindPushTokenResponse); + rpc DeletePushToken(DeletePushTokenRequest) returns (DeletePushTokenResponse); +} + // AppRegistryService 是 gateway 解析 package_name -> app_code 的内部入口。 service AppRegistryService { rpc ResolveApp(ResolveAppRequest) returns (ResolveAppResponse); diff --git a/api/proto/user/v1/user_grpc.pb.go b/api/proto/user/v1/user_grpc.pb.go index f55fb717..94389443 100644 --- a/api/proto/user/v1/user_grpc.pb.go +++ b/api/proto/user/v1/user_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v5.29.2 +// - protoc v5.27.3 // source: proto/user/v1/user.proto package userv1 @@ -21,6 +21,7 @@ const _ = grpc.SupportPackageIsVersion9 const ( UserService_GetUser_FullMethodName = "/hyapp.user.v1.UserService/GetUser" UserService_BatchGetUsers_FullMethodName = "/hyapp.user.v1.UserService/BatchGetUsers" + UserService_ListUserIDs_FullMethodName = "/hyapp.user.v1.UserService/ListUserIDs" UserService_UpdateUserProfile_FullMethodName = "/hyapp.user.v1.UserService/UpdateUserProfile" UserService_ChangeUserCountry_FullMethodName = "/hyapp.user.v1.UserService/ChangeUserCountry" UserService_CompleteOnboarding_FullMethodName = "/hyapp.user.v1.UserService/CompleteOnboarding" @@ -34,6 +35,7 @@ const ( type UserServiceClient interface { GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) BatchGetUsers(ctx context.Context, in *BatchGetUsersRequest, opts ...grpc.CallOption) (*BatchGetUsersResponse, error) + ListUserIDs(ctx context.Context, in *ListUserIDsRequest, opts ...grpc.CallOption) (*ListUserIDsResponse, error) UpdateUserProfile(ctx context.Context, in *UpdateUserProfileRequest, opts ...grpc.CallOption) (*UpdateUserProfileResponse, error) ChangeUserCountry(ctx context.Context, in *ChangeUserCountryRequest, opts ...grpc.CallOption) (*ChangeUserCountryResponse, error) CompleteOnboarding(ctx context.Context, in *CompleteOnboardingRequest, opts ...grpc.CallOption) (*CompleteOnboardingResponse, error) @@ -67,6 +69,16 @@ func (c *userServiceClient) BatchGetUsers(ctx context.Context, in *BatchGetUsers return out, nil } +func (c *userServiceClient) ListUserIDs(ctx context.Context, in *ListUserIDsRequest, opts ...grpc.CallOption) (*ListUserIDsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListUserIDsResponse) + err := c.cc.Invoke(ctx, UserService_ListUserIDs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *userServiceClient) UpdateUserProfile(ctx context.Context, in *UpdateUserProfileRequest, opts ...grpc.CallOption) (*UpdateUserProfileResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(UpdateUserProfileResponse) @@ -105,6 +117,7 @@ func (c *userServiceClient) CompleteOnboarding(ctx context.Context, in *Complete type UserServiceServer interface { GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) BatchGetUsers(context.Context, *BatchGetUsersRequest) (*BatchGetUsersResponse, error) + ListUserIDs(context.Context, *ListUserIDsRequest) (*ListUserIDsResponse, error) UpdateUserProfile(context.Context, *UpdateUserProfileRequest) (*UpdateUserProfileResponse, error) ChangeUserCountry(context.Context, *ChangeUserCountryRequest) (*ChangeUserCountryResponse, error) CompleteOnboarding(context.Context, *CompleteOnboardingRequest) (*CompleteOnboardingResponse, error) @@ -124,6 +137,9 @@ func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) func (UnimplementedUserServiceServer) BatchGetUsers(context.Context, *BatchGetUsersRequest) (*BatchGetUsersResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method BatchGetUsers not implemented") } +func (UnimplementedUserServiceServer) ListUserIDs(context.Context, *ListUserIDsRequest) (*ListUserIDsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListUserIDs not implemented") +} func (UnimplementedUserServiceServer) UpdateUserProfile(context.Context, *UpdateUserProfileRequest) (*UpdateUserProfileResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateUserProfile not implemented") } @@ -190,6 +206,24 @@ func _UserService_BatchGetUsers_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _UserService_ListUserIDs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListUserIDsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).ListUserIDs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserService_ListUserIDs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).ListUserIDs(ctx, req.(*ListUserIDsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _UserService_UpdateUserProfile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(UpdateUserProfileRequest) if err := dec(in); err != nil { @@ -259,6 +293,10 @@ var UserService_ServiceDesc = grpc.ServiceDesc{ MethodName: "BatchGetUsers", Handler: _UserService_BatchGetUsers_Handler, }, + { + MethodName: "ListUserIDs", + Handler: _UserService_ListUserIDs_Handler, + }, { MethodName: "UpdateUserProfile", Handler: _UserService_UpdateUserProfile_Handler, @@ -276,6 +314,150 @@ var UserService_ServiceDesc = grpc.ServiceDesc{ Metadata: "proto/user/v1/user.proto", } +const ( + UserDeviceService_BindPushToken_FullMethodName = "/hyapp.user.v1.UserDeviceService/BindPushToken" + UserDeviceService_DeletePushToken_FullMethodName = "/hyapp.user.v1.UserDeviceService/DeletePushToken" +) + +// UserDeviceServiceClient is the client API for UserDeviceService 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. +// +// UserDeviceService 承载 App 设备推送 token 的绑定和失效。 +type UserDeviceServiceClient interface { + BindPushToken(ctx context.Context, in *BindPushTokenRequest, opts ...grpc.CallOption) (*BindPushTokenResponse, error) + DeletePushToken(ctx context.Context, in *DeletePushTokenRequest, opts ...grpc.CallOption) (*DeletePushTokenResponse, error) +} + +type userDeviceServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUserDeviceServiceClient(cc grpc.ClientConnInterface) UserDeviceServiceClient { + return &userDeviceServiceClient{cc} +} + +func (c *userDeviceServiceClient) BindPushToken(ctx context.Context, in *BindPushTokenRequest, opts ...grpc.CallOption) (*BindPushTokenResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BindPushTokenResponse) + err := c.cc.Invoke(ctx, UserDeviceService_BindPushToken_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userDeviceServiceClient) DeletePushToken(ctx context.Context, in *DeletePushTokenRequest, opts ...grpc.CallOption) (*DeletePushTokenResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeletePushTokenResponse) + err := c.cc.Invoke(ctx, UserDeviceService_DeletePushToken_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserDeviceServiceServer is the server API for UserDeviceService service. +// All implementations must embed UnimplementedUserDeviceServiceServer +// for forward compatibility. +// +// UserDeviceService 承载 App 设备推送 token 的绑定和失效。 +type UserDeviceServiceServer interface { + BindPushToken(context.Context, *BindPushTokenRequest) (*BindPushTokenResponse, error) + DeletePushToken(context.Context, *DeletePushTokenRequest) (*DeletePushTokenResponse, error) + mustEmbedUnimplementedUserDeviceServiceServer() +} + +// UnimplementedUserDeviceServiceServer 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 UnimplementedUserDeviceServiceServer struct{} + +func (UnimplementedUserDeviceServiceServer) BindPushToken(context.Context, *BindPushTokenRequest) (*BindPushTokenResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method BindPushToken not implemented") +} +func (UnimplementedUserDeviceServiceServer) DeletePushToken(context.Context, *DeletePushTokenRequest) (*DeletePushTokenResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeletePushToken not implemented") +} +func (UnimplementedUserDeviceServiceServer) mustEmbedUnimplementedUserDeviceServiceServer() {} +func (UnimplementedUserDeviceServiceServer) testEmbeddedByValue() {} + +// UnsafeUserDeviceServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UserDeviceServiceServer will +// result in compilation errors. +type UnsafeUserDeviceServiceServer interface { + mustEmbedUnimplementedUserDeviceServiceServer() +} + +func RegisterUserDeviceServiceServer(s grpc.ServiceRegistrar, srv UserDeviceServiceServer) { + // If the following call pancis, it indicates UnimplementedUserDeviceServiceServer 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(&UserDeviceService_ServiceDesc, srv) +} + +func _UserDeviceService_BindPushToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BindPushTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserDeviceServiceServer).BindPushToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserDeviceService_BindPushToken_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserDeviceServiceServer).BindPushToken(ctx, req.(*BindPushTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserDeviceService_DeletePushToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeletePushTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserDeviceServiceServer).DeletePushToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserDeviceService_DeletePushToken_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserDeviceServiceServer).DeletePushToken(ctx, req.(*DeletePushTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// UserDeviceService_ServiceDesc is the grpc.ServiceDesc for UserDeviceService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var UserDeviceService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "hyapp.user.v1.UserDeviceService", + HandlerType: (*UserDeviceServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "BindPushToken", + Handler: _UserDeviceService_BindPushToken_Handler, + }, + { + MethodName: "DeletePushToken", + Handler: _UserDeviceService_DeletePushToken_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto/user/v1/user.proto", +} + const ( AppRegistryService_ResolveApp_FullMethodName = "/hyapp.user.v1.AppRegistryService/ResolveApp" ) diff --git a/api/proto/wallet/v1/wallet.pb.go b/api/proto/wallet/v1/wallet.pb.go index 6f88b228..82195b0c 100644 --- a/api/proto/wallet/v1/wallet.pb.go +++ b/api/proto/wallet/v1/wallet.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc-gen-go v1.35.1 +// protoc v5.27.3 // source: proto/wallet/v1/wallet.proto package walletv1 @@ -11,7 +11,6 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" - unsafe "unsafe" ) const ( @@ -23,20 +22,21 @@ const ( // DebitGiftRequest 是 room-service 送礼同步扣费的最小账务输入。 type DebitGiftRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` - RoomId string `protobuf:"bytes,2,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` - SenderUserId int64 `protobuf:"varint,3,opt,name=sender_user_id,json=senderUserId,proto3" json:"sender_user_id,omitempty"` - TargetUserId int64 `protobuf:"varint,4,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` - GiftId string `protobuf:"bytes,5,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` - GiftCount int32 `protobuf:"varint,6,opt,name=gift_count,json=giftCount,proto3" json:"gift_count,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + RoomId string `protobuf:"bytes,2,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + SenderUserId int64 `protobuf:"varint,3,opt,name=sender_user_id,json=senderUserId,proto3" json:"sender_user_id,omitempty"` + TargetUserId int64 `protobuf:"varint,4,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + GiftId string `protobuf:"bytes,5,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` + GiftCount int32 `protobuf:"varint,6,opt,name=gift_count,json=giftCount,proto3" json:"gift_count,omitempty"` // price_version 为空时使用当前生效价格;非空时必须命中 active 价格版本。 PriceVersion string `protobuf:"bytes,7,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` AppCode string `protobuf:"bytes,8,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` // region_id 来自 room-service 房间 visible_region_id,用于校验礼物区域可用性。 - RegionId int64 `protobuf:"varint,9,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + RegionId int64 `protobuf:"varint,9,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` } func (x *DebitGiftRequest) Reset() { @@ -134,19 +134,20 @@ func (x *DebitGiftRequest) GetRegionId() int64 { // DebitGiftResponse 返回扣费流水、服务端结算值和 sender COIN 账后余额。 type DebitGiftResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - BillingReceiptId string `protobuf:"bytes,1,opt,name=billing_receipt_id,json=billingReceiptId,proto3" json:"billing_receipt_id,omitempty"` - TransactionId string `protobuf:"bytes,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - CoinSpent int64 `protobuf:"varint,3,opt,name=coin_spent,json=coinSpent,proto3" json:"coin_spent,omitempty"` - GiftPointAdded int64 `protobuf:"varint,4,opt,name=gift_point_added,json=giftPointAdded,proto3" json:"gift_point_added,omitempty"` - HeatValue int64 `protobuf:"varint,5,opt,name=heat_value,json=heatValue,proto3" json:"heat_value,omitempty"` - PriceVersion string `protobuf:"bytes,6,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BillingReceiptId string `protobuf:"bytes,1,opt,name=billing_receipt_id,json=billingReceiptId,proto3" json:"billing_receipt_id,omitempty"` + TransactionId string `protobuf:"bytes,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + CoinSpent int64 `protobuf:"varint,3,opt,name=coin_spent,json=coinSpent,proto3" json:"coin_spent,omitempty"` + GiftPointAdded int64 `protobuf:"varint,4,opt,name=gift_point_added,json=giftPointAdded,proto3" json:"gift_point_added,omitempty"` + HeatValue int64 `protobuf:"varint,5,opt,name=heat_value,json=heatValue,proto3" json:"heat_value,omitempty"` + PriceVersion string `protobuf:"bytes,6,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` // balance_after 是 sender 被扣费资产 available_amount 账后余额。 BalanceAfter int64 `protobuf:"varint,7,opt,name=balance_after,json=balanceAfter,proto3" json:"balance_after,omitempty"` ChargeAssetType string `protobuf:"bytes,8,opt,name=charge_asset_type,json=chargeAssetType,proto3" json:"charge_asset_type,omitempty"` ChargeAmount int64 `protobuf:"varint,9,opt,name=charge_amount,json=chargeAmount,proto3" json:"charge_amount,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache } func (x *DebitGiftResponse) Reset() { @@ -244,14 +245,15 @@ func (x *DebitGiftResponse) GetChargeAmount() int64 { // AssetBalance 是用户某类资产的余额投影。 type AssetBalance struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetType string `protobuf:"bytes,1,opt,name=asset_type,json=assetType,proto3" json:"asset_type,omitempty"` - AvailableAmount int64 `protobuf:"varint,2,opt,name=available_amount,json=availableAmount,proto3" json:"available_amount,omitempty"` - FrozenAmount int64 `protobuf:"varint,3,opt,name=frozen_amount,json=frozenAmount,proto3" json:"frozen_amount,omitempty"` - Version int64 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"` - AppCode string `protobuf:"bytes,5,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AssetType string `protobuf:"bytes,1,opt,name=asset_type,json=assetType,proto3" json:"asset_type,omitempty"` + AvailableAmount int64 `protobuf:"varint,2,opt,name=available_amount,json=availableAmount,proto3" json:"available_amount,omitempty"` + FrozenAmount int64 `protobuf:"varint,3,opt,name=frozen_amount,json=frozenAmount,proto3" json:"frozen_amount,omitempty"` + Version int64 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"` + AppCode string `protobuf:"bytes,5,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` } func (x *AssetBalance) Reset() { @@ -321,13 +323,14 @@ func (x *AssetBalance) GetAppCode() string { // GetBalancesRequest 查询用户多资产余额;内部调用方负责鉴权和用户范围控制。 type GetBalancesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` - UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - AssetTypes []string `protobuf:"bytes,3,rep,name=asset_types,json=assetTypes,proto3" json:"asset_types,omitempty"` - AppCode string `protobuf:"bytes,4,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + AssetTypes []string `protobuf:"bytes,3,rep,name=asset_types,json=assetTypes,proto3" json:"asset_types,omitempty"` + AppCode string `protobuf:"bytes,4,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` } func (x *GetBalancesRequest) Reset() { @@ -389,10 +392,11 @@ func (x *GetBalancesRequest) GetAppCode() string { } type GetBalancesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Balances []*AssetBalance `protobuf:"bytes,1,rep,name=balances,proto3" json:"balances,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Balances []*AssetBalance `protobuf:"bytes,1,rep,name=balances,proto3" json:"balances,omitempty"` } func (x *GetBalancesResponse) Reset() { @@ -434,17 +438,18 @@ func (x *GetBalancesResponse) GetBalances() []*AssetBalance { // AdminCreditAssetRequest 是后台手动入账/调账的最小审计命令。 type AdminCreditAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` - TargetUserId int64 `protobuf:"varint,2,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` - AssetType string `protobuf:"bytes,3,opt,name=asset_type,json=assetType,proto3" json:"asset_type,omitempty"` - Amount int64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` - OperatorUserId int64 `protobuf:"varint,5,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - Reason string `protobuf:"bytes,6,opt,name=reason,proto3" json:"reason,omitempty"` - EvidenceRef string `protobuf:"bytes,7,opt,name=evidence_ref,json=evidenceRef,proto3" json:"evidence_ref,omitempty"` - AppCode string `protobuf:"bytes,8,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + TargetUserId int64 `protobuf:"varint,2,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + AssetType string `protobuf:"bytes,3,opt,name=asset_type,json=assetType,proto3" json:"asset_type,omitempty"` + Amount int64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` + OperatorUserId int64 `protobuf:"varint,5,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` + Reason string `protobuf:"bytes,6,opt,name=reason,proto3" json:"reason,omitempty"` + EvidenceRef string `protobuf:"bytes,7,opt,name=evidence_ref,json=evidenceRef,proto3" json:"evidence_ref,omitempty"` + AppCode string `protobuf:"bytes,8,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` } func (x *AdminCreditAssetRequest) Reset() { @@ -534,11 +539,12 @@ func (x *AdminCreditAssetRequest) GetAppCode() string { } type AdminCreditAssetResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - Balance *AssetBalance `protobuf:"bytes,2,opt,name=balance,proto3" json:"balance,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + Balance *AssetBalance `protobuf:"bytes,2,opt,name=balance,proto3" json:"balance,omitempty"` } func (x *AdminCreditAssetResponse) Reset() { @@ -587,18 +593,19 @@ func (x *AdminCreditAssetResponse) GetBalance() *AssetBalance { // TransferCoinFromSellerRequest 是币商给玩家转普通金币的内部账务命令。 type TransferCoinFromSellerRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` - SellerUserId int64 `protobuf:"varint,2,opt,name=seller_user_id,json=sellerUserId,proto3" json:"seller_user_id,omitempty"` - TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` - Amount int64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` - Reason string `protobuf:"bytes,5,opt,name=reason,proto3" json:"reason,omitempty"` - AppCode string `protobuf:"bytes,6,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + SellerUserId int64 `protobuf:"varint,2,opt,name=seller_user_id,json=sellerUserId,proto3" json:"seller_user_id,omitempty"` + TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + Amount int64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` + Reason string `protobuf:"bytes,5,opt,name=reason,proto3" json:"reason,omitempty"` + AppCode string `protobuf:"bytes,6,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` // seller_region_id 和 target_region_id 由 gateway 从 user-service 查询,不接受客户端提交。 SellerRegionId int64 `protobuf:"varint,7,opt,name=seller_region_id,json=sellerRegionId,proto3" json:"seller_region_id,omitempty"` TargetRegionId int64 `protobuf:"varint,8,opt,name=target_region_id,json=targetRegionId,proto3" json:"target_region_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache } func (x *TransferCoinFromSellerRequest) Reset() { @@ -689,19 +696,20 @@ func (x *TransferCoinFromSellerRequest) GetTargetRegionId() int64 { // TransferCoinFromSellerResponse 同时返回金币到账结果和本次转账对应的充值金额口径。 type TransferCoinFromSellerResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - SellerBalanceAfter int64 `protobuf:"varint,2,opt,name=seller_balance_after,json=sellerBalanceAfter,proto3" json:"seller_balance_after,omitempty"` - TargetBalanceAfter int64 `protobuf:"varint,3,opt,name=target_balance_after,json=targetBalanceAfter,proto3" json:"target_balance_after,omitempty"` - Amount int64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` - RechargeUsdMinor int64 `protobuf:"varint,5,opt,name=recharge_usd_minor,json=rechargeUsdMinor,proto3" json:"recharge_usd_minor,omitempty"` - RechargeCurrencyCode string `protobuf:"bytes,6,opt,name=recharge_currency_code,json=rechargeCurrencyCode,proto3" json:"recharge_currency_code,omitempty"` - RechargePolicyId int64 `protobuf:"varint,7,opt,name=recharge_policy_id,json=rechargePolicyId,proto3" json:"recharge_policy_id,omitempty"` - RechargePolicyVersion string `protobuf:"bytes,8,opt,name=recharge_policy_version,json=rechargePolicyVersion,proto3" json:"recharge_policy_version,omitempty"` - RechargePolicyCoinAmount int64 `protobuf:"varint,9,opt,name=recharge_policy_coin_amount,json=rechargePolicyCoinAmount,proto3" json:"recharge_policy_coin_amount,omitempty"` - RechargePolicyUsdMinorAmount int64 `protobuf:"varint,10,opt,name=recharge_policy_usd_minor_amount,json=rechargePolicyUsdMinorAmount,proto3" json:"recharge_policy_usd_minor_amount,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + SellerBalanceAfter int64 `protobuf:"varint,2,opt,name=seller_balance_after,json=sellerBalanceAfter,proto3" json:"seller_balance_after,omitempty"` + TargetBalanceAfter int64 `protobuf:"varint,3,opt,name=target_balance_after,json=targetBalanceAfter,proto3" json:"target_balance_after,omitempty"` + Amount int64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` + RechargeUsdMinor int64 `protobuf:"varint,5,opt,name=recharge_usd_minor,json=rechargeUsdMinor,proto3" json:"recharge_usd_minor,omitempty"` + RechargeCurrencyCode string `protobuf:"bytes,6,opt,name=recharge_currency_code,json=rechargeCurrencyCode,proto3" json:"recharge_currency_code,omitempty"` + RechargePolicyId int64 `protobuf:"varint,7,opt,name=recharge_policy_id,json=rechargePolicyId,proto3" json:"recharge_policy_id,omitempty"` + RechargePolicyVersion string `protobuf:"bytes,8,opt,name=recharge_policy_version,json=rechargePolicyVersion,proto3" json:"recharge_policy_version,omitempty"` + RechargePolicyCoinAmount int64 `protobuf:"varint,9,opt,name=recharge_policy_coin_amount,json=rechargePolicyCoinAmount,proto3" json:"recharge_policy_coin_amount,omitempty"` + RechargePolicyUsdMinorAmount int64 `protobuf:"varint,10,opt,name=recharge_policy_usd_minor_amount,json=rechargePolicyUsdMinorAmount,proto3" json:"recharge_policy_usd_minor_amount,omitempty"` } func (x *TransferCoinFromSellerResponse) Reset() { @@ -806,29 +814,30 @@ func (x *TransferCoinFromSellerResponse) GetRechargePolicyUsdMinorAmount() int64 // Resource 是资源库里可配置、可赠送、可被礼物引用的最小资源。 type Resource struct { - state protoimpl.MessageState `protogen:"open.v1"` - AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - ResourceId int64 `protobuf:"varint,2,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - ResourceCode string `protobuf:"bytes,3,opt,name=resource_code,json=resourceCode,proto3" json:"resource_code,omitempty"` - ResourceType string `protobuf:"bytes,4,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` - Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"` - Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` - Grantable bool `protobuf:"varint,7,opt,name=grantable,proto3" json:"grantable,omitempty"` - GrantStrategy string `protobuf:"bytes,8,opt,name=grant_strategy,json=grantStrategy,proto3" json:"grant_strategy,omitempty"` - WalletAssetType string `protobuf:"bytes,9,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` - WalletAssetAmount int64 `protobuf:"varint,10,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` - UsageScopes []string `protobuf:"bytes,11,rep,name=usage_scopes,json=usageScopes,proto3" json:"usage_scopes,omitempty"` - AssetUrl string `protobuf:"bytes,12,opt,name=asset_url,json=assetUrl,proto3" json:"asset_url,omitempty"` - PreviewUrl string `protobuf:"bytes,13,opt,name=preview_url,json=previewUrl,proto3" json:"preview_url,omitempty"` - AnimationUrl string `protobuf:"bytes,14,opt,name=animation_url,json=animationUrl,proto3" json:"animation_url,omitempty"` - MetadataJson string `protobuf:"bytes,15,opt,name=metadata_json,json=metadataJson,proto3" json:"metadata_json,omitempty"` - SortOrder int32 `protobuf:"varint,16,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` - CreatedByUserId int64 `protobuf:"varint,17,opt,name=created_by_user_id,json=createdByUserId,proto3" json:"created_by_user_id,omitempty"` - UpdatedByUserId int64 `protobuf:"varint,18,opt,name=updated_by_user_id,json=updatedByUserId,proto3" json:"updated_by_user_id,omitempty"` - CreatedAtMs int64 `protobuf:"varint,19,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` - UpdatedAtMs int64 `protobuf:"varint,20,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + ResourceId int64 `protobuf:"varint,2,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + ResourceCode string `protobuf:"bytes,3,opt,name=resource_code,json=resourceCode,proto3" json:"resource_code,omitempty"` + ResourceType string `protobuf:"bytes,4,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` + Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"` + Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` + Grantable bool `protobuf:"varint,7,opt,name=grantable,proto3" json:"grantable,omitempty"` + GrantStrategy string `protobuf:"bytes,8,opt,name=grant_strategy,json=grantStrategy,proto3" json:"grant_strategy,omitempty"` + WalletAssetType string `protobuf:"bytes,9,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` + WalletAssetAmount int64 `protobuf:"varint,10,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` + UsageScopes []string `protobuf:"bytes,11,rep,name=usage_scopes,json=usageScopes,proto3" json:"usage_scopes,omitempty"` + AssetUrl string `protobuf:"bytes,12,opt,name=asset_url,json=assetUrl,proto3" json:"asset_url,omitempty"` + PreviewUrl string `protobuf:"bytes,13,opt,name=preview_url,json=previewUrl,proto3" json:"preview_url,omitempty"` + AnimationUrl string `protobuf:"bytes,14,opt,name=animation_url,json=animationUrl,proto3" json:"animation_url,omitempty"` + MetadataJson string `protobuf:"bytes,15,opt,name=metadata_json,json=metadataJson,proto3" json:"metadata_json,omitempty"` + SortOrder int32 `protobuf:"varint,16,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + CreatedByUserId int64 `protobuf:"varint,17,opt,name=created_by_user_id,json=createdByUserId,proto3" json:"created_by_user_id,omitempty"` + UpdatedByUserId int64 `protobuf:"varint,18,opt,name=updated_by_user_id,json=updatedByUserId,proto3" json:"updated_by_user_id,omitempty"` + CreatedAtMs int64 `protobuf:"varint,19,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,20,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` } func (x *Resource) Reset() { @@ -1002,21 +1011,22 @@ func (x *Resource) GetUpdatedAtMs() int64 { } type ResourceGroupItem struct { - state protoimpl.MessageState `protogen:"open.v1"` - GroupItemId int64 `protobuf:"varint,1,opt,name=group_item_id,json=groupItemId,proto3" json:"group_item_id,omitempty"` - GroupId int64 `protobuf:"varint,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` - ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - Resource *Resource `protobuf:"bytes,4,opt,name=resource,proto3" json:"resource,omitempty"` - Quantity int64 `protobuf:"varint,5,opt,name=quantity,proto3" json:"quantity,omitempty"` - DurationMs int64 `protobuf:"varint,6,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` - SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,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"` - ItemType string `protobuf:"bytes,10,opt,name=item_type,json=itemType,proto3" json:"item_type,omitempty"` - WalletAssetType string `protobuf:"bytes,11,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` - WalletAssetAmount int64 `protobuf:"varint,12,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupItemId int64 `protobuf:"varint,1,opt,name=group_item_id,json=groupItemId,proto3" json:"group_item_id,omitempty"` + GroupId int64 `protobuf:"varint,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` + ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + Resource *Resource `protobuf:"bytes,4,opt,name=resource,proto3" json:"resource,omitempty"` + Quantity int64 `protobuf:"varint,5,opt,name=quantity,proto3" json:"quantity,omitempty"` + DurationMs int64 `protobuf:"varint,6,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` + SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,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"` + ItemType string `protobuf:"bytes,10,opt,name=item_type,json=itemType,proto3" json:"item_type,omitempty"` + WalletAssetType string `protobuf:"bytes,11,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` + WalletAssetAmount int64 `protobuf:"varint,12,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` } func (x *ResourceGroupItem) Reset() { @@ -1134,21 +1144,22 @@ func (x *ResourceGroupItem) GetWalletAssetAmount() int64 { } type ResourceGroup struct { - state protoimpl.MessageState `protogen:"open.v1"` - AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - GroupId int64 `protobuf:"varint,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` - GroupCode string `protobuf:"bytes,3,opt,name=group_code,json=groupCode,proto3" json:"group_code,omitempty"` - Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` - Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` - Items []*ResourceGroupItem `protobuf:"bytes,8,rep,name=items,proto3" json:"items,omitempty"` - CreatedByUserId int64 `protobuf:"varint,9,opt,name=created_by_user_id,json=createdByUserId,proto3" json:"created_by_user_id,omitempty"` - UpdatedByUserId int64 `protobuf:"varint,10,opt,name=updated_by_user_id,json=updatedByUserId,proto3" json:"updated_by_user_id,omitempty"` - CreatedAtMs int64 `protobuf:"varint,11,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` - UpdatedAtMs int64 `protobuf:"varint,12,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + GroupId int64 `protobuf:"varint,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` + GroupCode string `protobuf:"bytes,3,opt,name=group_code,json=groupCode,proto3" json:"group_code,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + Items []*ResourceGroupItem `protobuf:"bytes,8,rep,name=items,proto3" json:"items,omitempty"` + CreatedByUserId int64 `protobuf:"varint,9,opt,name=created_by_user_id,json=createdByUserId,proto3" json:"created_by_user_id,omitempty"` + UpdatedByUserId int64 `protobuf:"varint,10,opt,name=updated_by_user_id,json=updatedByUserId,proto3" json:"updated_by_user_id,omitempty"` + CreatedAtMs int64 `protobuf:"varint,11,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,12,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` } func (x *ResourceGroup) Reset() { @@ -1266,31 +1277,32 @@ func (x *ResourceGroup) GetUpdatedAtMs() int64 { } type GiftConfig struct { - state protoimpl.MessageState `protogen:"open.v1"` - AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - GiftId string `protobuf:"bytes,2,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` - ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - Resource *Resource `protobuf:"bytes,4,opt,name=resource,proto3" json:"resource,omitempty"` - Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` - SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` - PresentationJson string `protobuf:"bytes,8,opt,name=presentation_json,json=presentationJson,proto3" json:"presentation_json,omitempty"` - PriceVersion string `protobuf:"bytes,9,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` - CoinPrice int64 `protobuf:"varint,10,opt,name=coin_price,json=coinPrice,proto3" json:"coin_price,omitempty"` - GiftPointAmount int64 `protobuf:"varint,11,opt,name=gift_point_amount,json=giftPointAmount,proto3" json:"gift_point_amount,omitempty"` - HeatValue int64 `protobuf:"varint,12,opt,name=heat_value,json=heatValue,proto3" json:"heat_value,omitempty"` - CreatedByUserId int64 `protobuf:"varint,13,opt,name=created_by_user_id,json=createdByUserId,proto3" json:"created_by_user_id,omitempty"` - UpdatedByUserId int64 `protobuf:"varint,14,opt,name=updated_by_user_id,json=updatedByUserId,proto3" json:"updated_by_user_id,omitempty"` - CreatedAtMs int64 `protobuf:"varint,15,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` - UpdatedAtMs int64 `protobuf:"varint,16,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` - RegionIds []int64 `protobuf:"varint,17,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` - GiftTypeCode string `protobuf:"bytes,18,opt,name=gift_type_code,json=giftTypeCode,proto3" json:"gift_type_code,omitempty"` - ChargeAssetType string `protobuf:"bytes,19,opt,name=charge_asset_type,json=chargeAssetType,proto3" json:"charge_asset_type,omitempty"` - EffectiveFromMs int64 `protobuf:"varint,20,opt,name=effective_from_ms,json=effectiveFromMs,proto3" json:"effective_from_ms,omitempty"` - EffectiveToMs int64 `protobuf:"varint,21,opt,name=effective_to_ms,json=effectiveToMs,proto3" json:"effective_to_ms,omitempty"` - EffectTypes []string `protobuf:"bytes,22,rep,name=effect_types,json=effectTypes,proto3" json:"effect_types,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + GiftId string `protobuf:"bytes,2,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` + ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + Resource *Resource `protobuf:"bytes,4,opt,name=resource,proto3" json:"resource,omitempty"` + Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + PresentationJson string `protobuf:"bytes,8,opt,name=presentation_json,json=presentationJson,proto3" json:"presentation_json,omitempty"` + PriceVersion string `protobuf:"bytes,9,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` + CoinPrice int64 `protobuf:"varint,10,opt,name=coin_price,json=coinPrice,proto3" json:"coin_price,omitempty"` + GiftPointAmount int64 `protobuf:"varint,11,opt,name=gift_point_amount,json=giftPointAmount,proto3" json:"gift_point_amount,omitempty"` + HeatValue int64 `protobuf:"varint,12,opt,name=heat_value,json=heatValue,proto3" json:"heat_value,omitempty"` + CreatedByUserId int64 `protobuf:"varint,13,opt,name=created_by_user_id,json=createdByUserId,proto3" json:"created_by_user_id,omitempty"` + UpdatedByUserId int64 `protobuf:"varint,14,opt,name=updated_by_user_id,json=updatedByUserId,proto3" json:"updated_by_user_id,omitempty"` + CreatedAtMs int64 `protobuf:"varint,15,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,16,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` + RegionIds []int64 `protobuf:"varint,17,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` + GiftTypeCode string `protobuf:"bytes,18,opt,name=gift_type_code,json=giftTypeCode,proto3" json:"gift_type_code,omitempty"` + ChargeAssetType string `protobuf:"bytes,19,opt,name=charge_asset_type,json=chargeAssetType,proto3" json:"charge_asset_type,omitempty"` + EffectiveFromMs int64 `protobuf:"varint,20,opt,name=effective_from_ms,json=effectiveFromMs,proto3" json:"effective_from_ms,omitempty"` + EffectiveToMs int64 `protobuf:"varint,21,opt,name=effective_to_ms,json=effectiveToMs,proto3" json:"effective_to_ms,omitempty"` + EffectTypes []string `protobuf:"bytes,22,rep,name=effect_types,json=effectTypes,proto3" json:"effect_types,omitempty"` } func (x *GiftConfig) Reset() { @@ -1478,22 +1490,23 @@ func (x *GiftConfig) GetEffectTypes() []string { } type UserResourceEntitlement struct { - state protoimpl.MessageState `protogen:"open.v1"` - AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - EntitlementId string `protobuf:"bytes,2,opt,name=entitlement_id,json=entitlementId,proto3" json:"entitlement_id,omitempty"` - UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` - Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` - Quantity int64 `protobuf:"varint,7,opt,name=quantity,proto3" json:"quantity,omitempty"` - RemainingQuantity int64 `protobuf:"varint,8,opt,name=remaining_quantity,json=remainingQuantity,proto3" json:"remaining_quantity,omitempty"` - EffectiveAtMs int64 `protobuf:"varint,9,opt,name=effective_at_ms,json=effectiveAtMs,proto3" json:"effective_at_ms,omitempty"` - ExpiresAtMs int64 `protobuf:"varint,10,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"` - SourceGrantId string `protobuf:"bytes,11,opt,name=source_grant_id,json=sourceGrantId,proto3" json:"source_grant_id,omitempty"` - CreatedAtMs int64 `protobuf:"varint,12,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` - UpdatedAtMs int64 `protobuf:"varint,13,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + EntitlementId string `protobuf:"bytes,2,opt,name=entitlement_id,json=entitlementId,proto3" json:"entitlement_id,omitempty"` + UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` + Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` + Quantity int64 `protobuf:"varint,7,opt,name=quantity,proto3" json:"quantity,omitempty"` + RemainingQuantity int64 `protobuf:"varint,8,opt,name=remaining_quantity,json=remainingQuantity,proto3" json:"remaining_quantity,omitempty"` + EffectiveAtMs int64 `protobuf:"varint,9,opt,name=effective_at_ms,json=effectiveAtMs,proto3" json:"effective_at_ms,omitempty"` + ExpiresAtMs int64 `protobuf:"varint,10,opt,name=expires_at_ms,json=expiresAtMs,proto3" json:"expires_at_ms,omitempty"` + SourceGrantId string `protobuf:"bytes,11,opt,name=source_grant_id,json=sourceGrantId,proto3" json:"source_grant_id,omitempty"` + CreatedAtMs int64 `protobuf:"varint,12,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,13,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` } func (x *UserResourceEntitlement) Reset() { @@ -1618,19 +1631,20 @@ func (x *UserResourceEntitlement) GetUpdatedAtMs() int64 { } type ResourceGrantItem struct { - state protoimpl.MessageState `protogen:"open.v1"` - GrantItemId int64 `protobuf:"varint,1,opt,name=grant_item_id,json=grantItemId,proto3" json:"grant_item_id,omitempty"` - GrantId string `protobuf:"bytes,2,opt,name=grant_id,json=grantId,proto3" json:"grant_id,omitempty"` - ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - ResourceSnapshotJson string `protobuf:"bytes,4,opt,name=resource_snapshot_json,json=resourceSnapshotJson,proto3" json:"resource_snapshot_json,omitempty"` - Quantity int64 `protobuf:"varint,5,opt,name=quantity,proto3" json:"quantity,omitempty"` - DurationMs int64 `protobuf:"varint,6,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` - ResultType string `protobuf:"bytes,7,opt,name=result_type,json=resultType,proto3" json:"result_type,omitempty"` - WalletTransactionId string `protobuf:"bytes,8,opt,name=wallet_transaction_id,json=walletTransactionId,proto3" json:"wallet_transaction_id,omitempty"` - EntitlementId string `protobuf:"bytes,9,opt,name=entitlement_id,json=entitlementId,proto3" json:"entitlement_id,omitempty"` - CreatedAtMs int64 `protobuf:"varint,10,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GrantItemId int64 `protobuf:"varint,1,opt,name=grant_item_id,json=grantItemId,proto3" json:"grant_item_id,omitempty"` + GrantId string `protobuf:"bytes,2,opt,name=grant_id,json=grantId,proto3" json:"grant_id,omitempty"` + ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + ResourceSnapshotJson string `protobuf:"bytes,4,opt,name=resource_snapshot_json,json=resourceSnapshotJson,proto3" json:"resource_snapshot_json,omitempty"` + Quantity int64 `protobuf:"varint,5,opt,name=quantity,proto3" json:"quantity,omitempty"` + DurationMs int64 `protobuf:"varint,6,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` + ResultType string `protobuf:"bytes,7,opt,name=result_type,json=resultType,proto3" json:"result_type,omitempty"` + WalletTransactionId string `protobuf:"bytes,8,opt,name=wallet_transaction_id,json=walletTransactionId,proto3" json:"wallet_transaction_id,omitempty"` + EntitlementId string `protobuf:"bytes,9,opt,name=entitlement_id,json=entitlementId,proto3" json:"entitlement_id,omitempty"` + CreatedAtMs int64 `protobuf:"varint,10,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` } func (x *ResourceGrantItem) Reset() { @@ -1734,22 +1748,23 @@ func (x *ResourceGrantItem) GetCreatedAtMs() int64 { } type ResourceGrant struct { - state protoimpl.MessageState `protogen:"open.v1"` - AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - GrantId string `protobuf:"bytes,2,opt,name=grant_id,json=grantId,proto3" json:"grant_id,omitempty"` - CommandId string `protobuf:"bytes,3,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` - TargetUserId int64 `protobuf:"varint,4,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` - GrantSource string `protobuf:"bytes,5,opt,name=grant_source,json=grantSource,proto3" json:"grant_source,omitempty"` - GrantSubjectType string `protobuf:"bytes,6,opt,name=grant_subject_type,json=grantSubjectType,proto3" json:"grant_subject_type,omitempty"` - GrantSubjectId string `protobuf:"bytes,7,opt,name=grant_subject_id,json=grantSubjectId,proto3" json:"grant_subject_id,omitempty"` - Status string `protobuf:"bytes,8,opt,name=status,proto3" json:"status,omitempty"` - Reason string `protobuf:"bytes,9,opt,name=reason,proto3" json:"reason,omitempty"` - OperatorUserId int64 `protobuf:"varint,10,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - Items []*ResourceGrantItem `protobuf:"bytes,11,rep,name=items,proto3" json:"items,omitempty"` - CreatedAtMs int64 `protobuf:"varint,12,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` - UpdatedAtMs int64 `protobuf:"varint,13,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + GrantId string `protobuf:"bytes,2,opt,name=grant_id,json=grantId,proto3" json:"grant_id,omitempty"` + CommandId string `protobuf:"bytes,3,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + TargetUserId int64 `protobuf:"varint,4,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + GrantSource string `protobuf:"bytes,5,opt,name=grant_source,json=grantSource,proto3" json:"grant_source,omitempty"` + GrantSubjectType string `protobuf:"bytes,6,opt,name=grant_subject_type,json=grantSubjectType,proto3" json:"grant_subject_type,omitempty"` + GrantSubjectId string `protobuf:"bytes,7,opt,name=grant_subject_id,json=grantSubjectId,proto3" json:"grant_subject_id,omitempty"` + Status string `protobuf:"bytes,8,opt,name=status,proto3" json:"status,omitempty"` + Reason string `protobuf:"bytes,9,opt,name=reason,proto3" json:"reason,omitempty"` + OperatorUserId int64 `protobuf:"varint,10,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` + Items []*ResourceGrantItem `protobuf:"bytes,11,rep,name=items,proto3" json:"items,omitempty"` + CreatedAtMs int64 `protobuf:"varint,12,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + UpdatedAtMs int64 `protobuf:"varint,13,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"` } func (x *ResourceGrant) Reset() { @@ -1874,16 +1889,17 @@ func (x *ResourceGrant) GetUpdatedAtMs() int64 { } type ResourceGroupItemInput struct { - state protoimpl.MessageState `protogen:"open.v1"` - ResourceId int64 `protobuf:"varint,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - Quantity int64 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"` - DurationMs int64 `protobuf:"varint,3,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` - SortOrder int32 `protobuf:"varint,4,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` - ItemType string `protobuf:"bytes,5,opt,name=item_type,json=itemType,proto3" json:"item_type,omitempty"` - WalletAssetType string `protobuf:"bytes,6,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` - WalletAssetAmount int64 `protobuf:"varint,7,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ResourceId int64 `protobuf:"varint,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + Quantity int64 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"` + DurationMs int64 `protobuf:"varint,3,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` + SortOrder int32 `protobuf:"varint,4,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + ItemType string `protobuf:"bytes,5,opt,name=item_type,json=itemType,proto3" json:"item_type,omitempty"` + WalletAssetType string `protobuf:"bytes,6,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` + WalletAssetAmount int64 `protobuf:"varint,7,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` } func (x *ResourceGroupItemInput) Reset() { @@ -1966,17 +1982,18 @@ func (x *ResourceGroupItemInput) GetWalletAssetAmount() int64 { } type ListResourcesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - ResourceType string `protobuf:"bytes,3,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` - Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` - Keyword string `protobuf:"bytes,5,opt,name=keyword,proto3" json:"keyword,omitempty"` - Page int32 `protobuf:"varint,6,opt,name=page,proto3" json:"page,omitempty"` - PageSize int32 `protobuf:"varint,7,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - ActiveOnly bool `protobuf:"varint,8,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + ResourceType string `protobuf:"bytes,3,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` + Keyword string `protobuf:"bytes,5,opt,name=keyword,proto3" json:"keyword,omitempty"` + Page int32 `protobuf:"varint,6,opt,name=page,proto3" json:"page,omitempty"` + PageSize int32 `protobuf:"varint,7,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + ActiveOnly bool `protobuf:"varint,8,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"` } func (x *ListResourcesRequest) Reset() { @@ -2066,11 +2083,12 @@ func (x *ListResourcesRequest) GetActiveOnly() bool { } type ListResourcesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Resources []*Resource `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` - Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Resources []*Resource `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` } func (x *ListResourcesResponse) Reset() { @@ -2118,12 +2136,13 @@ func (x *ListResourcesResponse) GetTotal() int64 { } type GetResourceRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` } func (x *GetResourceRequest) Reset() { @@ -2178,10 +2197,11 @@ func (x *GetResourceRequest) GetResourceId() int64 { } type GetResourceResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Resource *Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Resource *Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` } func (x *GetResourceResponse) Reset() { @@ -2222,26 +2242,27 @@ func (x *GetResourceResponse) GetResource() *Resource { } type CreateResourceRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - ResourceCode string `protobuf:"bytes,3,opt,name=resource_code,json=resourceCode,proto3" json:"resource_code,omitempty"` - ResourceType string `protobuf:"bytes,4,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` - Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"` - Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` - Grantable bool `protobuf:"varint,7,opt,name=grantable,proto3" json:"grantable,omitempty"` - GrantStrategy string `protobuf:"bytes,8,opt,name=grant_strategy,json=grantStrategy,proto3" json:"grant_strategy,omitempty"` - WalletAssetType string `protobuf:"bytes,9,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` - WalletAssetAmount int64 `protobuf:"varint,10,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` - UsageScopes []string `protobuf:"bytes,11,rep,name=usage_scopes,json=usageScopes,proto3" json:"usage_scopes,omitempty"` - AssetUrl string `protobuf:"bytes,12,opt,name=asset_url,json=assetUrl,proto3" json:"asset_url,omitempty"` - PreviewUrl string `protobuf:"bytes,13,opt,name=preview_url,json=previewUrl,proto3" json:"preview_url,omitempty"` - AnimationUrl string `protobuf:"bytes,14,opt,name=animation_url,json=animationUrl,proto3" json:"animation_url,omitempty"` - MetadataJson string `protobuf:"bytes,15,opt,name=metadata_json,json=metadataJson,proto3" json:"metadata_json,omitempty"` - SortOrder int32 `protobuf:"varint,16,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` - OperatorUserId int64 `protobuf:"varint,17,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + ResourceCode string `protobuf:"bytes,3,opt,name=resource_code,json=resourceCode,proto3" json:"resource_code,omitempty"` + ResourceType string `protobuf:"bytes,4,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` + Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"` + Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` + Grantable bool `protobuf:"varint,7,opt,name=grantable,proto3" json:"grantable,omitempty"` + GrantStrategy string `protobuf:"bytes,8,opt,name=grant_strategy,json=grantStrategy,proto3" json:"grant_strategy,omitempty"` + WalletAssetType string `protobuf:"bytes,9,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` + WalletAssetAmount int64 `protobuf:"varint,10,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` + UsageScopes []string `protobuf:"bytes,11,rep,name=usage_scopes,json=usageScopes,proto3" json:"usage_scopes,omitempty"` + AssetUrl string `protobuf:"bytes,12,opt,name=asset_url,json=assetUrl,proto3" json:"asset_url,omitempty"` + PreviewUrl string `protobuf:"bytes,13,opt,name=preview_url,json=previewUrl,proto3" json:"preview_url,omitempty"` + AnimationUrl string `protobuf:"bytes,14,opt,name=animation_url,json=animationUrl,proto3" json:"animation_url,omitempty"` + MetadataJson string `protobuf:"bytes,15,opt,name=metadata_json,json=metadataJson,proto3" json:"metadata_json,omitempty"` + SortOrder int32 `protobuf:"varint,16,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + OperatorUserId int64 `protobuf:"varint,17,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` } func (x *CreateResourceRequest) Reset() { @@ -2394,27 +2415,28 @@ func (x *CreateResourceRequest) GetOperatorUserId() int64 { } type UpdateResourceRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - ResourceCode string `protobuf:"bytes,4,opt,name=resource_code,json=resourceCode,proto3" json:"resource_code,omitempty"` - ResourceType string `protobuf:"bytes,5,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` - Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` - Status string `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` - Grantable bool `protobuf:"varint,8,opt,name=grantable,proto3" json:"grantable,omitempty"` - GrantStrategy string `protobuf:"bytes,9,opt,name=grant_strategy,json=grantStrategy,proto3" json:"grant_strategy,omitempty"` - WalletAssetType string `protobuf:"bytes,10,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` - WalletAssetAmount int64 `protobuf:"varint,11,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` - UsageScopes []string `protobuf:"bytes,12,rep,name=usage_scopes,json=usageScopes,proto3" json:"usage_scopes,omitempty"` - AssetUrl string `protobuf:"bytes,13,opt,name=asset_url,json=assetUrl,proto3" json:"asset_url,omitempty"` - PreviewUrl string `protobuf:"bytes,14,opt,name=preview_url,json=previewUrl,proto3" json:"preview_url,omitempty"` - AnimationUrl string `protobuf:"bytes,15,opt,name=animation_url,json=animationUrl,proto3" json:"animation_url,omitempty"` - MetadataJson string `protobuf:"bytes,16,opt,name=metadata_json,json=metadataJson,proto3" json:"metadata_json,omitempty"` - SortOrder int32 `protobuf:"varint,17,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` - OperatorUserId int64 `protobuf:"varint,18,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + ResourceCode string `protobuf:"bytes,4,opt,name=resource_code,json=resourceCode,proto3" json:"resource_code,omitempty"` + ResourceType string `protobuf:"bytes,5,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + Status string `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` + Grantable bool `protobuf:"varint,8,opt,name=grantable,proto3" json:"grantable,omitempty"` + GrantStrategy string `protobuf:"bytes,9,opt,name=grant_strategy,json=grantStrategy,proto3" json:"grant_strategy,omitempty"` + WalletAssetType string `protobuf:"bytes,10,opt,name=wallet_asset_type,json=walletAssetType,proto3" json:"wallet_asset_type,omitempty"` + WalletAssetAmount int64 `protobuf:"varint,11,opt,name=wallet_asset_amount,json=walletAssetAmount,proto3" json:"wallet_asset_amount,omitempty"` + UsageScopes []string `protobuf:"bytes,12,rep,name=usage_scopes,json=usageScopes,proto3" json:"usage_scopes,omitempty"` + AssetUrl string `protobuf:"bytes,13,opt,name=asset_url,json=assetUrl,proto3" json:"asset_url,omitempty"` + PreviewUrl string `protobuf:"bytes,14,opt,name=preview_url,json=previewUrl,proto3" json:"preview_url,omitempty"` + AnimationUrl string `protobuf:"bytes,15,opt,name=animation_url,json=animationUrl,proto3" json:"animation_url,omitempty"` + MetadataJson string `protobuf:"bytes,16,opt,name=metadata_json,json=metadataJson,proto3" json:"metadata_json,omitempty"` + SortOrder int32 `protobuf:"varint,17,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + OperatorUserId int64 `protobuf:"varint,18,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` } func (x *UpdateResourceRequest) Reset() { @@ -2574,14 +2596,15 @@ func (x *UpdateResourceRequest) GetOperatorUserId() int64 { } type SetResourceStatusRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` - OperatorUserId int64 `protobuf:"varint,5,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + ResourceId int64 `protobuf:"varint,3,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` + OperatorUserId int64 `protobuf:"varint,5,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` } func (x *SetResourceStatusRequest) Reset() { @@ -2650,10 +2673,11 @@ func (x *SetResourceStatusRequest) GetOperatorUserId() int64 { } type ResourceResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Resource *Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Resource *Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` } func (x *ResourceResponse) Reset() { @@ -2694,16 +2718,17 @@ func (x *ResourceResponse) GetResource() *Resource { } type ListResourceGroupsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - Keyword string `protobuf:"bytes,4,opt,name=keyword,proto3" json:"keyword,omitempty"` - Page int32 `protobuf:"varint,5,opt,name=page,proto3" json:"page,omitempty"` - PageSize int32 `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - ActiveOnly bool `protobuf:"varint,7,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + Keyword string `protobuf:"bytes,4,opt,name=keyword,proto3" json:"keyword,omitempty"` + Page int32 `protobuf:"varint,5,opt,name=page,proto3" json:"page,omitempty"` + PageSize int32 `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + ActiveOnly bool `protobuf:"varint,7,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"` } func (x *ListResourceGroupsRequest) Reset() { @@ -2786,11 +2811,12 @@ func (x *ListResourceGroupsRequest) GetActiveOnly() bool { } type ListResourceGroupsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Groups []*ResourceGroup `protobuf:"bytes,1,rep,name=groups,proto3" json:"groups,omitempty"` - Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Groups []*ResourceGroup `protobuf:"bytes,1,rep,name=groups,proto3" json:"groups,omitempty"` + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` } func (x *ListResourceGroupsResponse) Reset() { @@ -2838,12 +2864,13 @@ func (x *ListResourceGroupsResponse) GetTotal() int64 { } type GetResourceGroupRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - GroupId int64 `protobuf:"varint,3,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + GroupId int64 `protobuf:"varint,3,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` } func (x *GetResourceGroupRequest) Reset() { @@ -2898,10 +2925,11 @@ func (x *GetResourceGroupRequest) GetGroupId() int64 { } type GetResourceGroupResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Group *ResourceGroup `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Group *ResourceGroup `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` } func (x *GetResourceGroupResponse) Reset() { @@ -2942,7 +2970,10 @@ func (x *GetResourceGroupResponse) GetGroup() *ResourceGroup { } type CreateResourceGroupRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` + 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"` GroupCode string `protobuf:"bytes,3,opt,name=group_code,json=groupCode,proto3" json:"group_code,omitempty"` @@ -2952,8 +2983,6 @@ type CreateResourceGroupRequest struct { SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` Items []*ResourceGroupItemInput `protobuf:"bytes,8,rep,name=items,proto3" json:"items,omitempty"` OperatorUserId int64 `protobuf:"varint,9,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache } func (x *CreateResourceGroupRequest) Reset() { @@ -3050,7 +3079,10 @@ func (x *CreateResourceGroupRequest) GetOperatorUserId() int64 { } type UpdateResourceGroupRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` + 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"` GroupId int64 `protobuf:"varint,3,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` @@ -3061,8 +3093,6 @@ type UpdateResourceGroupRequest struct { SortOrder int32 `protobuf:"varint,8,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` Items []*ResourceGroupItemInput `protobuf:"bytes,9,rep,name=items,proto3" json:"items,omitempty"` OperatorUserId int64 `protobuf:"varint,10,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache } func (x *UpdateResourceGroupRequest) Reset() { @@ -3166,14 +3196,15 @@ func (x *UpdateResourceGroupRequest) GetOperatorUserId() int64 { } type SetResourceGroupStatusRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - GroupId int64 `protobuf:"varint,3,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` - Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` - OperatorUserId int64 `protobuf:"varint,5,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + GroupId int64 `protobuf:"varint,3,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` + OperatorUserId int64 `protobuf:"varint,5,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` } func (x *SetResourceGroupStatusRequest) Reset() { @@ -3242,10 +3273,11 @@ func (x *SetResourceGroupStatusRequest) GetOperatorUserId() int64 { } type ResourceGroupResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Group *ResourceGroup `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Group *ResourceGroup `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` } func (x *ResourceGroupResponse) Reset() { @@ -3286,18 +3318,19 @@ func (x *ResourceGroupResponse) GetGroup() *ResourceGroup { } type ListGiftConfigsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - Keyword string `protobuf:"bytes,4,opt,name=keyword,proto3" json:"keyword,omitempty"` - Page int32 `protobuf:"varint,5,opt,name=page,proto3" json:"page,omitempty"` - PageSize int32 `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - ActiveOnly bool `protobuf:"varint,7,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"` - RegionId int64 `protobuf:"varint,8,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` - FilterRegion bool `protobuf:"varint,9,opt,name=filter_region,json=filterRegion,proto3" json:"filter_region,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + Keyword string `protobuf:"bytes,4,opt,name=keyword,proto3" json:"keyword,omitempty"` + Page int32 `protobuf:"varint,5,opt,name=page,proto3" json:"page,omitempty"` + PageSize int32 `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + ActiveOnly bool `protobuf:"varint,7,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"` + RegionId int64 `protobuf:"varint,8,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + FilterRegion bool `protobuf:"varint,9,opt,name=filter_region,json=filterRegion,proto3" json:"filter_region,omitempty"` } func (x *ListGiftConfigsRequest) Reset() { @@ -3394,11 +3427,12 @@ func (x *ListGiftConfigsRequest) GetFilterRegion() bool { } type ListGiftConfigsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Gifts []*GiftConfig `protobuf:"bytes,1,rep,name=gifts,proto3" json:"gifts,omitempty"` - Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Gifts []*GiftConfig `protobuf:"bytes,1,rep,name=gifts,proto3" json:"gifts,omitempty"` + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` } func (x *ListGiftConfigsResponse) Reset() { @@ -3446,29 +3480,30 @@ func (x *ListGiftConfigsResponse) GetTotal() int64 { } type CreateGiftConfigRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - GiftId string `protobuf:"bytes,3,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` - ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` - SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` - PresentationJson string `protobuf:"bytes,8,opt,name=presentation_json,json=presentationJson,proto3" json:"presentation_json,omitempty"` - PriceVersion string `protobuf:"bytes,9,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` - CoinPrice int64 `protobuf:"varint,10,opt,name=coin_price,json=coinPrice,proto3" json:"coin_price,omitempty"` - GiftPointAmount int64 `protobuf:"varint,11,opt,name=gift_point_amount,json=giftPointAmount,proto3" json:"gift_point_amount,omitempty"` - HeatValue int64 `protobuf:"varint,12,opt,name=heat_value,json=heatValue,proto3" json:"heat_value,omitempty"` - EffectiveAtMs int64 `protobuf:"varint,13,opt,name=effective_at_ms,json=effectiveAtMs,proto3" json:"effective_at_ms,omitempty"` - OperatorUserId int64 `protobuf:"varint,14,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - RegionIds []int64 `protobuf:"varint,15,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` - GiftTypeCode string `protobuf:"bytes,16,opt,name=gift_type_code,json=giftTypeCode,proto3" json:"gift_type_code,omitempty"` - ChargeAssetType string `protobuf:"bytes,17,opt,name=charge_asset_type,json=chargeAssetType,proto3" json:"charge_asset_type,omitempty"` - EffectiveFromMs int64 `protobuf:"varint,18,opt,name=effective_from_ms,json=effectiveFromMs,proto3" json:"effective_from_ms,omitempty"` - EffectiveToMs int64 `protobuf:"varint,19,opt,name=effective_to_ms,json=effectiveToMs,proto3" json:"effective_to_ms,omitempty"` - EffectTypes []string `protobuf:"bytes,20,rep,name=effect_types,json=effectTypes,proto3" json:"effect_types,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + GiftId string `protobuf:"bytes,3,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` + ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + PresentationJson string `protobuf:"bytes,8,opt,name=presentation_json,json=presentationJson,proto3" json:"presentation_json,omitempty"` + PriceVersion string `protobuf:"bytes,9,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` + CoinPrice int64 `protobuf:"varint,10,opt,name=coin_price,json=coinPrice,proto3" json:"coin_price,omitempty"` + GiftPointAmount int64 `protobuf:"varint,11,opt,name=gift_point_amount,json=giftPointAmount,proto3" json:"gift_point_amount,omitempty"` + HeatValue int64 `protobuf:"varint,12,opt,name=heat_value,json=heatValue,proto3" json:"heat_value,omitempty"` + EffectiveAtMs int64 `protobuf:"varint,13,opt,name=effective_at_ms,json=effectiveAtMs,proto3" json:"effective_at_ms,omitempty"` + OperatorUserId int64 `protobuf:"varint,14,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` + RegionIds []int64 `protobuf:"varint,15,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` + GiftTypeCode string `protobuf:"bytes,16,opt,name=gift_type_code,json=giftTypeCode,proto3" json:"gift_type_code,omitempty"` + ChargeAssetType string `protobuf:"bytes,17,opt,name=charge_asset_type,json=chargeAssetType,proto3" json:"charge_asset_type,omitempty"` + EffectiveFromMs int64 `protobuf:"varint,18,opt,name=effective_from_ms,json=effectiveFromMs,proto3" json:"effective_from_ms,omitempty"` + EffectiveToMs int64 `protobuf:"varint,19,opt,name=effective_to_ms,json=effectiveToMs,proto3" json:"effective_to_ms,omitempty"` + EffectTypes []string `protobuf:"bytes,20,rep,name=effect_types,json=effectTypes,proto3" json:"effect_types,omitempty"` } func (x *CreateGiftConfigRequest) Reset() { @@ -3642,29 +3677,30 @@ func (x *CreateGiftConfigRequest) GetEffectTypes() []string { } type UpdateGiftConfigRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - GiftId string `protobuf:"bytes,3,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` - ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` - SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` - PresentationJson string `protobuf:"bytes,8,opt,name=presentation_json,json=presentationJson,proto3" json:"presentation_json,omitempty"` - PriceVersion string `protobuf:"bytes,9,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` - CoinPrice int64 `protobuf:"varint,10,opt,name=coin_price,json=coinPrice,proto3" json:"coin_price,omitempty"` - GiftPointAmount int64 `protobuf:"varint,11,opt,name=gift_point_amount,json=giftPointAmount,proto3" json:"gift_point_amount,omitempty"` - HeatValue int64 `protobuf:"varint,12,opt,name=heat_value,json=heatValue,proto3" json:"heat_value,omitempty"` - EffectiveAtMs int64 `protobuf:"varint,13,opt,name=effective_at_ms,json=effectiveAtMs,proto3" json:"effective_at_ms,omitempty"` - OperatorUserId int64 `protobuf:"varint,14,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - RegionIds []int64 `protobuf:"varint,15,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` - GiftTypeCode string `protobuf:"bytes,16,opt,name=gift_type_code,json=giftTypeCode,proto3" json:"gift_type_code,omitempty"` - ChargeAssetType string `protobuf:"bytes,17,opt,name=charge_asset_type,json=chargeAssetType,proto3" json:"charge_asset_type,omitempty"` - EffectiveFromMs int64 `protobuf:"varint,18,opt,name=effective_from_ms,json=effectiveFromMs,proto3" json:"effective_from_ms,omitempty"` - EffectiveToMs int64 `protobuf:"varint,19,opt,name=effective_to_ms,json=effectiveToMs,proto3" json:"effective_to_ms,omitempty"` - EffectTypes []string `protobuf:"bytes,20,rep,name=effect_types,json=effectTypes,proto3" json:"effect_types,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + GiftId string `protobuf:"bytes,3,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` + ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + SortOrder int32 `protobuf:"varint,7,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"` + PresentationJson string `protobuf:"bytes,8,opt,name=presentation_json,json=presentationJson,proto3" json:"presentation_json,omitempty"` + PriceVersion string `protobuf:"bytes,9,opt,name=price_version,json=priceVersion,proto3" json:"price_version,omitempty"` + CoinPrice int64 `protobuf:"varint,10,opt,name=coin_price,json=coinPrice,proto3" json:"coin_price,omitempty"` + GiftPointAmount int64 `protobuf:"varint,11,opt,name=gift_point_amount,json=giftPointAmount,proto3" json:"gift_point_amount,omitempty"` + HeatValue int64 `protobuf:"varint,12,opt,name=heat_value,json=heatValue,proto3" json:"heat_value,omitempty"` + EffectiveAtMs int64 `protobuf:"varint,13,opt,name=effective_at_ms,json=effectiveAtMs,proto3" json:"effective_at_ms,omitempty"` + OperatorUserId int64 `protobuf:"varint,14,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` + RegionIds []int64 `protobuf:"varint,15,rep,packed,name=region_ids,json=regionIds,proto3" json:"region_ids,omitempty"` + GiftTypeCode string `protobuf:"bytes,16,opt,name=gift_type_code,json=giftTypeCode,proto3" json:"gift_type_code,omitempty"` + ChargeAssetType string `protobuf:"bytes,17,opt,name=charge_asset_type,json=chargeAssetType,proto3" json:"charge_asset_type,omitempty"` + EffectiveFromMs int64 `protobuf:"varint,18,opt,name=effective_from_ms,json=effectiveFromMs,proto3" json:"effective_from_ms,omitempty"` + EffectiveToMs int64 `protobuf:"varint,19,opt,name=effective_to_ms,json=effectiveToMs,proto3" json:"effective_to_ms,omitempty"` + EffectTypes []string `protobuf:"bytes,20,rep,name=effect_types,json=effectTypes,proto3" json:"effect_types,omitempty"` } func (x *UpdateGiftConfigRequest) Reset() { @@ -3838,14 +3874,15 @@ func (x *UpdateGiftConfigRequest) GetEffectTypes() []string { } type SetGiftConfigStatusRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - GiftId string `protobuf:"bytes,3,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` - Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` - OperatorUserId int64 `protobuf:"varint,5,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + GiftId string `protobuf:"bytes,3,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` + OperatorUserId int64 `protobuf:"varint,5,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` } func (x *SetGiftConfigStatusRequest) Reset() { @@ -3914,10 +3951,11 @@ func (x *SetGiftConfigStatusRequest) GetOperatorUserId() int64 { } type GiftConfigResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Gift *GiftConfig `protobuf:"bytes,1,opt,name=gift,proto3" json:"gift,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Gift *GiftConfig `protobuf:"bytes,1,opt,name=gift,proto3" json:"gift,omitempty"` } func (x *GiftConfigResponse) Reset() { @@ -3958,18 +3996,19 @@ func (x *GiftConfigResponse) GetGift() *GiftConfig { } type GrantResourceRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` - AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` - ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - Quantity int64 `protobuf:"varint,5,opt,name=quantity,proto3" json:"quantity,omitempty"` - DurationMs int64 `protobuf:"varint,6,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` - Reason string `protobuf:"bytes,7,opt,name=reason,proto3" json:"reason,omitempty"` - OperatorUserId int64 `protobuf:"varint,8,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - GrantSource string `protobuf:"bytes,9,opt,name=grant_source,json=grantSource,proto3" json:"grant_source,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + Quantity int64 `protobuf:"varint,5,opt,name=quantity,proto3" json:"quantity,omitempty"` + DurationMs int64 `protobuf:"varint,6,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` + Reason string `protobuf:"bytes,7,opt,name=reason,proto3" json:"reason,omitempty"` + OperatorUserId int64 `protobuf:"varint,8,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` + GrantSource string `protobuf:"bytes,9,opt,name=grant_source,json=grantSource,proto3" json:"grant_source,omitempty"` } func (x *GrantResourceRequest) Reset() { @@ -4066,16 +4105,17 @@ func (x *GrantResourceRequest) GetGrantSource() string { } type GrantResourceGroupRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` - AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` - GroupId int64 `protobuf:"varint,4,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` - Reason string `protobuf:"bytes,5,opt,name=reason,proto3" json:"reason,omitempty"` - OperatorUserId int64 `protobuf:"varint,6,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` - GrantSource string `protobuf:"bytes,7,opt,name=grant_source,json=grantSource,proto3" json:"grant_source,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + GroupId int64 `protobuf:"varint,4,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` + Reason string `protobuf:"bytes,5,opt,name=reason,proto3" json:"reason,omitempty"` + OperatorUserId int64 `protobuf:"varint,6,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"` + GrantSource string `protobuf:"bytes,7,opt,name=grant_source,json=grantSource,proto3" json:"grant_source,omitempty"` } func (x *GrantResourceGroupRequest) Reset() { @@ -4158,10 +4198,11 @@ func (x *GrantResourceGroupRequest) GetGrantSource() string { } type ResourceGrantResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Grant *ResourceGrant `protobuf:"bytes,1,opt,name=grant,proto3" json:"grant,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Grant *ResourceGrant `protobuf:"bytes,1,opt,name=grant,proto3" json:"grant,omitempty"` } func (x *ResourceGrantResponse) Reset() { @@ -4202,14 +4243,15 @@ func (x *ResourceGrantResponse) GetGrant() *ResourceGrant { } type ListUserResourcesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - ResourceType string `protobuf:"bytes,4,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` - ActiveOnly bool `protobuf:"varint,5,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ResourceType string `protobuf:"bytes,4,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` + ActiveOnly bool `protobuf:"varint,5,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"` } func (x *ListUserResourcesRequest) Reset() { @@ -4278,10 +4320,11 @@ func (x *ListUserResourcesRequest) GetActiveOnly() bool { } type ListUserResourcesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Resources []*UserResourceEntitlement `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Resources []*UserResourceEntitlement `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` } func (x *ListUserResourcesResponse) Reset() { @@ -4322,14 +4365,15 @@ func (x *ListUserResourcesResponse) GetResources() []*UserResourceEntitlement { } type EquipUserResourceRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - EntitlementId string `protobuf:"bytes,5,opt,name=entitlement_id,json=entitlementId,proto3" json:"entitlement_id,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ResourceId int64 `protobuf:"varint,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + EntitlementId string `protobuf:"bytes,5,opt,name=entitlement_id,json=entitlementId,proto3" json:"entitlement_id,omitempty"` } func (x *EquipUserResourceRequest) Reset() { @@ -4398,10 +4442,11 @@ func (x *EquipUserResourceRequest) GetEntitlementId() string { } type EquipUserResourceResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Resource *UserResourceEntitlement `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Resource *UserResourceEntitlement `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` } func (x *EquipUserResourceResponse) Reset() { @@ -4442,15 +4487,16 @@ func (x *EquipUserResourceResponse) GetResource() *UserResourceEntitlement { } type ListResourceGrantsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` - Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` - Page int32 `protobuf:"varint,5,opt,name=page,proto3" json:"page,omitempty"` - PageSize int32 `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"` + Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` + Page int32 `protobuf:"varint,5,opt,name=page,proto3" json:"page,omitempty"` + PageSize int32 `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` } func (x *ListResourceGrantsRequest) Reset() { @@ -4526,11 +4572,12 @@ func (x *ListResourceGrantsRequest) GetPageSize() int32 { } type ListResourceGrantsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Grants []*ResourceGrant `protobuf:"bytes,1,rep,name=grants,proto3" json:"grants,omitempty"` - Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Grants []*ResourceGrant `protobuf:"bytes,1,rep,name=grants,proto3" json:"grants,omitempty"` + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` } func (x *ListResourceGrantsResponse) Reset() { @@ -4578,27 +4625,28 @@ func (x *ListResourceGrantsResponse) GetTotal() int64 { } type RechargeBill struct { - state protoimpl.MessageState `protogen:"open.v1"` - AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` - TransactionId string `protobuf:"bytes,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - CommandId string `protobuf:"bytes,3,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` - RechargeType string `protobuf:"bytes,4,opt,name=recharge_type,json=rechargeType,proto3" json:"recharge_type,omitempty"` - Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - ExternalRef string `protobuf:"bytes,6,opt,name=external_ref,json=externalRef,proto3" json:"external_ref,omitempty"` - UserId int64 `protobuf:"varint,7,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - SellerUserId int64 `protobuf:"varint,8,opt,name=seller_user_id,json=sellerUserId,proto3" json:"seller_user_id,omitempty"` - SellerRegionId int64 `protobuf:"varint,9,opt,name=seller_region_id,json=sellerRegionId,proto3" json:"seller_region_id,omitempty"` - TargetRegionId int64 `protobuf:"varint,10,opt,name=target_region_id,json=targetRegionId,proto3" json:"target_region_id,omitempty"` - PolicyId int64 `protobuf:"varint,11,opt,name=policy_id,json=policyId,proto3" json:"policy_id,omitempty"` - PolicyVersion string `protobuf:"bytes,12,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` - CurrencyCode string `protobuf:"bytes,13,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` - CoinAmount int64 `protobuf:"varint,14,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` - UsdMinorAmount int64 `protobuf:"varint,15,opt,name=usd_minor_amount,json=usdMinorAmount,proto3" json:"usd_minor_amount,omitempty"` - ExchangeCoinAmount int64 `protobuf:"varint,16,opt,name=exchange_coin_amount,json=exchangeCoinAmount,proto3" json:"exchange_coin_amount,omitempty"` - ExchangeUsdMinorAmount int64 `protobuf:"varint,17,opt,name=exchange_usd_minor_amount,json=exchangeUsdMinorAmount,proto3" json:"exchange_usd_minor_amount,omitempty"` - CreatedAtMs int64 `protobuf:"varint,18,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + 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"` + TransactionId string `protobuf:"bytes,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + CommandId string `protobuf:"bytes,3,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + RechargeType string `protobuf:"bytes,4,opt,name=recharge_type,json=rechargeType,proto3" json:"recharge_type,omitempty"` + Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` + ExternalRef string `protobuf:"bytes,6,opt,name=external_ref,json=externalRef,proto3" json:"external_ref,omitempty"` + UserId int64 `protobuf:"varint,7,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + SellerUserId int64 `protobuf:"varint,8,opt,name=seller_user_id,json=sellerUserId,proto3" json:"seller_user_id,omitempty"` + SellerRegionId int64 `protobuf:"varint,9,opt,name=seller_region_id,json=sellerRegionId,proto3" json:"seller_region_id,omitempty"` + TargetRegionId int64 `protobuf:"varint,10,opt,name=target_region_id,json=targetRegionId,proto3" json:"target_region_id,omitempty"` + PolicyId int64 `protobuf:"varint,11,opt,name=policy_id,json=policyId,proto3" json:"policy_id,omitempty"` + PolicyVersion string `protobuf:"bytes,12,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` + CurrencyCode string `protobuf:"bytes,13,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` + CoinAmount int64 `protobuf:"varint,14,opt,name=coin_amount,json=coinAmount,proto3" json:"coin_amount,omitempty"` + UsdMinorAmount int64 `protobuf:"varint,15,opt,name=usd_minor_amount,json=usdMinorAmount,proto3" json:"usd_minor_amount,omitempty"` + ExchangeCoinAmount int64 `protobuf:"varint,16,opt,name=exchange_coin_amount,json=exchangeCoinAmount,proto3" json:"exchange_coin_amount,omitempty"` + ExchangeUsdMinorAmount int64 `protobuf:"varint,17,opt,name=exchange_usd_minor_amount,json=exchangeUsdMinorAmount,proto3" json:"exchange_usd_minor_amount,omitempty"` + CreatedAtMs int64 `protobuf:"varint,18,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` } func (x *RechargeBill) Reset() { @@ -4758,21 +4806,22 @@ func (x *RechargeBill) GetCreatedAtMs() int64 { } type ListRechargeBillsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - 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"` - UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - SellerUserId int64 `protobuf:"varint,4,opt,name=seller_user_id,json=sellerUserId,proto3" json:"seller_user_id,omitempty"` - RegionId int64 `protobuf:"varint,5,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` - RechargeType string `protobuf:"bytes,6,opt,name=recharge_type,json=rechargeType,proto3" json:"recharge_type,omitempty"` - Status string `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` - Keyword string `protobuf:"bytes,8,opt,name=keyword,proto3" json:"keyword,omitempty"` - StartAtMs int64 `protobuf:"varint,9,opt,name=start_at_ms,json=startAtMs,proto3" json:"start_at_ms,omitempty"` - EndAtMs int64 `protobuf:"varint,10,opt,name=end_at_ms,json=endAtMs,proto3" json:"end_at_ms,omitempty"` - Page int32 `protobuf:"varint,11,opt,name=page,proto3" json:"page,omitempty"` - PageSize int32 `protobuf:"varint,12,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - unknownFields protoimpl.UnknownFields + 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"` + UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + SellerUserId int64 `protobuf:"varint,4,opt,name=seller_user_id,json=sellerUserId,proto3" json:"seller_user_id,omitempty"` + RegionId int64 `protobuf:"varint,5,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + RechargeType string `protobuf:"bytes,6,opt,name=recharge_type,json=rechargeType,proto3" json:"recharge_type,omitempty"` + Status string `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` + Keyword string `protobuf:"bytes,8,opt,name=keyword,proto3" json:"keyword,omitempty"` + StartAtMs int64 `protobuf:"varint,9,opt,name=start_at_ms,json=startAtMs,proto3" json:"start_at_ms,omitempty"` + EndAtMs int64 `protobuf:"varint,10,opt,name=end_at_ms,json=endAtMs,proto3" json:"end_at_ms,omitempty"` + Page int32 `protobuf:"varint,11,opt,name=page,proto3" json:"page,omitempty"` + PageSize int32 `protobuf:"varint,12,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` } func (x *ListRechargeBillsRequest) Reset() { @@ -4890,11 +4939,12 @@ func (x *ListRechargeBillsRequest) GetPageSize() int32 { } type ListRechargeBillsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Bills []*RechargeBill `protobuf:"bytes,1,rep,name=bills,proto3" json:"bills,omitempty"` - Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Bills []*RechargeBill `protobuf:"bytes,1,rep,name=bills,proto3" json:"bills,omitempty"` + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` } func (x *ListRechargeBillsResponse) Reset() { @@ -4943,575 +4993,1095 @@ func (x *ListRechargeBillsResponse) GetTotal() int64 { var File_proto_wallet_v1_wallet_proto protoreflect.FileDescriptor -const file_proto_wallet_v1_wallet_proto_rawDesc = "" + - "\n" + - "\x1cproto/wallet/v1/wallet.proto\x12\x0fhyapp.wallet.v1\"\xab\x02\n" + - "\x10DebitGiftRequest\x12\x1d\n" + - "\n" + - "command_id\x18\x01 \x01(\tR\tcommandId\x12\x17\n" + - "\aroom_id\x18\x02 \x01(\tR\x06roomId\x12$\n" + - "\x0esender_user_id\x18\x03 \x01(\x03R\fsenderUserId\x12$\n" + - "\x0etarget_user_id\x18\x04 \x01(\x03R\ftargetUserId\x12\x17\n" + - "\agift_id\x18\x05 \x01(\tR\x06giftId\x12\x1d\n" + - "\n" + - "gift_count\x18\x06 \x01(\x05R\tgiftCount\x12#\n" + - "\rprice_version\x18\a \x01(\tR\fpriceVersion\x12\x19\n" + - "\bapp_code\x18\b \x01(\tR\aappCode\x12\x1b\n" + - "\tregion_id\x18\t \x01(\x03R\bregionId\"\xeb\x02\n" + - "\x11DebitGiftResponse\x12,\n" + - "\x12billing_receipt_id\x18\x01 \x01(\tR\x10billingReceiptId\x12%\n" + - "\x0etransaction_id\x18\x02 \x01(\tR\rtransactionId\x12\x1d\n" + - "\n" + - "coin_spent\x18\x03 \x01(\x03R\tcoinSpent\x12(\n" + - "\x10gift_point_added\x18\x04 \x01(\x03R\x0egiftPointAdded\x12\x1d\n" + - "\n" + - "heat_value\x18\x05 \x01(\x03R\theatValue\x12#\n" + - "\rprice_version\x18\x06 \x01(\tR\fpriceVersion\x12#\n" + - "\rbalance_after\x18\a \x01(\x03R\fbalanceAfter\x12*\n" + - "\x11charge_asset_type\x18\b \x01(\tR\x0fchargeAssetType\x12#\n" + - "\rcharge_amount\x18\t \x01(\x03R\fchargeAmount\"\xb2\x01\n" + - "\fAssetBalance\x12\x1d\n" + - "\n" + - "asset_type\x18\x01 \x01(\tR\tassetType\x12)\n" + - "\x10available_amount\x18\x02 \x01(\x03R\x0favailableAmount\x12#\n" + - "\rfrozen_amount\x18\x03 \x01(\x03R\ffrozenAmount\x12\x18\n" + - "\aversion\x18\x04 \x01(\x03R\aversion\x12\x19\n" + - "\bapp_code\x18\x05 \x01(\tR\aappCode\"\x88\x01\n" + - "\x12GetBalancesRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x17\n" + - "\auser_id\x18\x02 \x01(\x03R\x06userId\x12\x1f\n" + - "\vasset_types\x18\x03 \x03(\tR\n" + - "assetTypes\x12\x19\n" + - "\bapp_code\x18\x04 \x01(\tR\aappCode\"P\n" + - "\x13GetBalancesResponse\x129\n" + - "\bbalances\x18\x01 \x03(\v2\x1d.hyapp.wallet.v1.AssetBalanceR\bbalances\"\x95\x02\n" + - "\x17AdminCreditAssetRequest\x12\x1d\n" + - "\n" + - "command_id\x18\x01 \x01(\tR\tcommandId\x12$\n" + - "\x0etarget_user_id\x18\x02 \x01(\x03R\ftargetUserId\x12\x1d\n" + - "\n" + - "asset_type\x18\x03 \x01(\tR\tassetType\x12\x16\n" + - "\x06amount\x18\x04 \x01(\x03R\x06amount\x12(\n" + - "\x10operator_user_id\x18\x05 \x01(\x03R\x0eoperatorUserId\x12\x16\n" + - "\x06reason\x18\x06 \x01(\tR\x06reason\x12!\n" + - "\fevidence_ref\x18\a \x01(\tR\vevidenceRef\x12\x19\n" + - "\bapp_code\x18\b \x01(\tR\aappCode\"z\n" + - "\x18AdminCreditAssetResponse\x12%\n" + - "\x0etransaction_id\x18\x01 \x01(\tR\rtransactionId\x127\n" + - "\abalance\x18\x02 \x01(\v2\x1d.hyapp.wallet.v1.AssetBalanceR\abalance\"\xa9\x02\n" + - "\x1dTransferCoinFromSellerRequest\x12\x1d\n" + - "\n" + - "command_id\x18\x01 \x01(\tR\tcommandId\x12$\n" + - "\x0eseller_user_id\x18\x02 \x01(\x03R\fsellerUserId\x12$\n" + - "\x0etarget_user_id\x18\x03 \x01(\x03R\ftargetUserId\x12\x16\n" + - "\x06amount\x18\x04 \x01(\x03R\x06amount\x12\x16\n" + - "\x06reason\x18\x05 \x01(\tR\x06reason\x12\x19\n" + - "\bapp_code\x18\x06 \x01(\tR\aappCode\x12(\n" + - "\x10seller_region_id\x18\a \x01(\x03R\x0esellerRegionId\x12(\n" + - "\x10target_region_id\x18\b \x01(\x03R\x0etargetRegionId\"\x94\x04\n" + - "\x1eTransferCoinFromSellerResponse\x12%\n" + - "\x0etransaction_id\x18\x01 \x01(\tR\rtransactionId\x120\n" + - "\x14seller_balance_after\x18\x02 \x01(\x03R\x12sellerBalanceAfter\x120\n" + - "\x14target_balance_after\x18\x03 \x01(\x03R\x12targetBalanceAfter\x12\x16\n" + - "\x06amount\x18\x04 \x01(\x03R\x06amount\x12,\n" + - "\x12recharge_usd_minor\x18\x05 \x01(\x03R\x10rechargeUsdMinor\x124\n" + - "\x16recharge_currency_code\x18\x06 \x01(\tR\x14rechargeCurrencyCode\x12,\n" + - "\x12recharge_policy_id\x18\a \x01(\x03R\x10rechargePolicyId\x126\n" + - "\x17recharge_policy_version\x18\b \x01(\tR\x15rechargePolicyVersion\x12=\n" + - "\x1brecharge_policy_coin_amount\x18\t \x01(\x03R\x18rechargePolicyCoinAmount\x12F\n" + - " recharge_policy_usd_minor_amount\x18\n" + - " \x01(\x03R\x1crechargePolicyUsdMinorAmount\"\xc9\x05\n" + - "\bResource\x12\x19\n" + - "\bapp_code\x18\x01 \x01(\tR\aappCode\x12\x1f\n" + - "\vresource_id\x18\x02 \x01(\x03R\n" + - "resourceId\x12#\n" + - "\rresource_code\x18\x03 \x01(\tR\fresourceCode\x12#\n" + - "\rresource_type\x18\x04 \x01(\tR\fresourceType\x12\x12\n" + - "\x04name\x18\x05 \x01(\tR\x04name\x12\x16\n" + - "\x06status\x18\x06 \x01(\tR\x06status\x12\x1c\n" + - "\tgrantable\x18\a \x01(\bR\tgrantable\x12%\n" + - "\x0egrant_strategy\x18\b \x01(\tR\rgrantStrategy\x12*\n" + - "\x11wallet_asset_type\x18\t \x01(\tR\x0fwalletAssetType\x12.\n" + - "\x13wallet_asset_amount\x18\n" + - " \x01(\x03R\x11walletAssetAmount\x12!\n" + - "\fusage_scopes\x18\v \x03(\tR\vusageScopes\x12\x1b\n" + - "\tasset_url\x18\f \x01(\tR\bassetUrl\x12\x1f\n" + - "\vpreview_url\x18\r \x01(\tR\n" + - "previewUrl\x12#\n" + - "\ranimation_url\x18\x0e \x01(\tR\fanimationUrl\x12#\n" + - "\rmetadata_json\x18\x0f \x01(\tR\fmetadataJson\x12\x1d\n" + - "\n" + - "sort_order\x18\x10 \x01(\x05R\tsortOrder\x12+\n" + - "\x12created_by_user_id\x18\x11 \x01(\x03R\x0fcreatedByUserId\x12+\n" + - "\x12updated_by_user_id\x18\x12 \x01(\x03R\x0fupdatedByUserId\x12\"\n" + - "\rcreated_at_ms\x18\x13 \x01(\x03R\vcreatedAtMs\x12\"\n" + - "\rupdated_at_ms\x18\x14 \x01(\x03R\vupdatedAtMs\"\xc7\x03\n" + - "\x11ResourceGroupItem\x12\"\n" + - "\rgroup_item_id\x18\x01 \x01(\x03R\vgroupItemId\x12\x19\n" + - "\bgroup_id\x18\x02 \x01(\x03R\agroupId\x12\x1f\n" + - "\vresource_id\x18\x03 \x01(\x03R\n" + - "resourceId\x125\n" + - "\bresource\x18\x04 \x01(\v2\x19.hyapp.wallet.v1.ResourceR\bresource\x12\x1a\n" + - "\bquantity\x18\x05 \x01(\x03R\bquantity\x12\x1f\n" + - "\vduration_ms\x18\x06 \x01(\x03R\n" + - "durationMs\x12\x1d\n" + - "\n" + - "sort_order\x18\a \x01(\x05R\tsortOrder\x12\"\n" + - "\rcreated_at_ms\x18\b \x01(\x03R\vcreatedAtMs\x12\"\n" + - "\rupdated_at_ms\x18\t \x01(\x03R\vupdatedAtMs\x12\x1b\n" + - "\titem_type\x18\n" + - " \x01(\tR\bitemType\x12*\n" + - "\x11wallet_asset_type\x18\v \x01(\tR\x0fwalletAssetType\x12.\n" + - "\x13wallet_asset_amount\x18\f \x01(\x03R\x11walletAssetAmount\"\xad\x03\n" + - "\rResourceGroup\x12\x19\n" + - "\bapp_code\x18\x01 \x01(\tR\aappCode\x12\x19\n" + - "\bgroup_id\x18\x02 \x01(\x03R\agroupId\x12\x1d\n" + - "\n" + - "group_code\x18\x03 \x01(\tR\tgroupCode\x12\x12\n" + - "\x04name\x18\x04 \x01(\tR\x04name\x12\x16\n" + - "\x06status\x18\x05 \x01(\tR\x06status\x12 \n" + - "\vdescription\x18\x06 \x01(\tR\vdescription\x12\x1d\n" + - "\n" + - "sort_order\x18\a \x01(\x05R\tsortOrder\x128\n" + - "\x05items\x18\b \x03(\v2\".hyapp.wallet.v1.ResourceGroupItemR\x05items\x12+\n" + - "\x12created_by_user_id\x18\t \x01(\x03R\x0fcreatedByUserId\x12+\n" + - "\x12updated_by_user_id\x18\n" + - " \x01(\x03R\x0fupdatedByUserId\x12\"\n" + - "\rcreated_at_ms\x18\v \x01(\x03R\vcreatedAtMs\x12\"\n" + - "\rupdated_at_ms\x18\f \x01(\x03R\vupdatedAtMs\"\xa9\x06\n" + - "\n" + - "GiftConfig\x12\x19\n" + - "\bapp_code\x18\x01 \x01(\tR\aappCode\x12\x17\n" + - "\agift_id\x18\x02 \x01(\tR\x06giftId\x12\x1f\n" + - "\vresource_id\x18\x03 \x01(\x03R\n" + - "resourceId\x125\n" + - "\bresource\x18\x04 \x01(\v2\x19.hyapp.wallet.v1.ResourceR\bresource\x12\x16\n" + - "\x06status\x18\x05 \x01(\tR\x06status\x12\x12\n" + - "\x04name\x18\x06 \x01(\tR\x04name\x12\x1d\n" + - "\n" + - "sort_order\x18\a \x01(\x05R\tsortOrder\x12+\n" + - "\x11presentation_json\x18\b \x01(\tR\x10presentationJson\x12#\n" + - "\rprice_version\x18\t \x01(\tR\fpriceVersion\x12\x1d\n" + - "\n" + - "coin_price\x18\n" + - " \x01(\x03R\tcoinPrice\x12*\n" + - "\x11gift_point_amount\x18\v \x01(\x03R\x0fgiftPointAmount\x12\x1d\n" + - "\n" + - "heat_value\x18\f \x01(\x03R\theatValue\x12+\n" + - "\x12created_by_user_id\x18\r \x01(\x03R\x0fcreatedByUserId\x12+\n" + - "\x12updated_by_user_id\x18\x0e \x01(\x03R\x0fupdatedByUserId\x12\"\n" + - "\rcreated_at_ms\x18\x0f \x01(\x03R\vcreatedAtMs\x12\"\n" + - "\rupdated_at_ms\x18\x10 \x01(\x03R\vupdatedAtMs\x12\x1d\n" + - "\n" + - "region_ids\x18\x11 \x03(\x03R\tregionIds\x12$\n" + - "\x0egift_type_code\x18\x12 \x01(\tR\fgiftTypeCode\x12*\n" + - "\x11charge_asset_type\x18\x13 \x01(\tR\x0fchargeAssetType\x12*\n" + - "\x11effective_from_ms\x18\x14 \x01(\x03R\x0feffectiveFromMs\x12&\n" + - "\x0feffective_to_ms\x18\x15 \x01(\x03R\reffectiveToMs\x12!\n" + - "\feffect_types\x18\x16 \x03(\tR\veffectTypes\"\xeb\x03\n" + - "\x17UserResourceEntitlement\x12\x19\n" + - "\bapp_code\x18\x01 \x01(\tR\aappCode\x12%\n" + - "\x0eentitlement_id\x18\x02 \x01(\tR\rentitlementId\x12\x17\n" + - "\auser_id\x18\x03 \x01(\x03R\x06userId\x12\x1f\n" + - "\vresource_id\x18\x04 \x01(\x03R\n" + - "resourceId\x125\n" + - "\bresource\x18\x05 \x01(\v2\x19.hyapp.wallet.v1.ResourceR\bresource\x12\x16\n" + - "\x06status\x18\x06 \x01(\tR\x06status\x12\x1a\n" + - "\bquantity\x18\a \x01(\x03R\bquantity\x12-\n" + - "\x12remaining_quantity\x18\b \x01(\x03R\x11remainingQuantity\x12&\n" + - "\x0feffective_at_ms\x18\t \x01(\x03R\reffectiveAtMs\x12\"\n" + - "\rexpires_at_ms\x18\n" + - " \x01(\x03R\vexpiresAtMs\x12&\n" + - "\x0fsource_grant_id\x18\v \x01(\tR\rsourceGrantId\x12\"\n" + - "\rcreated_at_ms\x18\f \x01(\x03R\vcreatedAtMs\x12\"\n" + - "\rupdated_at_ms\x18\r \x01(\x03R\vupdatedAtMs\"\x86\x03\n" + - "\x11ResourceGrantItem\x12\"\n" + - "\rgrant_item_id\x18\x01 \x01(\x03R\vgrantItemId\x12\x19\n" + - "\bgrant_id\x18\x02 \x01(\tR\agrantId\x12\x1f\n" + - "\vresource_id\x18\x03 \x01(\x03R\n" + - "resourceId\x124\n" + - "\x16resource_snapshot_json\x18\x04 \x01(\tR\x14resourceSnapshotJson\x12\x1a\n" + - "\bquantity\x18\x05 \x01(\x03R\bquantity\x12\x1f\n" + - "\vduration_ms\x18\x06 \x01(\x03R\n" + - "durationMs\x12\x1f\n" + - "\vresult_type\x18\a \x01(\tR\n" + - "resultType\x122\n" + - "\x15wallet_transaction_id\x18\b \x01(\tR\x13walletTransactionId\x12%\n" + - "\x0eentitlement_id\x18\t \x01(\tR\rentitlementId\x12\"\n" + - "\rcreated_at_ms\x18\n" + - " \x01(\x03R\vcreatedAtMs\"\xe1\x03\n" + - "\rResourceGrant\x12\x19\n" + - "\bapp_code\x18\x01 \x01(\tR\aappCode\x12\x19\n" + - "\bgrant_id\x18\x02 \x01(\tR\agrantId\x12\x1d\n" + - "\n" + - "command_id\x18\x03 \x01(\tR\tcommandId\x12$\n" + - "\x0etarget_user_id\x18\x04 \x01(\x03R\ftargetUserId\x12!\n" + - "\fgrant_source\x18\x05 \x01(\tR\vgrantSource\x12,\n" + - "\x12grant_subject_type\x18\x06 \x01(\tR\x10grantSubjectType\x12(\n" + - "\x10grant_subject_id\x18\a \x01(\tR\x0egrantSubjectId\x12\x16\n" + - "\x06status\x18\b \x01(\tR\x06status\x12\x16\n" + - "\x06reason\x18\t \x01(\tR\x06reason\x12(\n" + - "\x10operator_user_id\x18\n" + - " \x01(\x03R\x0eoperatorUserId\x128\n" + - "\x05items\x18\v \x03(\v2\".hyapp.wallet.v1.ResourceGrantItemR\x05items\x12\"\n" + - "\rcreated_at_ms\x18\f \x01(\x03R\vcreatedAtMs\x12\"\n" + - "\rupdated_at_ms\x18\r \x01(\x03R\vupdatedAtMs\"\x8e\x02\n" + - "\x16ResourceGroupItemInput\x12\x1f\n" + - "\vresource_id\x18\x01 \x01(\x03R\n" + - "resourceId\x12\x1a\n" + - "\bquantity\x18\x02 \x01(\x03R\bquantity\x12\x1f\n" + - "\vduration_ms\x18\x03 \x01(\x03R\n" + - "durationMs\x12\x1d\n" + - "\n" + - "sort_order\x18\x04 \x01(\x05R\tsortOrder\x12\x1b\n" + - "\titem_type\x18\x05 \x01(\tR\bitemType\x12*\n" + - "\x11wallet_asset_type\x18\x06 \x01(\tR\x0fwalletAssetType\x12.\n" + - "\x13wallet_asset_amount\x18\a \x01(\x03R\x11walletAssetAmount\"\xf9\x01\n" + - "\x14ListResourcesRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12#\n" + - "\rresource_type\x18\x03 \x01(\tR\fresourceType\x12\x16\n" + - "\x06status\x18\x04 \x01(\tR\x06status\x12\x18\n" + - "\akeyword\x18\x05 \x01(\tR\akeyword\x12\x12\n" + - "\x04page\x18\x06 \x01(\x05R\x04page\x12\x1b\n" + - "\tpage_size\x18\a \x01(\x05R\bpageSize\x12\x1f\n" + - "\vactive_only\x18\b \x01(\bR\n" + - "activeOnly\"f\n" + - "\x15ListResourcesResponse\x127\n" + - "\tresources\x18\x01 \x03(\v2\x19.hyapp.wallet.v1.ResourceR\tresources\x12\x14\n" + - "\x05total\x18\x02 \x01(\x03R\x05total\"o\n" + - "\x12GetResourceRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x1f\n" + - "\vresource_id\x18\x03 \x01(\x03R\n" + - "resourceId\"L\n" + - "\x13GetResourceResponse\x125\n" + - "\bresource\x18\x01 \x01(\v2\x19.hyapp.wallet.v1.ResourceR\bresource\"\xdc\x04\n" + - "\x15CreateResourceRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12#\n" + - "\rresource_code\x18\x03 \x01(\tR\fresourceCode\x12#\n" + - "\rresource_type\x18\x04 \x01(\tR\fresourceType\x12\x12\n" + - "\x04name\x18\x05 \x01(\tR\x04name\x12\x16\n" + - "\x06status\x18\x06 \x01(\tR\x06status\x12\x1c\n" + - "\tgrantable\x18\a \x01(\bR\tgrantable\x12%\n" + - "\x0egrant_strategy\x18\b \x01(\tR\rgrantStrategy\x12*\n" + - "\x11wallet_asset_type\x18\t \x01(\tR\x0fwalletAssetType\x12.\n" + - "\x13wallet_asset_amount\x18\n" + - " \x01(\x03R\x11walletAssetAmount\x12!\n" + - "\fusage_scopes\x18\v \x03(\tR\vusageScopes\x12\x1b\n" + - "\tasset_url\x18\f \x01(\tR\bassetUrl\x12\x1f\n" + - "\vpreview_url\x18\r \x01(\tR\n" + - "previewUrl\x12#\n" + - "\ranimation_url\x18\x0e \x01(\tR\fanimationUrl\x12#\n" + - "\rmetadata_json\x18\x0f \x01(\tR\fmetadataJson\x12\x1d\n" + - "\n" + - "sort_order\x18\x10 \x01(\x05R\tsortOrder\x12(\n" + - "\x10operator_user_id\x18\x11 \x01(\x03R\x0eoperatorUserId\"\xfd\x04\n" + - "\x15UpdateResourceRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x1f\n" + - "\vresource_id\x18\x03 \x01(\x03R\n" + - "resourceId\x12#\n" + - "\rresource_code\x18\x04 \x01(\tR\fresourceCode\x12#\n" + - "\rresource_type\x18\x05 \x01(\tR\fresourceType\x12\x12\n" + - "\x04name\x18\x06 \x01(\tR\x04name\x12\x16\n" + - "\x06status\x18\a \x01(\tR\x06status\x12\x1c\n" + - "\tgrantable\x18\b \x01(\bR\tgrantable\x12%\n" + - "\x0egrant_strategy\x18\t \x01(\tR\rgrantStrategy\x12*\n" + - "\x11wallet_asset_type\x18\n" + - " \x01(\tR\x0fwalletAssetType\x12.\n" + - "\x13wallet_asset_amount\x18\v \x01(\x03R\x11walletAssetAmount\x12!\n" + - "\fusage_scopes\x18\f \x03(\tR\vusageScopes\x12\x1b\n" + - "\tasset_url\x18\r \x01(\tR\bassetUrl\x12\x1f\n" + - "\vpreview_url\x18\x0e \x01(\tR\n" + - "previewUrl\x12#\n" + - "\ranimation_url\x18\x0f \x01(\tR\fanimationUrl\x12#\n" + - "\rmetadata_json\x18\x10 \x01(\tR\fmetadataJson\x12\x1d\n" + - "\n" + - "sort_order\x18\x11 \x01(\x05R\tsortOrder\x12(\n" + - "\x10operator_user_id\x18\x12 \x01(\x03R\x0eoperatorUserId\"\xb7\x01\n" + - "\x18SetResourceStatusRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x1f\n" + - "\vresource_id\x18\x03 \x01(\x03R\n" + - "resourceId\x12\x16\n" + - "\x06status\x18\x04 \x01(\tR\x06status\x12(\n" + - "\x10operator_user_id\x18\x05 \x01(\x03R\x0eoperatorUserId\"I\n" + - "\x10ResourceResponse\x125\n" + - "\bresource\x18\x01 \x01(\v2\x19.hyapp.wallet.v1.ResourceR\bresource\"\xd9\x01\n" + - "\x19ListResourceGroupsRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x16\n" + - "\x06status\x18\x03 \x01(\tR\x06status\x12\x18\n" + - "\akeyword\x18\x04 \x01(\tR\akeyword\x12\x12\n" + - "\x04page\x18\x05 \x01(\x05R\x04page\x12\x1b\n" + - "\tpage_size\x18\x06 \x01(\x05R\bpageSize\x12\x1f\n" + - "\vactive_only\x18\a \x01(\bR\n" + - "activeOnly\"j\n" + - "\x1aListResourceGroupsResponse\x126\n" + - "\x06groups\x18\x01 \x03(\v2\x1e.hyapp.wallet.v1.ResourceGroupR\x06groups\x12\x14\n" + - "\x05total\x18\x02 \x01(\x03R\x05total\"n\n" + - "\x17GetResourceGroupRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x19\n" + - "\bgroup_id\x18\x03 \x01(\x03R\agroupId\"P\n" + - "\x18GetResourceGroupResponse\x124\n" + - "\x05group\x18\x01 \x01(\v2\x1e.hyapp.wallet.v1.ResourceGroupR\x05group\"\xcb\x02\n" + - "\x1aCreateResourceGroupRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x1d\n" + - "\n" + - "group_code\x18\x03 \x01(\tR\tgroupCode\x12\x12\n" + - "\x04name\x18\x04 \x01(\tR\x04name\x12\x16\n" + - "\x06status\x18\x05 \x01(\tR\x06status\x12 \n" + - "\vdescription\x18\x06 \x01(\tR\vdescription\x12\x1d\n" + - "\n" + - "sort_order\x18\a \x01(\x05R\tsortOrder\x12=\n" + - "\x05items\x18\b \x03(\v2'.hyapp.wallet.v1.ResourceGroupItemInputR\x05items\x12(\n" + - "\x10operator_user_id\x18\t \x01(\x03R\x0eoperatorUserId\"\xe6\x02\n" + - "\x1aUpdateResourceGroupRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x19\n" + - "\bgroup_id\x18\x03 \x01(\x03R\agroupId\x12\x1d\n" + - "\n" + - "group_code\x18\x04 \x01(\tR\tgroupCode\x12\x12\n" + - "\x04name\x18\x05 \x01(\tR\x04name\x12\x16\n" + - "\x06status\x18\x06 \x01(\tR\x06status\x12 \n" + - "\vdescription\x18\a \x01(\tR\vdescription\x12\x1d\n" + - "\n" + - "sort_order\x18\b \x01(\x05R\tsortOrder\x12=\n" + - "\x05items\x18\t \x03(\v2'.hyapp.wallet.v1.ResourceGroupItemInputR\x05items\x12(\n" + - "\x10operator_user_id\x18\n" + - " \x01(\x03R\x0eoperatorUserId\"\xb6\x01\n" + - "\x1dSetResourceGroupStatusRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x19\n" + - "\bgroup_id\x18\x03 \x01(\x03R\agroupId\x12\x16\n" + - "\x06status\x18\x04 \x01(\tR\x06status\x12(\n" + - "\x10operator_user_id\x18\x05 \x01(\x03R\x0eoperatorUserId\"M\n" + - "\x15ResourceGroupResponse\x124\n" + - "\x05group\x18\x01 \x01(\v2\x1e.hyapp.wallet.v1.ResourceGroupR\x05group\"\x98\x02\n" + - "\x16ListGiftConfigsRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x16\n" + - "\x06status\x18\x03 \x01(\tR\x06status\x12\x18\n" + - "\akeyword\x18\x04 \x01(\tR\akeyword\x12\x12\n" + - "\x04page\x18\x05 \x01(\x05R\x04page\x12\x1b\n" + - "\tpage_size\x18\x06 \x01(\x05R\bpageSize\x12\x1f\n" + - "\vactive_only\x18\a \x01(\bR\n" + - "activeOnly\x12\x1b\n" + - "\tregion_id\x18\b \x01(\x03R\bregionId\x12#\n" + - "\rfilter_region\x18\t \x01(\bR\ffilterRegion\"b\n" + - "\x17ListGiftConfigsResponse\x121\n" + - "\x05gifts\x18\x01 \x03(\v2\x1b.hyapp.wallet.v1.GiftConfigR\x05gifts\x12\x14\n" + - "\x05total\x18\x02 \x01(\x03R\x05total\"\xce\x05\n" + - "\x17CreateGiftConfigRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x17\n" + - "\agift_id\x18\x03 \x01(\tR\x06giftId\x12\x1f\n" + - "\vresource_id\x18\x04 \x01(\x03R\n" + - "resourceId\x12\x16\n" + - "\x06status\x18\x05 \x01(\tR\x06status\x12\x12\n" + - "\x04name\x18\x06 \x01(\tR\x04name\x12\x1d\n" + - "\n" + - "sort_order\x18\a \x01(\x05R\tsortOrder\x12+\n" + - "\x11presentation_json\x18\b \x01(\tR\x10presentationJson\x12#\n" + - "\rprice_version\x18\t \x01(\tR\fpriceVersion\x12\x1d\n" + - "\n" + - "coin_price\x18\n" + - " \x01(\x03R\tcoinPrice\x12*\n" + - "\x11gift_point_amount\x18\v \x01(\x03R\x0fgiftPointAmount\x12\x1d\n" + - "\n" + - "heat_value\x18\f \x01(\x03R\theatValue\x12&\n" + - "\x0feffective_at_ms\x18\r \x01(\x03R\reffectiveAtMs\x12(\n" + - "\x10operator_user_id\x18\x0e \x01(\x03R\x0eoperatorUserId\x12\x1d\n" + - "\n" + - "region_ids\x18\x0f \x03(\x03R\tregionIds\x12$\n" + - "\x0egift_type_code\x18\x10 \x01(\tR\fgiftTypeCode\x12*\n" + - "\x11charge_asset_type\x18\x11 \x01(\tR\x0fchargeAssetType\x12*\n" + - "\x11effective_from_ms\x18\x12 \x01(\x03R\x0feffectiveFromMs\x12&\n" + - "\x0feffective_to_ms\x18\x13 \x01(\x03R\reffectiveToMs\x12!\n" + - "\feffect_types\x18\x14 \x03(\tR\veffectTypes\"\xce\x05\n" + - "\x17UpdateGiftConfigRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x17\n" + - "\agift_id\x18\x03 \x01(\tR\x06giftId\x12\x1f\n" + - "\vresource_id\x18\x04 \x01(\x03R\n" + - "resourceId\x12\x16\n" + - "\x06status\x18\x05 \x01(\tR\x06status\x12\x12\n" + - "\x04name\x18\x06 \x01(\tR\x04name\x12\x1d\n" + - "\n" + - "sort_order\x18\a \x01(\x05R\tsortOrder\x12+\n" + - "\x11presentation_json\x18\b \x01(\tR\x10presentationJson\x12#\n" + - "\rprice_version\x18\t \x01(\tR\fpriceVersion\x12\x1d\n" + - "\n" + - "coin_price\x18\n" + - " \x01(\x03R\tcoinPrice\x12*\n" + - "\x11gift_point_amount\x18\v \x01(\x03R\x0fgiftPointAmount\x12\x1d\n" + - "\n" + - "heat_value\x18\f \x01(\x03R\theatValue\x12&\n" + - "\x0feffective_at_ms\x18\r \x01(\x03R\reffectiveAtMs\x12(\n" + - "\x10operator_user_id\x18\x0e \x01(\x03R\x0eoperatorUserId\x12\x1d\n" + - "\n" + - "region_ids\x18\x0f \x03(\x03R\tregionIds\x12$\n" + - "\x0egift_type_code\x18\x10 \x01(\tR\fgiftTypeCode\x12*\n" + - "\x11charge_asset_type\x18\x11 \x01(\tR\x0fchargeAssetType\x12*\n" + - "\x11effective_from_ms\x18\x12 \x01(\x03R\x0feffectiveFromMs\x12&\n" + - "\x0feffective_to_ms\x18\x13 \x01(\x03R\reffectiveToMs\x12!\n" + - "\feffect_types\x18\x14 \x03(\tR\veffectTypes\"\xb1\x01\n" + - "\x1aSetGiftConfigStatusRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x17\n" + - "\agift_id\x18\x03 \x01(\tR\x06giftId\x12\x16\n" + - "\x06status\x18\x04 \x01(\tR\x06status\x12(\n" + - "\x10operator_user_id\x18\x05 \x01(\x03R\x0eoperatorUserId\"E\n" + - "\x12GiftConfigResponse\x12/\n" + - "\x04gift\x18\x01 \x01(\v2\x1b.hyapp.wallet.v1.GiftConfigR\x04gift\"\xb9\x02\n" + - "\x14GrantResourceRequest\x12\x1d\n" + - "\n" + - "command_id\x18\x01 \x01(\tR\tcommandId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12$\n" + - "\x0etarget_user_id\x18\x03 \x01(\x03R\ftargetUserId\x12\x1f\n" + - "\vresource_id\x18\x04 \x01(\x03R\n" + - "resourceId\x12\x1a\n" + - "\bquantity\x18\x05 \x01(\x03R\bquantity\x12\x1f\n" + - "\vduration_ms\x18\x06 \x01(\x03R\n" + - "durationMs\x12\x16\n" + - "\x06reason\x18\a \x01(\tR\x06reason\x12(\n" + - "\x10operator_user_id\x18\b \x01(\x03R\x0eoperatorUserId\x12!\n" + - "\fgrant_source\x18\t \x01(\tR\vgrantSource\"\xfb\x01\n" + - "\x19GrantResourceGroupRequest\x12\x1d\n" + - "\n" + - "command_id\x18\x01 \x01(\tR\tcommandId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12$\n" + - "\x0etarget_user_id\x18\x03 \x01(\x03R\ftargetUserId\x12\x19\n" + - "\bgroup_id\x18\x04 \x01(\x03R\agroupId\x12\x16\n" + - "\x06reason\x18\x05 \x01(\tR\x06reason\x12(\n" + - "\x10operator_user_id\x18\x06 \x01(\x03R\x0eoperatorUserId\x12!\n" + - "\fgrant_source\x18\a \x01(\tR\vgrantSource\"M\n" + - "\x15ResourceGrantResponse\x124\n" + - "\x05grant\x18\x01 \x01(\v2\x1e.hyapp.wallet.v1.ResourceGrantR\x05grant\"\xb3\x01\n" + - "\x18ListUserResourcesRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x17\n" + - "\auser_id\x18\x03 \x01(\x03R\x06userId\x12#\n" + - "\rresource_type\x18\x04 \x01(\tR\fresourceType\x12\x1f\n" + - "\vactive_only\x18\x05 \x01(\bR\n" + - "activeOnly\"c\n" + - "\x19ListUserResourcesResponse\x12F\n" + - "\tresources\x18\x01 \x03(\v2(.hyapp.wallet.v1.UserResourceEntitlementR\tresources\"\xb5\x01\n" + - "\x18EquipUserResourceRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x17\n" + - "\auser_id\x18\x03 \x01(\x03R\x06userId\x12\x1f\n" + - "\vresource_id\x18\x04 \x01(\x03R\n" + - "resourceId\x12%\n" + - "\x0eentitlement_id\x18\x05 \x01(\tR\rentitlementId\"a\n" + - "\x19EquipUserResourceResponse\x12D\n" + - "\bresource\x18\x01 \x01(\v2(.hyapp.wallet.v1.UserResourceEntitlementR\bresource\"\xc4\x01\n" + - "\x19ListResourceGrantsRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12$\n" + - "\x0etarget_user_id\x18\x03 \x01(\x03R\ftargetUserId\x12\x16\n" + - "\x06status\x18\x04 \x01(\tR\x06status\x12\x12\n" + - "\x04page\x18\x05 \x01(\x05R\x04page\x12\x1b\n" + - "\tpage_size\x18\x06 \x01(\x05R\bpageSize\"j\n" + - "\x1aListResourceGrantsResponse\x126\n" + - "\x06grants\x18\x01 \x03(\v2\x1e.hyapp.wallet.v1.ResourceGrantR\x06grants\x12\x14\n" + - "\x05total\x18\x02 \x01(\x03R\x05total\"\xa7\x05\n" + - "\fRechargeBill\x12\x19\n" + - "\bapp_code\x18\x01 \x01(\tR\aappCode\x12%\n" + - "\x0etransaction_id\x18\x02 \x01(\tR\rtransactionId\x12\x1d\n" + - "\n" + - "command_id\x18\x03 \x01(\tR\tcommandId\x12#\n" + - "\rrecharge_type\x18\x04 \x01(\tR\frechargeType\x12\x16\n" + - "\x06status\x18\x05 \x01(\tR\x06status\x12!\n" + - "\fexternal_ref\x18\x06 \x01(\tR\vexternalRef\x12\x17\n" + - "\auser_id\x18\a \x01(\x03R\x06userId\x12$\n" + - "\x0eseller_user_id\x18\b \x01(\x03R\fsellerUserId\x12(\n" + - "\x10seller_region_id\x18\t \x01(\x03R\x0esellerRegionId\x12(\n" + - "\x10target_region_id\x18\n" + - " \x01(\x03R\x0etargetRegionId\x12\x1b\n" + - "\tpolicy_id\x18\v \x01(\x03R\bpolicyId\x12%\n" + - "\x0epolicy_version\x18\f \x01(\tR\rpolicyVersion\x12#\n" + - "\rcurrency_code\x18\r \x01(\tR\fcurrencyCode\x12\x1f\n" + - "\vcoin_amount\x18\x0e \x01(\x03R\n" + - "coinAmount\x12(\n" + - "\x10usd_minor_amount\x18\x0f \x01(\x03R\x0eusdMinorAmount\x120\n" + - "\x14exchange_coin_amount\x18\x10 \x01(\x03R\x12exchangeCoinAmount\x129\n" + - "\x19exchange_usd_minor_amount\x18\x11 \x01(\x03R\x16exchangeUsdMinorAmount\x12\"\n" + - "\rcreated_at_ms\x18\x12 \x01(\x03R\vcreatedAtMs\"\xf4\x02\n" + - "\x18ListRechargeBillsRequest\x12\x1d\n" + - "\n" + - "request_id\x18\x01 \x01(\tR\trequestId\x12\x19\n" + - "\bapp_code\x18\x02 \x01(\tR\aappCode\x12\x17\n" + - "\auser_id\x18\x03 \x01(\x03R\x06userId\x12$\n" + - "\x0eseller_user_id\x18\x04 \x01(\x03R\fsellerUserId\x12\x1b\n" + - "\tregion_id\x18\x05 \x01(\x03R\bregionId\x12#\n" + - "\rrecharge_type\x18\x06 \x01(\tR\frechargeType\x12\x16\n" + - "\x06status\x18\a \x01(\tR\x06status\x12\x18\n" + - "\akeyword\x18\b \x01(\tR\akeyword\x12\x1e\n" + - "\vstart_at_ms\x18\t \x01(\x03R\tstartAtMs\x12\x1a\n" + - "\tend_at_ms\x18\n" + - " \x01(\x03R\aendAtMs\x12\x12\n" + - "\x04page\x18\v \x01(\x05R\x04page\x12\x1b\n" + - "\tpage_size\x18\f \x01(\x05R\bpageSize\"f\n" + - "\x19ListRechargeBillsResponse\x123\n" + - "\x05bills\x18\x01 \x03(\v2\x1d.hyapp.wallet.v1.RechargeBillR\x05bills\x12\x14\n" + - "\x05total\x18\x02 \x01(\x03R\x05total2\xac\x13\n" + - "\rWalletService\x12R\n" + - "\tDebitGift\x12!.hyapp.wallet.v1.DebitGiftRequest\x1a\".hyapp.wallet.v1.DebitGiftResponse\x12X\n" + - "\vGetBalances\x12#.hyapp.wallet.v1.GetBalancesRequest\x1a$.hyapp.wallet.v1.GetBalancesResponse\x12g\n" + - "\x10AdminCreditAsset\x12(.hyapp.wallet.v1.AdminCreditAssetRequest\x1a).hyapp.wallet.v1.AdminCreditAssetResponse\x12y\n" + - "\x16TransferCoinFromSeller\x12..hyapp.wallet.v1.TransferCoinFromSellerRequest\x1a/.hyapp.wallet.v1.TransferCoinFromSellerResponse\x12^\n" + - "\rListResources\x12%.hyapp.wallet.v1.ListResourcesRequest\x1a&.hyapp.wallet.v1.ListResourcesResponse\x12X\n" + - "\vGetResource\x12#.hyapp.wallet.v1.GetResourceRequest\x1a$.hyapp.wallet.v1.GetResourceResponse\x12[\n" + - "\x0eCreateResource\x12&.hyapp.wallet.v1.CreateResourceRequest\x1a!.hyapp.wallet.v1.ResourceResponse\x12[\n" + - "\x0eUpdateResource\x12&.hyapp.wallet.v1.UpdateResourceRequest\x1a!.hyapp.wallet.v1.ResourceResponse\x12a\n" + - "\x11SetResourceStatus\x12).hyapp.wallet.v1.SetResourceStatusRequest\x1a!.hyapp.wallet.v1.ResourceResponse\x12m\n" + - "\x12ListResourceGroups\x12*.hyapp.wallet.v1.ListResourceGroupsRequest\x1a+.hyapp.wallet.v1.ListResourceGroupsResponse\x12g\n" + - "\x10GetResourceGroup\x12(.hyapp.wallet.v1.GetResourceGroupRequest\x1a).hyapp.wallet.v1.GetResourceGroupResponse\x12j\n" + - "\x13CreateResourceGroup\x12+.hyapp.wallet.v1.CreateResourceGroupRequest\x1a&.hyapp.wallet.v1.ResourceGroupResponse\x12j\n" + - "\x13UpdateResourceGroup\x12+.hyapp.wallet.v1.UpdateResourceGroupRequest\x1a&.hyapp.wallet.v1.ResourceGroupResponse\x12p\n" + - "\x16SetResourceGroupStatus\x12..hyapp.wallet.v1.SetResourceGroupStatusRequest\x1a&.hyapp.wallet.v1.ResourceGroupResponse\x12d\n" + - "\x0fListGiftConfigs\x12'.hyapp.wallet.v1.ListGiftConfigsRequest\x1a(.hyapp.wallet.v1.ListGiftConfigsResponse\x12a\n" + - "\x10CreateGiftConfig\x12(.hyapp.wallet.v1.CreateGiftConfigRequest\x1a#.hyapp.wallet.v1.GiftConfigResponse\x12a\n" + - "\x10UpdateGiftConfig\x12(.hyapp.wallet.v1.UpdateGiftConfigRequest\x1a#.hyapp.wallet.v1.GiftConfigResponse\x12g\n" + - "\x13SetGiftConfigStatus\x12+.hyapp.wallet.v1.SetGiftConfigStatusRequest\x1a#.hyapp.wallet.v1.GiftConfigResponse\x12^\n" + - "\rGrantResource\x12%.hyapp.wallet.v1.GrantResourceRequest\x1a&.hyapp.wallet.v1.ResourceGrantResponse\x12h\n" + - "\x12GrantResourceGroup\x12*.hyapp.wallet.v1.GrantResourceGroupRequest\x1a&.hyapp.wallet.v1.ResourceGrantResponse\x12j\n" + - "\x11ListUserResources\x12).hyapp.wallet.v1.ListUserResourcesRequest\x1a*.hyapp.wallet.v1.ListUserResourcesResponse\x12j\n" + - "\x11EquipUserResource\x12).hyapp.wallet.v1.EquipUserResourceRequest\x1a*.hyapp.wallet.v1.EquipUserResourceResponse\x12m\n" + - "\x12ListResourceGrants\x12*.hyapp.wallet.v1.ListResourceGrantsRequest\x1a+.hyapp.wallet.v1.ListResourceGrantsResponse\x12j\n" + - "\x11ListRechargeBills\x12).hyapp.wallet.v1.ListRechargeBillsRequest\x1a*.hyapp.wallet.v1.ListRechargeBillsResponseB*Z(hyapp.local/api/proto/wallet/v1;walletv1b\x06proto3" +var file_proto_wallet_v1_wallet_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x76, + 0x31, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x22, + 0xab, 0x02, 0x0a, 0x10, 0x44, 0x65, 0x62, 0x69, 0x74, 0x47, 0x69, 0x66, 0x74, 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, 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, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, + 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x63, 0x65, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xeb, 0x02, + 0x0a, 0x11, 0x44, 0x65, 0x62, 0x69, 0x74, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x72, + 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 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, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x69, 0x6e, + 0x5f, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, + 0x69, 0x6e, 0x53, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x67, 0x69, 0x66, 0x74, 0x5f, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0e, 0x67, 0x69, 0x66, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x65, + 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x65, 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x68, 0x65, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x63, 0x65, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x62, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x68, + 0x61, 0x72, 0x67, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, + 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, + 0x68, 0x61, 0x72, 0x67, 0x65, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xb2, 0x01, 0x0a, 0x0c, + 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x61, + 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, + 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x66, + 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 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, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, + 0x22, 0x88, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 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, 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, + 0x1f, 0x0a, 0x0b, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, + 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x50, 0x0a, 0x13, 0x47, + 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 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, 0x08, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x95, 0x02, + 0x0a, 0x17, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x41, 0x73, 0x73, + 0x65, 0x74, 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, 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, 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, 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, 0x12, + 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x76, 0x69, 0x64, 0x65, + 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, + 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x66, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, + 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, + 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x7a, 0x0a, 0x18, 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, 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, 0x73, 0x73, 0x65, + 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x22, 0xa9, 0x02, 0x0a, 0x1d, 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, 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, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x6c, + 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 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, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x19, + 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x65, 0x6c, + 0x6c, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x94, 0x04, + 0x0a, 0x1e, 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, 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, 0x30, 0x0a, 0x14, 0x73, 0x65, 0x6c, 0x6c, 0x65, + 0x72, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x61, 0x66, 0x74, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x42, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 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, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, + 0x75, 0x73, 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x10, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x55, 0x73, 0x64, 0x4d, 0x69, 0x6e, 0x6f, + 0x72, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x14, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x43, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x68, 0x61, + 0x72, 0x67, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, + 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, + 0x1b, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x18, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x46, 0x0a, 0x20, + 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, + 0x75, 0x73, 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1c, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x73, 0x64, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc9, 0x05, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 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, 0x1f, 0x0a, 0x0b, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 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, 0x03, + 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, 0x04, 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, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, + 0x65, 0x67, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x67, 0x72, 0x61, 0x6e, 0x74, + 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x11, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x63, + 0x6f, 0x70, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x73, 0x61, 0x67, + 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, + 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x73, 0x73, 0x65, + 0x74, 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x69, + 0x65, 0x77, 0x55, 0x72, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6e, 0x69, 0x6d, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x6e, + 0x69, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x12, + 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x2b, + 0x0a, 0x12, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x18, 0x11, 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, 0x12, 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, 0x13, 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, 0x14, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, + 0x22, 0xc7, 0x03, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x22, 0x0a, 0x0d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, + 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 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, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 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, 0x1f, 0x0a, 0x0b, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, + 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x07, 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, 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, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, + 0x0a, 0x11, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xad, 0x03, 0x0a, 0x0d, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 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, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 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, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 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, + 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x38, + 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 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, 0x49, 0x74, 0x65, + 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x2b, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x09, + 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, 0x0a, 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, 0x0b, 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, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xa9, 0x06, 0x0a, 0x0a, 0x47, + 0x69, 0x66, 0x74, 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, 0x17, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, + 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x35, + 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 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, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 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, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 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, + 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x23, 0x0a, + 0x0d, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x69, 0x63, + 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x67, 0x69, + 0x66, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, + 0x0a, 0x68, 0x65, 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x68, 0x65, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2b, 0x0a, 0x12, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x0d, 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, + 0x0e, 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, 0x0f, 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, 0x10, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x1d, + 0x0a, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x11, 0x20, 0x03, + 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x24, 0x0a, + 0x0e, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x67, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x61, 0x73, + 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x2a, 0x0a, 0x11, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x72, 0x6f, + 0x6d, 0x5f, 0x6d, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x65, 0x66, 0x66, 0x65, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x4d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x65, + 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6d, 0x73, 0x18, 0x15, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, + 0x6f, 0x4d, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x66, 0x66, 0x65, 0x63, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0xeb, 0x03, 0x0a, 0x17, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 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, 0x25, 0x0a, + 0x0e, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 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, 0x1f, 0x0a, + 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x35, + 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 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, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x6d, + 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, + 0x51, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x66, 0x66, 0x65, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x41, 0x74, 0x4d, 0x73, + 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x5f, 0x6d, + 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x41, 0x74, 0x4d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, + 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0c, 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, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x4d, 0x73, 0x22, 0x86, 0x03, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x22, 0x0a, 0x0d, 0x67, 0x72, + 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0b, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x19, + 0x0a, 0x08, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, + 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4a, 0x73, 0x6f, 0x6e, + 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, 0x1f, 0x0a, 0x0b, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0a, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x12, 0x1f, 0x0a, + 0x0b, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 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, 0x08, 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, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xe1, 0x03, + 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 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, 0x19, 0x0a, 0x08, 0x67, 0x72, + 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, + 0x61, 0x6e, 0x74, 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, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x67, 0x72, + 0x61, 0x6e, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2c, 0x0a, + 0x12, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x67, 0x72, 0x61, 0x6e, 0x74, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x67, + 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x09, 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, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x38, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, + 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, 0x49, 0x74, + 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0c, 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, 0x0d, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, + 0x73, 0x22, 0x8e, 0x02, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x70, 0x75, 0x74, 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, 0x1a, 0x0a, + 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, + 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, + 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x74, 0x65, + 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x74, + 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x73, 0x73, + 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x11, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x22, 0xf9, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 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, 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, 0x16, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x70, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, + 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x66, + 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 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, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x6f, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 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, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x22, 0x4c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, + 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 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, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xdc, 0x04, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 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, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 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, + 0x04, 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, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x1c, 0x0a, 0x09, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x25, 0x0a, + 0x0e, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x61, + 0x74, 0x65, 0x67, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x2e, 0x0a, 0x13, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, + 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, + 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x73, 0x61, 0x67, 0x65, 0x53, 0x63, 0x6f, + 0x70, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x75, 0x72, 0x6c, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x55, 0x72, 0x6c, + 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x55, 0x72, + 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6e, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, + 0x72, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x6e, 0x69, 0x6d, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x10, 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, 0x11, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x22, 0xfd, 0x04, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 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, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 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, 0x04, 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, + 0x05, 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, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 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, + 0x1c, 0x0a, 0x09, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x25, 0x0a, + 0x0e, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x61, + 0x74, 0x65, 0x67, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x2e, 0x0a, 0x13, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, + 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, + 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x73, 0x61, 0x67, 0x65, 0x53, 0x63, 0x6f, + 0x70, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x75, 0x72, 0x6c, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x55, 0x72, 0x6c, + 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x55, 0x72, + 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6e, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, + 0x72, 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x6e, 0x69, 0x6d, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x11, 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, 0x12, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 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, 0x1f, 0x0a, 0x0b, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 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, 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, 0x49, + 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 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, + 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xd9, 0x01, 0x0a, 0x19, 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, 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, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, + 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, + 0x6f, 0x72, 0x64, 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, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6f, + 0x6e, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x6a, 0x0a, 0x1a, 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, 0x36, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1e, 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, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x22, 0x6e, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x47, 0x72, 0x6f, 0x75, 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, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x64, 0x22, 0x50, 0x0a, 0x18, 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, 0x34, 0x0a, + 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 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, 0x05, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x22, 0xcb, 0x02, 0x0a, 0x1a, 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, 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, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 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, + 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 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, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, + 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, + 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 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, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x22, 0xe6, 0x02, 0x0a, 0x1a, 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, + 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, 0x19, 0x0a, 0x08, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 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, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x12, 0x3d, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x27, 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, + 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, + 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, 0xb6, 0x01, 0x0a, 0x1d, 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, 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, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x64, 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, 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, 0x4d, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x05, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 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, 0x05, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x22, 0x98, 0x02, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x66, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, + 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 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, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0c, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, + 0x17, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x05, 0x67, 0x69, 0x66, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 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, 0x05, 0x67, 0x69, 0x66, 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, 0xce, 0x05, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, 0x74, + 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, 0x67, 0x69, 0x66, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, + 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 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, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x06, 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, 0x07, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x11, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6a, 0x73, 0x6f, + 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x70, 0x72, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, + 0x0a, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x2a, 0x0a, + 0x11, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x67, 0x69, 0x66, 0x74, 0x50, 0x6f, + 0x69, 0x6e, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x65, 0x61, + 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x68, + 0x65, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x66, 0x66, 0x65, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x41, 0x74, 0x4d, 0x73, + 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x67, 0x69, 0x66, + 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x67, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, + 0x2a, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x72, + 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x65, + 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x6d, 0x73, + 0x18, 0x12, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, + 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x4d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x66, 0x66, 0x65, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6d, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x6f, 0x4d, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, + 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x73, 0x22, 0xce, 0x05, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x69, 0x66, + 0x74, 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, 0x67, 0x69, 0x66, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, + 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x49, 0x64, 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, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x06, 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, 0x07, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x2b, 0x0a, + 0x11, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6a, 0x73, + 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x2a, + 0x0a, 0x11, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x67, 0x69, 0x66, 0x74, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x65, + 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x68, 0x65, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x66, 0x66, + 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x41, 0x74, 0x4d, + 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x03, 0x52, + 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x67, 0x69, + 0x66, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x10, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x67, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x68, 0x61, + 0x72, 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x11, + 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x6d, + 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x4d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x66, 0x66, 0x65, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6d, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x6f, 0x4d, 0x73, + 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x1a, 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, 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, + 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, + 0x69, 0x66, 0x74, 0x49, 0x64, 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, 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, 0x45, 0x0a, 0x12, 0x47, 0x69, 0x66, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, + 0x04, 0x67, 0x69, 0x66, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 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, 0x04, 0x67, 0x69, 0x66, 0x74, 0x22, 0xb9, + 0x02, 0x0a, 0x14, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 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, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 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, 0x1f, 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x73, 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, 0x28, 0x0a, + 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x67, 0x72, 0x61, 0x6e, 0x74, + 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x67, + 0x72, 0x61, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xfb, 0x01, 0x0a, 0x19, 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, 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, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, + 0x70, 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, 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, 0x21, 0x0a, 0x0c, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x67, 0x72, 0x61, + 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x4d, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x34, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1e, 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, 0x05, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x22, 0xb3, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 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, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x63, 0x0a, + 0x19, 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, 0x46, 0x0a, 0x09, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x18, 0x45, 0x71, 0x75, 0x69, 0x70, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 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, 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, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x61, 0x0a, 0x19, 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, 0x44, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xc4, 0x01, + 0x0a, 0x19, 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, 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, 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, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 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, 0x6a, 0x0a, 0x1a, 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, 0x36, 0x0a, 0x06, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1e, 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, 0x06, 0x67, 0x72, 0x61, 0x6e, 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, 0xa7, 0x05, 0x0a, 0x0c, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x42, 0x69, 0x6c, + 0x6c, 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, 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, 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, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x68, 0x61, + 0x72, 0x67, 0x65, 0x54, 0x79, 0x70, 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, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x66, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52, + 0x65, 0x66, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, + 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x65, 0x6c, + 0x6c, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, + 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x28, 0x0a, 0x10, 0x75, 0x73, 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x75, 0x73, 0x64, 0x4d, 0x69, + 0x6e, 0x6f, 0x72, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x65, 0x78, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x19, 0x65, + 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x75, 0x73, 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x6f, + 0x72, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, 0x52, 0x16, + 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x64, 0x4d, 0x69, 0x6e, 0x6f, 0x72, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 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, 0x22, 0xf4, 0x02, 0x0a, 0x18, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x42, 0x69, 0x6c, 0x6c, 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, 0x24, 0x0a, 0x0e, 0x73, 0x65, + 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, + 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, 0x23, 0x0a, + 0x0d, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x54, 0x79, + 0x70, 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, 0x18, 0x0a, 0x07, 0x6b, 0x65, + 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, + 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x61, 0x74, + 0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x41, 0x74, 0x4d, 0x73, 0x12, 0x1a, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, + 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x4d, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, + 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, + 0x65, 0x22, 0x66, 0x0a, 0x19, 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, 0x33, + 0x0a, 0x05, 0x62, 0x69, 0x6c, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 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, 0x42, 0x69, 0x6c, 0x6c, 0x52, 0x05, 0x62, 0x69, + 0x6c, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x32, 0xac, 0x13, 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, 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, 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, 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, + 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, 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, 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, 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, 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 ( file_proto_wallet_v1_wallet_proto_rawDescOnce sync.Once - file_proto_wallet_v1_wallet_proto_rawDescData []byte + file_proto_wallet_v1_wallet_proto_rawDescData = file_proto_wallet_v1_wallet_proto_rawDesc ) func file_proto_wallet_v1_wallet_proto_rawDescGZIP() []byte { file_proto_wallet_v1_wallet_proto_rawDescOnce.Do(func() { - file_proto_wallet_v1_wallet_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_wallet_v1_wallet_proto_rawDesc), len(file_proto_wallet_v1_wallet_proto_rawDesc))) + file_proto_wallet_v1_wallet_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_wallet_v1_wallet_proto_rawDescData) }) return file_proto_wallet_v1_wallet_proto_rawDescData } @@ -5657,7 +6227,7 @@ func file_proto_wallet_v1_wallet_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_wallet_v1_wallet_proto_rawDesc), len(file_proto_wallet_v1_wallet_proto_rawDesc)), + RawDescriptor: file_proto_wallet_v1_wallet_proto_rawDesc, NumEnums: 0, NumMessages: 51, NumExtensions: 0, @@ -5668,6 +6238,7 @@ func file_proto_wallet_v1_wallet_proto_init() { MessageInfos: file_proto_wallet_v1_wallet_proto_msgTypes, }.Build() File_proto_wallet_v1_wallet_proto = out.File + file_proto_wallet_v1_wallet_proto_rawDesc = nil file_proto_wallet_v1_wallet_proto_goTypes = nil file_proto_wallet_v1_wallet_proto_depIdxs = nil } diff --git a/api/proto/wallet/v1/wallet_grpc.pb.go b/api/proto/wallet/v1/wallet_grpc.pb.go index b4d5244d..6992d341 100644 --- a/api/proto/wallet/v1/wallet_grpc.pb.go +++ b/api/proto/wallet/v1/wallet_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.6.1 -// - protoc v7.34.1 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: proto/wallet/v1/wallet.proto package walletv1 @@ -366,76 +366,76 @@ type WalletServiceServer interface { type UnimplementedWalletServiceServer struct{} func (UnimplementedWalletServiceServer) DebitGift(context.Context, *DebitGiftRequest) (*DebitGiftResponse, error) { - return nil, status.Error(codes.Unimplemented, "method DebitGift not implemented") + return nil, status.Errorf(codes.Unimplemented, "method DebitGift not implemented") } func (UnimplementedWalletServiceServer) GetBalances(context.Context, *GetBalancesRequest) (*GetBalancesResponse, error) { - return nil, status.Error(codes.Unimplemented, "method GetBalances not implemented") + return nil, status.Errorf(codes.Unimplemented, "method GetBalances not implemented") } func (UnimplementedWalletServiceServer) AdminCreditAsset(context.Context, *AdminCreditAssetRequest) (*AdminCreditAssetResponse, error) { - return nil, status.Error(codes.Unimplemented, "method AdminCreditAsset not implemented") + return nil, status.Errorf(codes.Unimplemented, "method AdminCreditAsset not implemented") } func (UnimplementedWalletServiceServer) TransferCoinFromSeller(context.Context, *TransferCoinFromSellerRequest) (*TransferCoinFromSellerResponse, error) { - return nil, status.Error(codes.Unimplemented, "method TransferCoinFromSeller not implemented") + return nil, status.Errorf(codes.Unimplemented, "method TransferCoinFromSeller not implemented") } func (UnimplementedWalletServiceServer) ListResources(context.Context, *ListResourcesRequest) (*ListResourcesResponse, error) { - return nil, status.Error(codes.Unimplemented, "method ListResources not implemented") + return nil, status.Errorf(codes.Unimplemented, "method ListResources not implemented") } func (UnimplementedWalletServiceServer) GetResource(context.Context, *GetResourceRequest) (*GetResourceResponse, error) { - return nil, status.Error(codes.Unimplemented, "method GetResource not implemented") + return nil, status.Errorf(codes.Unimplemented, "method GetResource not implemented") } func (UnimplementedWalletServiceServer) CreateResource(context.Context, *CreateResourceRequest) (*ResourceResponse, error) { - return nil, status.Error(codes.Unimplemented, "method CreateResource not implemented") + return nil, status.Errorf(codes.Unimplemented, "method CreateResource not implemented") } func (UnimplementedWalletServiceServer) UpdateResource(context.Context, *UpdateResourceRequest) (*ResourceResponse, error) { - return nil, status.Error(codes.Unimplemented, "method UpdateResource not implemented") + return nil, status.Errorf(codes.Unimplemented, "method UpdateResource not implemented") } func (UnimplementedWalletServiceServer) SetResourceStatus(context.Context, *SetResourceStatusRequest) (*ResourceResponse, error) { - return nil, status.Error(codes.Unimplemented, "method SetResourceStatus not implemented") + return nil, status.Errorf(codes.Unimplemented, "method SetResourceStatus not implemented") } func (UnimplementedWalletServiceServer) ListResourceGroups(context.Context, *ListResourceGroupsRequest) (*ListResourceGroupsResponse, error) { - return nil, status.Error(codes.Unimplemented, "method ListResourceGroups not implemented") + return nil, status.Errorf(codes.Unimplemented, "method ListResourceGroups not implemented") } func (UnimplementedWalletServiceServer) GetResourceGroup(context.Context, *GetResourceGroupRequest) (*GetResourceGroupResponse, error) { - return nil, status.Error(codes.Unimplemented, "method GetResourceGroup not implemented") + return nil, status.Errorf(codes.Unimplemented, "method GetResourceGroup not implemented") } func (UnimplementedWalletServiceServer) CreateResourceGroup(context.Context, *CreateResourceGroupRequest) (*ResourceGroupResponse, error) { - return nil, status.Error(codes.Unimplemented, "method CreateResourceGroup not implemented") + return nil, status.Errorf(codes.Unimplemented, "method CreateResourceGroup not implemented") } func (UnimplementedWalletServiceServer) UpdateResourceGroup(context.Context, *UpdateResourceGroupRequest) (*ResourceGroupResponse, error) { - return nil, status.Error(codes.Unimplemented, "method UpdateResourceGroup not implemented") + return nil, status.Errorf(codes.Unimplemented, "method UpdateResourceGroup not implemented") } func (UnimplementedWalletServiceServer) SetResourceGroupStatus(context.Context, *SetResourceGroupStatusRequest) (*ResourceGroupResponse, error) { - return nil, status.Error(codes.Unimplemented, "method SetResourceGroupStatus not implemented") + return nil, status.Errorf(codes.Unimplemented, "method SetResourceGroupStatus not implemented") } func (UnimplementedWalletServiceServer) ListGiftConfigs(context.Context, *ListGiftConfigsRequest) (*ListGiftConfigsResponse, error) { - return nil, status.Error(codes.Unimplemented, "method ListGiftConfigs not implemented") + return nil, status.Errorf(codes.Unimplemented, "method ListGiftConfigs not implemented") } func (UnimplementedWalletServiceServer) CreateGiftConfig(context.Context, *CreateGiftConfigRequest) (*GiftConfigResponse, error) { - return nil, status.Error(codes.Unimplemented, "method CreateGiftConfig not implemented") + return nil, status.Errorf(codes.Unimplemented, "method CreateGiftConfig not implemented") } func (UnimplementedWalletServiceServer) UpdateGiftConfig(context.Context, *UpdateGiftConfigRequest) (*GiftConfigResponse, error) { - return nil, status.Error(codes.Unimplemented, "method UpdateGiftConfig not implemented") + return nil, status.Errorf(codes.Unimplemented, "method UpdateGiftConfig not implemented") } func (UnimplementedWalletServiceServer) SetGiftConfigStatus(context.Context, *SetGiftConfigStatusRequest) (*GiftConfigResponse, error) { - return nil, status.Error(codes.Unimplemented, "method SetGiftConfigStatus not implemented") + return nil, status.Errorf(codes.Unimplemented, "method SetGiftConfigStatus not implemented") } func (UnimplementedWalletServiceServer) GrantResource(context.Context, *GrantResourceRequest) (*ResourceGrantResponse, error) { - return nil, status.Error(codes.Unimplemented, "method GrantResource not implemented") + return nil, status.Errorf(codes.Unimplemented, "method GrantResource not implemented") } func (UnimplementedWalletServiceServer) GrantResourceGroup(context.Context, *GrantResourceGroupRequest) (*ResourceGrantResponse, error) { - return nil, status.Error(codes.Unimplemented, "method GrantResourceGroup not implemented") + return nil, status.Errorf(codes.Unimplemented, "method GrantResourceGroup not implemented") } func (UnimplementedWalletServiceServer) ListUserResources(context.Context, *ListUserResourcesRequest) (*ListUserResourcesResponse, error) { - return nil, status.Error(codes.Unimplemented, "method ListUserResources not implemented") + return nil, status.Errorf(codes.Unimplemented, "method ListUserResources not implemented") } func (UnimplementedWalletServiceServer) EquipUserResource(context.Context, *EquipUserResourceRequest) (*EquipUserResourceResponse, error) { - return nil, status.Error(codes.Unimplemented, "method EquipUserResource not implemented") + return nil, status.Errorf(codes.Unimplemented, "method EquipUserResource not implemented") } func (UnimplementedWalletServiceServer) ListResourceGrants(context.Context, *ListResourceGrantsRequest) (*ListResourceGrantsResponse, error) { - return nil, status.Error(codes.Unimplemented, "method ListResourceGrants not implemented") + return nil, status.Errorf(codes.Unimplemented, "method ListResourceGrants not implemented") } func (UnimplementedWalletServiceServer) ListRechargeBills(context.Context, *ListRechargeBillsRequest) (*ListRechargeBillsResponse, error) { - return nil, status.Error(codes.Unimplemented, "method ListRechargeBills not implemented") + return nil, status.Errorf(codes.Unimplemented, "method ListRechargeBills not implemented") } func (UnimplementedWalletServiceServer) mustEmbedUnimplementedWalletServiceServer() {} func (UnimplementedWalletServiceServer) testEmbeddedByValue() {} @@ -448,7 +448,7 @@ type UnsafeWalletServiceServer interface { } func RegisterWalletServiceServer(s grpc.ServiceRegistrar, srv WalletServiceServer) { - // If the following call panics, it indicates UnimplementedWalletServiceServer was + // If the following call pancis, it indicates UnimplementedWalletServiceServer 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. diff --git a/docker-compose.yml b/docker-compose.yml index 4a85979a..a96c3cfe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -85,6 +85,8 @@ services: depends_on: mysql: condition: service_healthy + user-service: + condition: service_healthy healthcheck: test: ["CMD-SHELL", "/app/grpc-health-probe -addr=127.0.0.1:13006 -service=activity-service"] interval: 5s diff --git a/docs/app-entry-state-machine.md b/docs/app-entry-state-machine.md new file mode 100644 index 00000000..b79fa3c8 --- /dev/null +++ b/docs/app-entry-state-machine.md @@ -0,0 +1,382 @@ +# App Entry State Machine + +本文定义用户从打开 App 到进入主界面的完整状态机。它只描述 App 入口流程、接口调用顺序、跳转条件和异常恢复边界;登录注册细节见 [Login And Registration Technical Design](./auth-login-register-technical-design.md),房间重连细节见 [Room Entry Reconnect Development Requirements](./room-entry-reconnect-development-requirements.md)。 + +## Goals + +- 客户端启动时用确定的状态机决定去登录页、资料补全页、主界面或维护/升级页。 +- 未完成资料的用户不能进入房间、IM、RTC、钱包和付费流程。 +- access token 过期时优先 refresh,refresh 失败才回登录页。 +- 主界面首屏只调用轻量一级接口:房间、消息、我的。 +- 腾讯云 IM 登录必须在 `profile_completed=true` 后发生,避免未完成资料用户进入实时系统。 +- 房间恢复必须独立于房间列表,不能靠列表猜测用户是否还在某个房间。 + +## Current Interface Inventory + +| Capability | Endpoint | Status | Rule | +| --- | --- | --- | --- | +| 三方登录即注册 | `POST /api/v1/auth/third-party/login` | DONE | 返回 `is_new_user/profile_completed/onboarding_status` | +| refresh token | `POST /api/v1/auth/token/refresh` | DONE | 成功后轮换 refresh token | +| 资料补全 | `POST /api/v1/users/me/onboarding/complete` | DONE | 成功后返回新的 access token,不轮换 refresh token | +| 注册国家 | `GET /api/v1/countries` | DONE | 登录前可用 | +| 我的页首屏 | `GET /api/v1/users/me/overview` | DONE | 主界面轻聚合 | +| 房间列表 | `GET /api/v1/rooms?tab=hot/new` | DONE | 需要 completed profile | +| 消息 tab | `GET /api/v1/messages/tabs` | DONE | 需要 completed profile | +| 腾讯 IM UserSig | `GET /api/v1/im/usersig` | DONE | 需要 completed profile | +| App 启动配置 | `GET /api/v1/app/bootstrap` | DONE | 版本、维护、feature flags、配置版本 | +| 当前房间恢复 | `GET /api/v1/rooms/current` | DONE | 判断是否有可恢复房间 | +| 推送 token 绑定 | `POST /api/v1/devices/push-token` / `DELETE /api/v1/devices/push-token` | DONE | 离线消息触达 | + +## Top Level State Machine + +```mermaid +stateDiagram-v2 + [*] --> Launch + Launch --> Bootstrap + Bootstrap --> ForceUpgrade + Bootstrap --> Maintenance + Bootstrap --> TokenCheck + + TokenCheck --> LoginRequired: no local token + TokenCheck --> AuthenticatedProbe: access token exists + + AuthenticatedProbe --> MainReady: overview ok and profile completed + AuthenticatedProbe --> Refreshing: access token expired or 401 + AuthenticatedProbe --> ProfileRequired: PROFILE_REQUIRED or token says profile incomplete + + Refreshing --> AuthenticatedProbe: refresh ok + Refreshing --> LoginRequired: refresh failed + + LoginRequired --> LoginOrRegister + LoginOrRegister --> ProfileRequired: login ok but profile incomplete + LoginOrRegister --> MainReady: login ok and profile completed + + ProfileRequired --> CompleteOnboarding + CompleteOnboarding --> MainReady: success with replacement access token + + MainReady --> MainTabs + MainTabs --> IMLogin + MainTabs --> RoomRestoreProbe +``` + +## Launch Sequence + +启动顺序: + +1. App 启动,生成或读取 stable `device_id`。 +2. 调 `GET /api/v1/app/bootstrap`,以 bootstrap 返回的版本、维护、feature flags 和配置版本作为入口决策事实。 +3. 如果 bootstrap 返回强更,进入强更页。 +4. 如果 bootstrap 返回维护中,进入维护页。 +5. 检查本地是否有 access token。 +6. 没有 token,进入登录页。 +7. 有 token,调用 `GET /api/v1/users/me/overview` 做认证探测和首屏数据读取。 + +不要只靠本地缓存判断是否进入主界面。用户可能被禁用、token 可能过期、资料完成状态可能已经变化。 + +## Bootstrap Contract + +当前接口: + +```http +GET /api/v1/app/bootstrap +``` + +登录前也可调用。请求必须携带 App 解析头: + +| Header | Meaning | +| --- | --- | +| `X-App-Code` / `X-HY-App-Code` | 已知内部 `app_code` | +| `X-App-Package` / `X-Package-Name` | 包名或 Bundle ID | +| `X-App-Platform` / `X-Platform` | `android` or `ios` | +| `X-App-Version` | 客户端版本 | +| `X-Build-Number` | 构建号 | + +响应字段: + +```json +{ + "app_code": "lalu", + "server_time_ms": 1777996800000, + "force_upgrade": false, + "maintenance": false, + "minimum_version": "1.0.0", + "latest_version": "1.2.0", + "feature_flags": { + "wallet_recharge": true, + "wallet_withdraw": true, + "diamond_exchange": true, + "message_tab": true, + "host_center": true, + "room_create": true + }, + "bottom_tabs": [ + {"key": "rooms", "title": "房间", "enabled": true}, + {"key": "messages", "title": "消息", "enabled": true}, + {"key": "me", "title": "我的", "enabled": true} + ], + "config_versions": { + "countries": "v1", + "banners": "v1", + "h5_links": "v1", + "resources": "v1", + "gifts": "v1" + } +} +``` + +bootstrap 只返回配置摘要和版本号,不返回完整礼物、背包资源或 banner 列表。客户端发现版本变化后再拉对应配置接口。 + +## Authentication Probe + +有 access token 时,首选调用: + +```http +GET /api/v1/users/me/overview +``` + +结果处理: + +| Result | Client Action | +| --- | --- | +| `200 OK` | 使用 overview 进入主界面 | +| `401 AUTH_REQUIRED` / token expired | 调 refresh | +| `403 PROFILE_REQUIRED` | 进入资料补全页 | +| `403 USER_DISABLED/BANNED` | 进入账号异常页 | +| `5xx/502` | 展示重试页,不清 token | + +`overview` 失败时不要直接清空登录态。只有 refresh 明确失败、session revoked 或用户主动 logout 才清本地 token。 + +## Refresh State + +```http +POST /api/v1/auth/token/refresh +``` + +请求必须带: + +- `refresh_token` +- `device_id` + +处理规则: + +| Result | Client Action | +| --- | --- | +| refresh ok | 替换 access token 和 refresh token,重试 `overview` | +| `SESSION_EXPIRED` | 清 token,进登录页 | +| `SESSION_REVOKED` | 清 token,进登录页 | +| `AUTH_FAILED` | 清 token,进登录页 | +| network/5xx | 不清 token,展示重试 | + +refresh 成功会轮换 refresh token。客户端必须原子保存新 access token 和新 refresh token,避免只保存一半导致下次启动失效。 + +## Login State + +三方登录: + +```http +POST /api/v1/auth/third-party/login +``` + +状态跳转: + +| Response | Client Action | +| --- | --- | +| `is_new_user=true` | 进入资料补全页 | +| `profile_completed=false` | 进入资料补全页 | +| `profile_completed=true` | 进入主界面 | + +服务端不会返回 `NOT_REGISTERED`。三方身份不存在时,该接口原子创建用户、三方绑定、默认短号和 session。 + +## Profile Required State + +资料补全页需要先拉: + +```http +GET /api/v1/countries +``` + +提交: + +```http +POST /api/v1/users/me/onboarding/complete +``` + +成功后: + +- 替换响应里的新 access token。 +- 保留原 refresh token;该接口不轮换 refresh token。 +- 重新调用 `GET /api/v1/users/me/overview`。 +- overview 成功后进入主界面。 + +未完成资料的 access token 会在 gateway profile gate 被拒绝。客户端不能绕过资料补全去请求房间、IM、RTC、钱包和付费接口。 + +## Main Tabs Entry + +进入主界面后,底部三个一级页使用这些接口: + +| Tab | Primary Endpoint | Notes | +| --- | --- | --- | +| 房间 | `GET /api/v1/rooms?tab=hot&limit=20` | 默认 hot;new 用同一接口 | +| 消息 | `GET /api/v1/messages/tabs` | 用户私聊列表走腾讯云 IM SDK | +| 我的 | `GET /api/v1/users/me/overview` | 轻聚合,不查流水、成员、工资 | + +主界面首屏可以并行: + +```mermaid +sequenceDiagram + participant C as Client + participant G as gateway-service + participant TIM as Tencent IM + + par room tab + C->>G: GET /api/v1/rooms?tab=hot + and message tab + C->>G: GET /api/v1/messages/tabs + and me tab + C->>G: GET /api/v1/users/me/overview + and IM + C->>G: GET /api/v1/im/usersig + C->>TIM: SDK login + end +``` + +如果当前默认落在“房间” tab,可以优先请求房间列表,消息和我的延后或并行低优先级请求。 + +## IM Login State + +腾讯云 IM 登录必须发生在 `profile_completed=true` 后。 + +```http +GET /api/v1/im/usersig +``` + +规则: + +- UserSig 只用于腾讯云 IM SDK 登录。 +- 用户私聊会话列表由 SDK 拉取。 +- 系统/活动消息由 `/api/v1/messages/tabs` 和 `/api/v1/messages` 拉取。 +- UserSig 过期时重新调用该接口,不使用 refresh token。 + +未完成资料用户请求 `/api/v1/im/usersig` 必须返回 `PROFILE_REQUIRED`。 + +## Room Restore State + +当前接口: + +```http +GET /api/v1/rooms/current +``` + +用途:App 从后台回前台、进程重启、网络恢复时,判断是否有需要恢复的房间。不能通过房间列表猜测当前房间,因为列表是发现页,不表达当前用户 presence。 + +响应字段: + +```json +{ + "has_current_room": true, + "room_id": "lalu_room_01", + "room_version": 12, + "role": "audience", + "mic_session_id": "", + "publish_state": "", + "need_join_im_group": true, + "need_rtc_token": false, + "server_time_ms": 1777996800000 +} +``` + +恢复规则: + +| State | Client Action | +| --- | --- | +| `has_current_room=false` | 不展示恢复入口 | +| `audience` | 重新登录 IM 并 join group;不申请 RTC token | +| `on mic pending/publishing` | 调 `/api/v1/rtc/token`,恢复 RTC;随后按麦位状态确认发流 | +| room closed / kicked / banned | 清本地房间态,展示原因或静默回房间列表 | + +`rooms/current` 由 room-service 的用户 presence 读模型和 Room Cell 快照二次校验共同决定。该接口只做恢复探测,不写命令日志、不刷新心跳、不隐式 JoinRoom。 + +## Push Token State + +当前接口: + +```http +POST /api/v1/devices/push-token +DELETE /api/v1/devices/push-token +``` + +绑定时机: + +- 资料完成后。 +- 用户允许系统通知后。 +- token 变化、App 重装、语言/时区变化时重新上报。 + +该能力服务系统/活动消息离线触达,不影响 App 能否进入主界面。 + +## Error Handling Rules + +| Error | Meaning | Client Action | +| --- | --- | --- | +| `AUTH_REQUIRED` | access token 缺失或无效 | 有 refresh 则 refresh;否则登录 | +| `SESSION_EXPIRED` | refresh session 过期 | 清 token,登录 | +| `SESSION_REVOKED` | refresh session 已吊销 | 清 token,登录 | +| `PROFILE_REQUIRED` | 已登录但资料未完成 | 资料补全 | +| `USER_DISABLED` | 用户被禁用 | 账号异常页 | +| `USER_BANNED` | 用户被封禁 | 账号异常页 | +| `UPSTREAM_ERROR` | 上游不可用 | 重试,不清 token | +| network timeout | 网络异常 | 重试,不清 token | + +不要因为普通 5xx、网络失败或 bootstrap 失败清空登录态。 + +## Client Local State + +客户端本地至少保存: + +- `access_token` +- `refresh_token` +- `session_id` +- `user_id` +- `app_code` +- `profile_completed` +- `onboarding_status` +- `device_id` +- `last_room_id`,只做恢复提示,不能作为 presence 事实 +- config version cache + +服务端事实优先级高于本地缓存。只要服务端返回 profile required、disabled、banned、session revoked,客户端必须更新本地状态。 + +## Implementation Status + +1. 服务端已固定 App 入口状态机文档,客户端入口必须按本文状态转移。 +2. gateway 已实现 `GET /api/v1/app/bootstrap`,返回版本、维护、feature flags、bottom tabs 和配置版本。 +3. gateway 已实现 `GET /api/v1/rooms/current`,只用 token user_id 做当前用户房间恢复探测,不修改房间状态。 +4. user-service 已实现 push token 绑定/解绑 RPC,gateway 已暴露 `POST/DELETE /api/v1/devices/push-token`。 +5. App 端下一步按本文状态机接入:bootstrap -> token probe -> refresh/login/onboarding -> main tabs -> IM login -> room restore。 +6. 端到端 smoke 必须覆盖:新用户注册、老用户启动、access token 过期 refresh、profile required、IM login、房间恢复。 + +## Verification Matrix + +| Scenario | Expected | +| --- | --- | +| 首次安装无 token | bootstrap 后进入登录页 | +| 新用户三方登录 | 创建用户,进入资料补全页 | +| 资料补全成功 | 替换 access token,进入主界面 | +| access token 过期 | refresh 成功后重试 overview | +| refresh token 过期 | 清 token,进入登录页 | +| 未完成资料请求房间列表 | 返回 `PROFILE_REQUIRED` | +| 未完成资料请求 IM UserSig | 返回 `PROFILE_REQUIRED` | +| 主界面打开房间 tab | 拉 `GET /api/v1/rooms?tab=hot` | +| 主界面打开消息 tab | 拉 `GET /api/v1/messages/tabs`,用户私聊走 IM SDK | +| 主界面打开我的 tab | 拉 `GET /api/v1/users/me/overview` | +| App 回前台且有房间 presence | `rooms/current` 返回恢复信息 | +| 普通 5xx 或网络失败 | 展示重试,不清本地 token | + +## Critical Rules + +- 资料未完成不能进入实时系统、房间、钱包和付费流程。 +- `request_id` 只做链路追踪,不做幂等键。 +- 登录和 refresh 响应里的 token 必须原子保存。 +- CompleteOnboarding 只替换 access token,不轮换 refresh token。 +- IM 登录在主资料完成之后,用户私聊状态以腾讯云 IM SDK 为准。 +- 房间恢复用 `rooms/current`,不要用房间列表代替。 +- bootstrap 只返回配置摘要和版本,不返回大列表。 diff --git a/docs/app-message-tab-architecture.md b/docs/app-message-tab-architecture.md new file mode 100644 index 00000000..c3c63036 --- /dev/null +++ b/docs/app-message-tab-architecture.md @@ -0,0 +1,593 @@ +# App Message Tab Architecture + +本文定义 App 底部 `消息` tab 的产品边界、服务架构、数据模型、接口契约和开发顺序。消息 tab 固定分为 `用户`、`系统`、`活动` 三个分区。当前仓库不自研 IM 长连接,用户私聊仍由腾讯云 IM SDK 承担;后端只持久化系统和活动 inbox,并提供列表、未读、已读、删除和运营触达能力。 + +## Goals + +- App 底部消息 tab 展示三个分区:`用户`、`系统`、`活动`。 +- `用户` 分区来自腾讯云 IM C2C conversation list,不把私聊内容重复落进业务库。 +- `系统` 和 `活动` 分区由后端 inbox 持久化,支持分页、未读、已读、删除、过期、撤回和跳转。 +- 消息事实必须按 `app_code` 和 `user_id` 隔离,不允许跨 App、跨用户读取或写入。 +- 消息事实必须在 MySQL,可用 Redis 做未读数短 TTL 缓存,但 Redis 不能作为恢复来源。 +- 后端外部入口统一在 `gateway-service`,响应使用 `/api/v1` envelope。 +- 生产者只发领域事件或内部消息命令,message inbox owner 负责模板快照、幂等、入箱和未读数。 + +## Non-Goals + +- 不实现自研 IM 长连接、单聊投递、离线漫游或私聊已读同步。腾讯云 IM 继续负责实时用户消息。 +- 不把房间群消息、公屏消息或房间系统消息复制到个人消息 tab。 +- 不把后台管理端 `admin_notifications` 复用给 App 用户。后台通知属于 `hyapp_admin`,App 消息属于 App 业务库。 +- 不允许客户端自报消息归属、未读数、系统消息内容、活动消息内容或目标用户。 +- 不在 `room-service`、`wallet-service`、`user-service` 内直接写用户 inbox 表;它们只通过 outbox/事件或内部 RPC 触发入箱。 + +## Current Implementation Snapshot + +| Capability | Status | Current Evidence | Gap | +| --- | --- | --- | --- | +| 腾讯云 IM 登录 | `DONE` | `gateway-service` 已有 `/api/v1/im/usersig` | App 侧会话列表仍需客户端 SDK 接入 | +| 用户资料批量查询 | `DONE` | `user-service.BatchGetUsers` + gateway `/api/v1/users/profiles:batch` | 仅返回 IM 会话展示字段 | +| activity-service 底座 | `DONE` | `ActivityService` + `MessageInboxService` 共用 gRPC 入口 | message inbox 事实 owner 已放在 activity-service | +| gateway 消息接口 | `DONE` | `/api/v1/messages/tabs`、列表、已读、read-all、删除 | gateway 只透传 JWT user_id 和 app_code | +| inbox MySQL 表 | `DONE` | `message_templates`、`user_inbox_messages`、`message_fanout_jobs` | MySQL 是 system/activity inbox 唯一事实来源 | +| 系统消息生产者 | `TODO` | wallet、room、user host domain 已有各自业务/outbox 方向 | 尚无统一 `CreateInboxMessage` 或 MQ consumer | +| 活动消息生产者 | `TODO` | activity-service 目前只有活动状态查询 | 需要活动上线、奖励、任务、运营触达入箱 | +| 未读数缓存 | `TODO` | 无 Redis key 设计落地 | 需要缓存失效和 fallback 统计 | +| 广播/fanout | `DONE` | `message_fanout_jobs` + `CreateFanoutJob` + activity fanout worker;region/country/all_active_users 通过 user-service `ListUserIDs` 游标取目标 | 还需要后台运营生产者接入 | + +这张表只描述当前仓库事实和缺口。后续实现必须先补 Redis 未读缓存和第一个领域生产者,不能让生产服务直接写 inbox 表。 + +## Message Sections + +| Section | Meaning | Source Of Truth | Backend Responsibility | +| --- | --- | --- | --- | +| `user` | 用户之间的单聊消息和会话 | Tencent IM SDK | 签发 UserSig、按需批量补用户资料 | +| `system` | 账号、钱包、房间、host/agency/bd、审核、提现等系统通知 | message inbox MySQL | 持久化、分页、未读、已读、删除、撤回 | +| `activity` | 活动上线、奖励、任务、运营触达 | message inbox MySQL, activity producer | 持久化、分页、未读、已读、删除、跳转参数 | + +`user` 分区在客户端通过腾讯云 IM SDK 拉取 conversation list。后端不能把用户私聊复制一份做列表,否则会引入隐私、合规、已读同步和消息一致性问题。 + +`system` 和 `activity` 分区使用同一套 inbox 表,通过 `message_type` 区分。活动服务或后台运营系统只生产消息事件,最终个人收件箱由 message inbox owner 落库。 + +## Service Boundary + +```mermaid +graph LR + Client["Client"] --> Gateway["gateway-service"] + Client --> TIM["Tencent IM SDK"] + + Gateway --> User["user-service"] + Gateway --> Message["message inbox owner\nactivity-service inbox module first"] + Gateway --> Activity["activity-service"] + + TIM --> TIMCloud["Tencent IM"] + + User --> UserDB[("hyapp_user")] + Message --> MessageDB[("hyapp_activity message tables")] + Activity --> ActivityDB[("hyapp_activity")] + + RoomOutbox[("room_outbox")] --> MQ["MQ / event bus"] + WalletOutbox[("wallet_outbox")] --> MQ + UserOutbox[("user/host outbox")] --> MQ + ActivityOutbox[("activity_outbox")] --> MQ + MQ --> Message + + Admin["hyapp-admin-server"] --> Message +``` + +首版把 `message inbox owner` 放在 `activity-service` 内的 inbox 模块,原因是当前已经有 `activity-service` 和 `hyapp_activity` 库,且活动通知天然需要 message fanout。后续如果系统/活动消息量、部署策略或权限模型明显独立,再拆为独立 `message-service`。 + +无论放在哪个进程,都必须遵守以下边界: + +- `gateway-service` 只做 HTTP 鉴权、协议转换、app_code 解析、内部 gRPC 编排,不保存 inbox 状态。 +- `activity-service inbox module` 是 `system/activity` 消息事实 owner,负责 MySQL 表、未读数、fanout job 和幂等。 +- `user-service` 只提供用户资料、区域、账号状态和批量查询,不承载消息内容。 +- `room-service` 只拥有房间状态和房间腾讯 IM 群消息,不直接写个人消息 tab。 +- `wallet-service` 只拥有账务事实,通过 wallet outbox 或内部事件触发系统通知。 +- `hyapp-admin-server` 只做后台入口、权限和审计;创建 App 消息时必须调用 message inbox owner,不能直接写业务表。 + +## Product Behavior + +### Tab Summary + +- App 打开消息 tab 时展示三块:`用户`、`系统`、`活动`。 +- `用户` 分区的标题、最近会话、未读数由腾讯云 IM SDK 返回。 +- 后端 `/api/v1/messages/tabs` 返回 `system/activity` 未读数,并明确 `user.source=tencent_im_sdk`。 +- App 总红点 = Tencent IM unread + backend system unread + backend activity unread。 + +### Message List + +- `system/activity` 列表按 `sent_at_ms DESC, inbox_message_id DESC` 排序。 +- 只展示当前 `app_code`、当前 `user_id`、`status=visible`、未删除、未过期的消息。 +- 列表项必须包含 title、summary、icon/image、action、read 状态、sent_at_ms。 +- `body` 用于详情或富文本,不要求首版做详情页;首版可以在列表响应里返回简短 body。 +- 客户端展示跳转动作时只能使用服务端白名单 action,不能执行任意 URL 或脚本。 + +### Read And Delete + +- 标记已读是用户侧状态变更,重复请求返回成功,不覆盖首次 `read_at_ms`。 +- 删除是用户侧隐藏,设置 `deleted_at_ms`,不物理删除事实行。 +- 删除未读消息后不再计入未读。 +- 过期消息不展示、不计入未读,但保留审计行。 +- 撤回消息不展示、不计入未读;撤回原因仅用于审计和后台排查。 + +## Data Model + +### Message Templates + +模板只保存服务端可控内容。App 展示标题、摘要、图标和跳转动作时,以消息实例 snapshot 为准,避免模板更新影响历史消息。 + +```sql +message_templates( + app_code VARCHAR(32) NOT NULL, + template_id VARCHAR(96) NOT NULL, + template_version VARCHAR(64) NOT NULL, + message_type VARCHAR(32) NOT NULL, + locale VARCHAR(32) NOT NULL DEFAULT '', + title VARCHAR(160) NOT NULL, + summary VARCHAR(512) NOT NULL, + body VARCHAR(2048) NOT NULL DEFAULT '', + icon_url VARCHAR(512) NOT NULL DEFAULT '', + image_url VARCHAR(512) NOT NULL DEFAULT '', + action_type VARCHAR(64) NOT NULL DEFAULT '', + action_param VARCHAR(1024) NOT NULL DEFAULT '', + status VARCHAR(32) NOT NULL, + created_by VARCHAR(64) NOT NULL DEFAULT '', + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, template_id, template_version), + KEY idx_message_templates_type_status (app_code, message_type, status), + KEY idx_message_templates_template_status (app_code, template_id, status) +); +``` + +字段规则: + +- `message_type` 只允许 `system` 或 `activity`。 +- `template_version` 必须进入消息实例 snapshot,避免模板修改影响历史消息。 +- `locale` 首版可以为空;后续多语言按 `app_code + template_id + template_version + locale` 选择。 +- `action_type` 必须是服务端白名单枚举,例如 `wallet_withdraw_detail`、`host_application_detail`、`activity_detail`、`room_detail`。 +- 模板可以被停用,但停用不影响已入箱消息展示。 + +### User Inbox + +```sql +user_inbox_messages( + app_code VARCHAR(32) NOT NULL, + inbox_message_id VARCHAR(96) NOT NULL, + user_id BIGINT NOT NULL, + message_type VARCHAR(32) NOT NULL, + producer VARCHAR(64) NOT NULL, + producer_event_id VARCHAR(128) NOT NULL, + producer_event_type VARCHAR(96) NOT NULL DEFAULT '', + aggregate_type VARCHAR(64) NOT NULL DEFAULT '', + aggregate_id VARCHAR(128) NOT NULL DEFAULT '', + template_id VARCHAR(96) NOT NULL DEFAULT '', + template_version VARCHAR(64) NOT NULL DEFAULT '', + title VARCHAR(160) NOT NULL, + summary VARCHAR(512) NOT NULL, + body VARCHAR(2048) NOT NULL DEFAULT '', + icon_url VARCHAR(512) NOT NULL DEFAULT '', + image_url VARCHAR(512) NOT NULL DEFAULT '', + action_type VARCHAR(64) NOT NULL DEFAULT '', + action_param VARCHAR(1024) NOT NULL DEFAULT '', + priority INT NOT NULL DEFAULT 0, + status VARCHAR(32) NOT NULL, + read_at_ms BIGINT NULL, + deleted_at_ms BIGINT NULL, + sent_at_ms BIGINT NOT NULL, + expire_at_ms BIGINT NULL, + metadata_json JSON NULL, + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, inbox_message_id), + UNIQUE KEY uk_user_inbox_producer_event (app_code, user_id, producer, producer_event_id), + KEY idx_user_inbox_list (app_code, user_id, message_type, deleted_at_ms, status, sent_at_ms, inbox_message_id), + KEY idx_user_inbox_unread (app_code, user_id, message_type, read_at_ms, deleted_at_ms, status, expire_at_ms), + KEY idx_user_inbox_aggregate (app_code, user_id, aggregate_type, aggregate_id) +); +``` + +字段规则: + +- `producer_event_id` 是入箱幂等键。钱包提现审核、host 申请、活动奖励等每个业务事件必须生成稳定 ID。 +- `producer_event_type` 保留源事件类型,方便排查和消费策略分流。 +- `aggregate_type/aggregate_id` 用于同一业务对象查询,例如 `withdraw_request/wd_01`、`host_application/ha_01`。 +- `status=visible` 才能被 App 列表看到。`recalled`、`hidden`、`expired` 不展示。 +- `deleted_at_ms` 是用户侧删除标记,不删除事实行。 +- `expire_at_ms` 只影响展示和未读,不影响审计。 +- `metadata_json` 只放低敏业务快照,不放支付凭证、手机号、证件号、provider receipt 或密钥。 + +### Fanout Jobs + +大范围活动消息不要在 HTTP 请求里同步 fanout。后台只创建任务,worker 分批写入,并记录进度和失败原因。 + +```sql +message_fanout_jobs( + app_code VARCHAR(32) NOT NULL, + job_id VARCHAR(96) NOT NULL, + command_id VARCHAR(128) NOT NULL, + message_type VARCHAR(32) NOT NULL, + target_scope VARCHAR(64) NOT NULL, + target_filter_json JSON NOT NULL, + template_snapshot_json JSON NOT NULL, + status VARCHAR(32) NOT NULL, + cursor_user_id BIGINT NOT NULL DEFAULT 0, + total_count BIGINT NOT NULL DEFAULT 0, + success_count BIGINT NOT NULL DEFAULT 0, + failure_count BIGINT NOT NULL DEFAULT 0, + batch_size INT NOT NULL DEFAULT 500, + next_run_at_ms BIGINT NOT NULL DEFAULT 0, + locked_by VARCHAR(96) NOT NULL DEFAULT '', + locked_until_ms BIGINT NOT NULL DEFAULT 0, + error_message VARCHAR(512) NOT NULL DEFAULT '', + created_by VARCHAR(64) NOT NULL, + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, job_id), + UNIQUE KEY uk_message_fanout_command (app_code, command_id), + KEY idx_message_fanout_status (app_code, status, next_run_at_ms, updated_at_ms) +); +``` + +`target_filter_json` 必须由后台服务端生成,不能直接信任客户端或运营前端提交的任意 SQL 条件。首版支持以下 scope: + +| Scope | Meaning | Target Source | +| --- | --- | --- | +| `single_user` | 单个用户消息 | request target_user_id | +| `user_ids` | 指定用户列表 | admin 上传或活动产出名单 | +| `region` | 区域活动、区域公告 | user-service `users.region_id` | +| `country` | 国家定向通知 | user-service `users.country` | +| `all_active_users` | 全 App 活跃用户 | user-service active users cursor | + +### Global Broadcast State + +如果全量公告需要“未读、已读、删除”语义,不能只保存一条公告定义后让客户端自行判断。可以二选一: + +- P0 方案:全量公告也通过 `message_fanout_jobs` 分批物化到 `user_inbox_messages`,实现简单,查询统一。 +- P1 方案:新增 `message_broadcasts` 和 `user_broadcast_states`,列表时合并个人 inbox 和广播定义,适合超大规模全量公告。 + +首版建议采用 P0 物化方案,避免 read-all、delete 和未读数出现两套语义。只有当全量 fanout 成本明显不可接受时,再实现 P1 懒加载模型。 + +### Unread Counter Cache + +未读数可以缓存,但缓存不是事实。 + +```text +message:unread:{app_code}:{user_id}:{message_type} +``` + +缓存规则: + +- cache miss 时从 `user_inbox_messages` 统计。 +- 入箱、已读、read-all、删除、撤回后删除或更新缓存。 +- 缓存 TTL 建议 30-120 秒,防止缓存失效遗漏导致长期错误。 +- 未读数不得由客户端上报覆盖。 + +## Internal RPC Surface + +首版建议在 `api/proto/activity/v1` 追加 message inbox RPC,或者单独新增 `api/proto/message/v1`。如果实现仍放在 `activity-service`,可以先追加到 activity proto,但命名必须保持 message inbox 边界。 + +```proto +service MessageInboxService { + rpc ListMessageTabs(ListMessageTabsRequest) returns (ListMessageTabsResponse); + rpc ListInboxMessages(ListInboxMessagesRequest) returns (ListInboxMessagesResponse); + rpc MarkInboxMessageRead(MarkInboxMessageReadRequest) returns (MarkInboxMessageReadResponse); + rpc MarkInboxSectionRead(MarkInboxSectionReadRequest) returns (MarkInboxSectionReadResponse); + rpc DeleteInboxMessage(DeleteInboxMessageRequest) returns (DeleteInboxMessageResponse); + rpc CreateInboxMessage(CreateInboxMessageRequest) returns (CreateInboxMessageResponse); + rpc CreateFanoutJob(CreateFanoutJobRequest) returns (CreateFanoutJobResponse); +} +``` + +RPC 要求: + +- 所有请求必须携带 `RequestMeta.app_code` 和 `request_id`。 +- App 用户读写请求必须携带 `user_id`,并由 gateway 使用 JWT 中的用户 ID 填充。 +- `CreateInboxMessage` 必须携带 `producer`、`producer_event_id`、`message_type`、`target_user_id`、内容 snapshot 或 template 引用。 +- `CreateFanoutJob` 必须携带后台 `command_id`,同 command 重试返回原 job。 +- 查询接口不需要 `command_id`,但必须透传 `request_id` 用于追踪。 +- 修改 proto 后必须运行 `make proto`,并提交生成后的 `.pb.go` / `_grpc.pb.go`。 + +## App API Surface + +所有接口都由 `gateway-service` 暴露,使用 `/api/v1` envelope:`{code,message,request_id,data}`。`app_code` 来自 gateway 的 App 解析或 JWT,不接受客户端 body 自报。 + +### Tab Summary + +```http +GET /api/v1/messages/tabs +``` + +Response data: + +```json +{ + "sections": [ + { + "section": "user", + "title": "用户", + "unread_count": 0, + "source": "tencent_im_sdk" + }, + { + "section": "system", + "title": "系统", + "unread_count": 2, + "source": "backend" + }, + { + "section": "activity", + "title": "活动", + "unread_count": 1, + "source": "backend" + } + ] +} +``` + +`user.unread_count` 推荐由客户端腾讯云 IM SDK 直接提供。后端返回 `source=tencent_im_sdk`,提醒客户端不要等待后端私聊列表。 + +### System And Activity List + +```http +GET /api/v1/messages?section=system&page_size=20&page_token= +GET /api/v1/messages?section=activity&page_size=20&page_token= +``` + +Response data: + +```json +{ + "section": "system", + "items": [ + { + "message_id": "msg_01", + "title": "提现审核通过", + "summary": "你的提现申请已通过,请等待人工转账。", + "body": "", + "icon_url": "", + "image_url": "", + "action_type": "wallet_withdraw_detail", + "action_param": "withdrawal_id=wd_01", + "read": false, + "sent_at_ms": 1777996800000 + } + ], + "next_page_token": "" +} +``` + +分页使用 `(sent_at_ms, inbox_message_id)` 游标。不要使用 offset,大用户消息量上来后 offset 翻页会越来越慢且容易重复或漏项。 + +### Mark Read + +```http +POST /api/v1/messages/{message_id}/read +POST /api/v1/messages/read-all +``` + +`read-all` body: + +```json +{ + "section": "system" +} +``` + +已读接口必须幂等:重复标记已读返回成功,不改变 `read_at_ms` 的首次已读时间。`read-all` 只影响当前 `app_code/user_id/section` 下未删除、未过期、visible 的消息。 + +### Delete + +```http +DELETE /api/v1/messages/{message_id} +``` + +删除是用户侧隐藏,设置 `deleted_at_ms`。已经删除的消息不进入列表,也不计入未读。删除不存在或不属于当前用户的消息应返回 `NOT_FOUND`,不能泄露其他用户消息是否存在。 + +### User Message Section + +用户消息列表由客户端腾讯云 IM SDK 获取: + +```text +Tencent IM SDK getConversationList() +``` + +后端只补充两个能力: + +- `GET /api/v1/im/usersig`:已有,给客户端登录腾讯云 IM。 +- `GET /api/v1/users/profiles:batch?user_ids=...`:后续可新增,用于会话列表头像、昵称、短号批量补全。底层复用 `user-service.BatchGetUsers`。 + +`profiles:batch` 只返回展示字段:`user_id`、`display_user_id`、`username`、`avatar`、`gender`、`country`、`region_id`、`app_code`。不能返回手机号、登录凭证、实名信息或后台身份详情。 + +## Producer Rules + +系统消息生产者: + +| Producer | Event | Section | Target | +| --- | --- | --- | --- | +| `wallet-service` | 充值到账、提现审核、提现失败、提现打款完成 | `system` | affected user | +| `user-service` | 登录安全、账号状态、资料审核、host/agency/bd 申请结果 | `system` | affected user | +| `room-service` | 被踢、被禁言、被解除 ban 等个人强相关通知 | `system` | affected user | +| `activity-service` | 活动奖励、任务完成、排行榜奖励 | `activity` | affected user | +| `hyapp-admin-server` | 定向运营通知、全量公告、区域活动通知 | `activity` | selected users | + +生产规则: + +- 生产者只发领域事件或调用内部 `CreateInboxMessage`,不能直接写 `user_inbox_messages`。 +- 每个生产者事件必须提供稳定 `producer_event_id`,重复消费只能生成一条 inbox。 +- 房间公屏、房间礼物、麦位变更等群内事件仍走腾讯云 IM 群,不进入个人消息 tab。 +- `room-service` 只有个人强相关的管理结果才进入消息 tab,例如被踢出房间、被禁言;这类消息不替代房间 IM 系统消息。 +- 钱包消息必须以 wallet 交易或提现单状态为事实来源,不能由 gateway 根据接口返回自行拼通知。 +- 后台运营通知必须经过 admin 权限和审计,最终由 message inbox owner 入箱。 + +## Event To Inbox Flow + +```mermaid +sequenceDiagram + participant P as Producer Service + participant O as Producer Outbox + participant M as MQ / Consumer + participant I as Message Inbox Owner + participant DB as message MySQL + participant R as Redis + + P->>O: commit domain fact + outbox + M->>O: poll or consume event + M->>I: CreateInboxMessage(producer_event_id) + I->>DB: insert user_inbox_messages with unique key + I->>R: invalidate unread cache + I-->>M: idempotent result +``` + +一致性要求: + +- 生产者业务事实提交不能依赖消息入箱成功。 +- 入箱失败由生产者 outbox 或 MQ consumer 重试。 +- message inbox owner 以唯一键保证重复消费不重复发消息。 +- 如果模板不存在或已停用,消费者应进入 retry 或 dead-letter,并告警;不能生成空标题消息。 +- 如果目标用户不存在、跨 app 或已注销,按业务策略记录 skipped,不应无限重试。 + +## Broadcast And Fanout + +消息分发分三种: + +| Mode | Use Case | Rule | +| --- | --- | --- | +| `single_user` | 提现审核、申请结果、个人奖励 | 直接写一条 inbox | +| `user_group` | 区域活动、主播群体通知、指定用户列表 | 创建 fanout job,分批写 inbox | +| `global` | 全 App 公告 | 首版仍建议 fanout 物化;超大规模后再做 broadcast lazy state | + +Fanout worker 要求: + +- 每轮锁定一批待执行 job,使用 `locked_by/locked_until_ms` 防止多实例重复处理。 +- 按 `cursor_user_id` 分页查询目标用户,不使用 offset。 +- 每个目标用户的 `producer_event_id` 必须稳定,例如 `fanout:{job_id}:{user_id}`。 +- 单批失败不能让整个 job 丢失,记录 `failure_count/error_message` 并继续或进入 retry。 +- 目标范围按区域/国家选择时,使用 user-service 当前主数据;是否需要冻结目标用户快照由具体活动决定。 +- 大型 fanout 配置必须支持 `poll_interval`、`batch_size`、`max_retry`、`lock_ttl`。 + +## Read Consistency + +- 用户消息的已读、未读和最后一条消息以腾讯云 IM 为准。 +- 系统和活动消息的已读、未读以 `user_inbox_messages` 为准。 +- App tab 总红点 = IM SDK unread + backend system unread + backend activity unread。 +- 后端不接收客户端上报的 IM unread 作为事实,只能作为埋点或调试信息。 +- `read-all` 和删除成功后,必须清理对应 section 的 Redis 未读缓存。 +- 列表接口如果读到 Redis 未读数和 MySQL 列表状态短暂不一致,以 MySQL 为最终事实。 + +## Error Semantics + +| Error | Meaning | HTTP Mapping | +| --- | --- | --- | +| `INVALID_SECTION` | section 不是 `system/activity` | 400 | +| `MESSAGE_NOT_FOUND` | 消息不存在、已删除或不属于当前用户 | 404 | +| `MESSAGE_RECALLED` | 消息已撤回,不允许展示或操作 | 404 | +| `PAGE_TOKEN_INVALID` | 游标无法解析或不属于当前查询 | 400 | +| `REQUEST_CONFLICT` | 同 command_id/fanout job 不同 payload | 409 | +| `PRODUCER_EVENT_CONFLICT` | 同 producer_event_id 不同 payload | 409 | +| `MESSAGE_INTERNAL` | DB、缓存或内部未知错误 | 500 | + +`request_id` 只做链路追踪,不作为消息入箱幂等键。入箱幂等键必须是 `producer_event_id` 或后台 `command_id`。 + +## Security And Privacy + +- `app_code` 由 gateway 解析或 token 携带,不接受客户端 body 覆盖。 +- `user_id` 由 JWT 提供,读写接口不能让客户端指定目标用户。 +- 后台创建消息必须通过 admin 鉴权和审计,审计留在 `hyapp_admin`。 +- `action_param` 必须是白名单动作参数,不允许任意外链、脚本、内嵌 HTML。 +- 消息 title/summary/body 不得包含支付凭证、provider receipt、敏感证件、完整手机号或密钥。 +- 用户删除消息只影响自己,不影响其他用户和后台审计。 +- 用户私聊内容不进入后端业务库,不出现在系统/活动消息搜索里。 + +## Configuration + +首版实现需要在 `activity-service` 增加 message inbox 配置,并同步本地 `config.yaml`、Docker `config.docker.yaml`、线上 `config.tencent.example.yaml`: + +```yaml +message_inbox: + unread_cache_ttl: 60s + fanout_worker: + enabled: true + poll_interval: 1s + batch_size: 500 + lock_ttl: 30s + max_retry: 8 +``` + +如果消息 owner 后续拆成独立 `message-service`,这些配置迁移到新服务;gateway 只需要更新 message gRPC 地址。 + +## Implementation Order + +1. 追加 proto:新增 `MessageInboxService`、消息列表、未读、已读、删除、创建入箱、fanout job RPC。 +2. 更新 `activity-service` MySQL initdb:新增 `message_templates`、`user_inbox_messages`、`message_fanout_jobs`。 +3. 在 `activity-service` 增加 inbox domain/repository/service,先实现单用户入箱、列表、未读、已读、删除。 +4. 在 `gateway-service` 增加 activity/message client 和 App HTTP:`/api/v1/messages/tabs`、`/api/v1/messages`、`/api/v1/messages/{id}/read`、`/api/v1/messages/read-all`、`DELETE /api/v1/messages/{id}`。 +5. 接入第一个系统生产者,建议从提现审核或 host 申请结果开始,因为它们天然是单用户消息。 +6. 增加 fanout job 和 worker,先支持 `region`、`country`、`user_ids`、`all_active_users`。 +7. 增加 `/api/v1/users/profiles:batch`,给腾讯云 IM 用户会话列表补头像、昵称、短号。 +8. 增加 Redis 未读数缓存和缓存失效逻辑。 +9. 补 OpenAPI 文档、Docker 配置、线上配置示例和端到端冒烟脚本。 + +## Verification Matrix + +| Scenario | Expected | +| --- | --- | +| 打开消息 tab | 返回 `user/system/activity` 三个分区 | +| `user` 分区 | response 标记 `source=tencent_im_sdk`,不返回私聊内容 | +| 拉系统消息列表 | 只返回当前 `app_code`、当前用户、未删除、未过期、visible 的 system 消息 | +| 拉活动消息列表 | 只返回当前 `app_code`、当前用户、未删除、未过期、visible 的 activity 消息 | +| 重复消费同一 producer event | 只生成一条 inbox 消息 | +| 同 producer event 不同 payload | 返回或记录冲突,不覆盖原消息 | +| 标记已读重复请求 | 返回成功,`read_at_ms` 不被覆盖,未读数不变成负数 | +| read-all | 当前 section 未读全部归零,其他 section 不受影响 | +| 删除未读消息 | 消息不再展示,未读数减少 | +| 删除其他用户消息 | 返回 `NOT_FOUND` | +| 过期消息 | 不展示、不计入未读,但数据库事实保留 | +| 全量活动通知 | fanout job 分批写入,不阻塞 Admin HTTP 请求 | +| 区域活动通知 | 只给当前 app 下目标 region 用户入箱 | +| 用户私聊会话 | App 从腾讯云 IM SDK 获取,后端不返回私聊内容 | +| Redis unread cache miss | 从 MySQL 统计后回填缓存 | + +## Test And Release Requirements + +涉及 proto 时运行: + +```bash +make proto +go test ./... +``` + +涉及 DB、配置、Docker 时运行: + +```bash +docker compose config +docker compose build +``` + +涉及启动链路时实际拉起: + +```bash +docker compose up -d +docker compose ps +docker compose down +``` + +最小测试覆盖: + +- activity-service inbox repository 单元/集成测试:幂等、分页、未读、已读、删除、过期。 +- gateway transport 测试:JWT 用户 ID 生效、app_code 透传、envelope、错误映射。 +- fanout worker 测试:锁 job、分页、重复 target 幂等、失败重试。 +- producer consumer 测试:同 event 重复消费只入箱一次。 +- profiles batch 测试:只返回安全展示字段。 + +## Critical Rules + +- `user` 分区不落业务库,不复制腾讯云 IM 私聊内容。 +- `system` 和 `activity` 必须持久化到 MySQL,不能只靠 Redis 或推送。 +- 所有 inbox 事实必须带 `app_code`。 +- 已读和删除必须幂等。 +- 大范围活动消息必须异步 fanout。 +- 房间群消息仍走腾讯云 IM 群,不进入个人消息 tab。 +- `request_id` 只做追踪,不做幂等。 +- 后台运营消息必须有 admin 鉴权和审计。 +- 生产者不能直接写 inbox 表,只能发事件或调用 message inbox owner。 diff --git a/docs/my-page-overview-api.md b/docs/my-page-overview-api.md new file mode 100644 index 00000000..01b48fa6 --- /dev/null +++ b/docs/my-page-overview-api.md @@ -0,0 +1,296 @@ +# My Page Overview API + +本文定义 App 底部 `我的` 页首屏聚合接口。该接口只返回首屏渲染需要的轻量摘要:用户资料、核心资产余额、身份开关、消息红点和入口显隐。流水、成员列表、背包完整列表、工资明细和团队统计必须放到二级页接口。 + +## Goals + +- `我的` 页首屏一次请求拿到稳定摘要,减少 App 冷启动后的接口数量。 +- 聚合已有轻量能力:`/users/me`、`/wallet/me/balances`、`/users/me/host-identity`、`/messages/tabs`。 +- 避免实时 `COUNT(*)`、扫流水、扫成员、扫背包、现算工资。 +- 后端控制入口显隐,App 不硬编码复杂身份组合。 +- 所有数据按 `app_code` 和当前 JWT `user_id` 隔离。 + +## Endpoint + +```http +GET /api/v1/users/me/overview +Authorization: Bearer +``` + +响应仍使用 gateway `/api/v1` envelope: + +```json +{ + "code": "OK", + "message": "ok", + "request_id": "req_01", + "data": { + "profile": {}, + "wallet": {}, + "roles": {}, + "badges": {}, + "entries": [], + "server_time_ms": 1777996800000 + } +} +``` + +## Response Shape + +```json +{ + "profile": { + "user_id": "10001", + "display_user_id": "163000", + "default_display_user_id": "163000", + "display_user_id_kind": "default", + "display_user_id_expires_at_ms": 0, + "username": "Alice", + "avatar": "https://cdn.example.com/avatar.png", + "gender": "female", + "birth": "2000-01-01", + "country": "US", + "country_id": 1, + "country_name": "United States", + "country_display_name": "United States", + "region_id": 10, + "region_code": "north_america", + "region_name": "North America", + "language": "en", + "profile_completed": true, + "onboarding_status": "completed" + }, + "wallet": { + "balances": [ + { + "asset_type": "COIN", + "available_amount": 12000, + "frozen_amount": 0, + "version": 8 + }, + { + "asset_type": "DIAMOND", + "available_amount": 300, + "frozen_amount": 0, + "version": 3 + }, + { + "asset_type": "USD_BALANCE", + "available_amount": 2500, + "frozen_amount": 500, + "version": 2 + } + ], + "recharge_enabled": true, + "diamond_exchange_enabled": true, + "withdraw_enabled": true + }, + "roles": { + "is_host": true, + "is_agent": false, + "is_bd": false, + "is_bd_leader": false, + "is_coin_seller": false + }, + "badges": { + "unread_system_messages": 2, + "unread_activity_messages": 1, + "pending_role_invitations": 0 + }, + "entries": [ + { + "key": "wallet", + "title": "Wallet", + "visible": true, + "badge_count": 0 + }, + { + "key": "host_center", + "title": "Host Center", + "visible": true, + "badge_count": 0 + }, + { + "key": "coin_seller_center", + "title": "Coin Seller", + "visible": false, + "badge_count": 0 + }, + { + "key": "backpack", + "title": "Backpack", + "visible": true, + "badge_count": 0 + }, + { + "key": "settings", + "title": "Settings", + "visible": true, + "badge_count": 0 + } + ], + "server_time_ms": 1777996800000 +} +``` + +## Field Sources + +| Field | Source | Query Pattern | +| --- | --- | --- | +| `profile` | `user-service.GetUser` | single row by `(app_code, user_id)` | +| `wallet.balances` | `wallet-service.GetBalances` | point read for `COIN`、`DIAMOND`、`USD_BALANCE` | +| `roles` | `user-service` host identity module | point read role facts or future role summary read model | +| `badges.unread_*` | message inbox owner | counter/read model, not message list scan | +| `entries` | gateway composition rules | computed from `roles` and feature flags | +| `server_time_ms` | gateway | current server clock | + +当前实现已有 `/users/me`、`/wallet/me/balances`、`/users/me/host-identity`、`/messages/tabs`。`/users/me/overview` 可以先在 `gateway-service` 聚合这些能力;后续如果角色判断的三次 not-found RPC 变慢,再在 `user-service` 增加 `GetUserRoleSummary` 内部 RPC。 + +## Asset Rules + +首屏只返回三类资产: + +| Asset | Show Rule | +| --- | --- | +| `COIN` | 所有用户展示 | +| `DIAMOND` | 所有用户展示,但文案不能暗示可直接消费 | +| `USD_BALANCE` | 有余额、冻结金额、host/agent/bd/coin_seller 身份时展示 | + +不要返回 `GIFT_POINT`。积分是后台工资/活动计算输入,不是普通用户钱包可直接操作资产。 + +## Entry Rules + +入口显隐由后端返回,App 只负责渲染。 + +| Entry Key | Visible Rule | +| --- | --- | +| `wallet` | always true | +| `host_center` | `roles.is_host == true` | +| `apply_host` | `roles.is_host == false` | +| `agency_center` | `roles.is_agent == true` | +| `bd_center` | `roles.is_bd == true` | +| `bd_leader_center` | `roles.is_bd_leader == true` | +| `coin_seller_center` | `roles.is_coin_seller == true` | +| `backpack` | always true | +| `settings` | always true | +| `support` | always true | + +同一个用户可能同时是 BD 和 host。不要用互斥枚举表达角色,必须使用 bool flags。 + +## Expensive Fields To Exclude + +这些字段不要放进首屏 overview: + +| Field | Reason | Replacement | +| --- | --- | --- | +| `period_mic_minutes` | 需要统计聚合,可能扫 stats | Host Center 二级页 | +| `period_gift_points` | 需要统计聚合,可能跨日汇总 | Host Center 二级页 | +| `estimated_earning_usd_minor` | 不能首屏现算工资 | 后台工资 read model 或收益页 | +| `agency_member_count` | 容易 `COUNT(*)` members | Agency Center 二级页或 summary table | +| `bd_host_count` | 团队规模统计昂贵 | BD Center 二级页或 summary table | +| `pending_withdrawals` | 扫提现/流水表 | wallet badge counter | +| `recharge_count` | 扫充值记录 | wallet 二级页 | +| `resource_count` | 扫背包权益表 | backpack 二级页 | +| `latest_transactions` | 扫交易流水 | wallet 二级页 | +| `inbox_items` | 扫消息列表 | messages 二级页 | + +首屏接口禁止为了红点实时扫大表。需要红点就维护 counter/read model;没有 counter 时先不展示该红点。 + +## Performance Budget + +目标: + +- P95 backend latency: `< 120ms` in normal region deployment. +- Gateway fanout RPC count: max 4. +- No list scan. +- No transaction history query. +- No member `COUNT(*)`. +- No resource entitlement list. +- No salary calculation. + +推荐并行 fanout: + +```mermaid +sequenceDiagram + participant C as Client + participant G as gateway-service + participant U as user-service + participant W as wallet-service + participant M as message inbox owner + + C->>G: GET /api/v1/users/me/overview + par profile and roles + G->>U: GetUser(user_id) + G->>U: GetUserRoleSummary(user_id) + and wallet + G->>W: GetBalances(COIN, DIAMOND, USD_BALANCE) + and badges + G->>M: ListMessageTabs(user_id) + end + G->>G: compose entries and feature flags + G-->>C: overview +``` + +MVP 可以复用已有 `GetHostProfile`、`GetBDProfile`、`GetCoinSellerProfile` 聚合角色;优化版应增加单个 `GetUserRoleSummary`,减少 not-found RPC 和错误映射成本。 + +## Degraded Responses + +首屏接口可以部分降级,但必须清楚标记。 + +| Upstream Failure | Response Rule | +| --- | --- | +| `user-service.GetUser` fail | 整体失败,资料是首屏主数据 | +| `wallet-service.GetBalances` fail | 返回空 balances,并加 `wallet.unavailable=true` | +| role summary fail | 返回 all false,并加 `roles.unavailable=true`,不要误展示特权入口 | +| message tabs fail | unread 置 0,并加 `badges.unavailable=true` | + +如果某个上游超时,gateway 不应无限等待。overview 是首屏接口,应该有比普通操作接口更短的聚合超时预算。 + +## HTTP Handler Shape + +新增路由: + +```go +mux.Handle(apiV1Prefix+"/users/me/overview", h.profileAPIHandler(jwtVerifier, h.getMyOverview)) +``` + +handler 只做协议聚合: + +1. 从 JWT context 取 `user_id` 和 `app_code`。 +2. 并行请求 profile、balances、roles、message tabs。 +3. 把资产补齐为固定三类,缺失资产返回 0。 +4. 根据 roles 和 feature flags 生成 entries。 +5. 返回 envelope data。 + +不要在 gateway 写 SQL,也不要在 gateway 做工资、成员、资源统计。 + +## Verification Matrix + +| Scenario | Expected | +| --- | --- | +| 普通用户打开我的页 | 返回 profile、COIN/DIAMOND/USD_BALANCE、普通入口 | +| host 打开我的页 | `roles.is_host=true`,展示 `host_center` | +| BD Leader 打开我的页 | `is_bd=true` 且 `is_bd_leader=true`,展示 leader 入口 | +| 币商打开我的页 | `is_coin_seller=true`,展示 coin seller 入口 | +| 钱包没有账户行 | 三类资产都返回 0 投影 | +| 消息服务失败 | 我的页仍可展示,消息红点降级为 0 | +| 用户资料服务失败 | overview 整体失败 | +| 大量成员/流水存在 | overview 延迟不受影响,因为不查成员和流水 | + +## Implementation Order + +1. 新增本文档,确认字段边界和慢查询排除规则。 +2. 在 `gateway-service` 增加 `GET /api/v1/users/me/overview` handler。 +3. 复用现有 `GetUser`、`GetBalances`、`GetHostProfile/GetBDProfile/GetCoinSellerProfile`、`ListMessageTabs`。 +4. 增加 handler 单元测试,覆盖普通用户、host、BD Leader、币商、钱包缺失、消息降级。 +5. 如果角色 RPC 成本偏高,再在 `user-service` 增加 `GetUserRoleSummary`。 +6. 如果红点需要更多类型,先补 counter/read model,再把 badge 加进 overview。 + +## Critical Rules + +- `我的` 页 overview 是轻聚合接口,不是用户全量详情接口。 +- 首屏不做 `COUNT(*)`、不扫流水、不扫成员、不查完整背包、不现算工资。 +- 钱包余额以 `wallet-service` 为准。 +- 用户资料以 `user-service` 为准。 +- 角色入口以服务端返回的 `roles` 和 `entries` 为准。 +- 消息红点以 message inbox counter/read model 为准,用户私聊未读仍以腾讯云 IM SDK 为准。 diff --git a/docs/openapi/activity.swagger.yaml b/docs/openapi/activity.swagger.yaml index 03f4ae1c..4594f574 100644 --- a/docs/openapi/activity.swagger.yaml +++ b/docs/openapi/activity.swagger.yaml @@ -17,6 +17,8 @@ produces: tags: - name: activity description: ActivityService,活动服务同步查询接口。 + - name: messages + description: MessageInboxService,App system/activity 个人 inbox 内部接口。 - name: health description: 标准 grpc.health.v1.Health。 responses: @@ -65,6 +67,146 @@ paths: $ref: "#/definitions/GetActivityStatusResponse" default: $ref: "#/responses/GRPCError" + /hyapp.activity.v1.MessageInboxService/ListMessageTabs: + post: + tags: + - messages + summary: 查询 App 消息 tab 摘要 + operationId: activityListMessageTabs + x-grpc-full-method: /hyapp.activity.v1.MessageInboxService/ListMessageTabs + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/ListMessageTabsRequest" + responses: + "200": + description: 固定返回 user/system/activity 三个分区。 + schema: + $ref: "#/definitions/ListMessageTabsResponse" + default: + $ref: "#/responses/GRPCError" + /hyapp.activity.v1.MessageInboxService/ListInboxMessages: + post: + tags: + - messages + summary: 分页查询 system/activity inbox + operationId: activityListInboxMessages + x-grpc-full-method: /hyapp.activity.v1.MessageInboxService/ListInboxMessages + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/ListInboxMessagesRequest" + responses: + "200": + description: 返回当前页消息和下一页游标。 + schema: + $ref: "#/definitions/ListInboxMessagesResponse" + default: + $ref: "#/responses/GRPCError" + /hyapp.activity.v1.MessageInboxService/MarkInboxMessageRead: + post: + tags: + - messages + summary: 标记单条 inbox 消息已读 + operationId: activityMarkInboxMessageRead + x-grpc-full-method: /hyapp.activity.v1.MessageInboxService/MarkInboxMessageRead + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/MarkInboxMessageReadRequest" + responses: + "200": + description: 重复标记成功且不覆盖首次 read_at_ms。 + schema: + $ref: "#/definitions/MarkInboxMessageReadResponse" + default: + $ref: "#/responses/GRPCError" + /hyapp.activity.v1.MessageInboxService/MarkInboxSectionRead: + post: + tags: + - messages + summary: 标记一个消息分区全部已读 + operationId: activityMarkInboxSectionRead + x-grpc-full-method: /hyapp.activity.v1.MessageInboxService/MarkInboxSectionRead + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/MarkInboxSectionReadRequest" + responses: + "200": + description: 返回本次实际更新的消息数。 + schema: + $ref: "#/definitions/MarkInboxSectionReadResponse" + default: + $ref: "#/responses/GRPCError" + /hyapp.activity.v1.MessageInboxService/DeleteInboxMessage: + post: + tags: + - messages + summary: 删除当前用户可见 inbox 消息 + operationId: activityDeleteInboxMessage + x-grpc-full-method: /hyapp.activity.v1.MessageInboxService/DeleteInboxMessage + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/DeleteInboxMessageRequest" + responses: + "200": + description: 删除是用户侧隐藏,不物理删除事实行。 + schema: + $ref: "#/definitions/DeleteInboxMessageResponse" + default: + $ref: "#/responses/GRPCError" + /hyapp.activity.v1.MessageInboxService/CreateInboxMessage: + post: + tags: + - messages + summary: 生产者创建单用户 inbox 消息 + operationId: activityCreateInboxMessage + x-grpc-full-method: /hyapp.activity.v1.MessageInboxService/CreateInboxMessage + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/CreateInboxMessageRequest" + responses: + "200": + description: 同 producer_event_id 重试返回原 message_id。 + schema: + $ref: "#/definitions/CreateInboxMessageResponse" + default: + $ref: "#/responses/GRPCError" + /hyapp.activity.v1.MessageInboxService/CreateFanoutJob: + post: + tags: + - messages + summary: 创建后台 fanout 任务 + operationId: activityCreateFanoutJob + x-grpc-full-method: /hyapp.activity.v1.MessageInboxService/CreateFanoutJob + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/CreateFanoutJobRequest" + responses: + "200": + description: 同 command_id 重试返回原 job_id。 + schema: + $ref: "#/definitions/CreateFanoutJobResponse" + default: + $ref: "#/responses/GRPCError" /grpc.health.v1.Health/Check: post: tags: @@ -119,6 +261,9 @@ definitions: sent_at_ms: type: integer format: int64 + app_code: + type: string + description: 调用方解析出的 App 租户键,所有 inbox 事实必须按该字段隔离。 PingActivityRequest: type: object properties: @@ -148,6 +293,280 @@ definitions: status: type: string description: 当前活动状态;具体业务活动会扩展自己的状态枚举。 + MessageTabSection: + type: object + properties: + section: + type: string + enum: + - user + - system + - activity + title: + type: string + unread_count: + type: integer + format: int64 + source: + type: string + enum: + - tencent_im_sdk + - backend + ListMessageTabsRequest: + type: object + required: + - user_id + properties: + meta: + $ref: "#/definitions/RequestMeta" + user_id: + type: integer + format: int64 + ListMessageTabsResponse: + type: object + properties: + sections: + type: array + items: + $ref: "#/definitions/MessageTabSection" + InboxMessage: + type: object + properties: + message_id: + type: string + section: + type: string + enum: + - system + - activity + title: + type: string + summary: + type: string + body: + type: string + icon_url: + type: string + image_url: + type: string + action_type: + type: string + action_param: + type: string + read: + type: boolean + sent_at_ms: + type: integer + format: int64 + ListInboxMessagesRequest: + type: object + required: + - user_id + - section + properties: + meta: + $ref: "#/definitions/RequestMeta" + user_id: + type: integer + format: int64 + section: + type: string + enum: + - system + - activity + page_size: + type: integer + format: int32 + page_token: + type: string + ListInboxMessagesResponse: + type: object + properties: + section: + type: string + items: + type: array + items: + $ref: "#/definitions/InboxMessage" + next_page_token: + type: string + MarkInboxMessageReadRequest: + type: object + required: + - user_id + - message_id + properties: + meta: + $ref: "#/definitions/RequestMeta" + user_id: + type: integer + format: int64 + message_id: + type: string + MarkInboxMessageReadResponse: + type: object + properties: + message_id: + type: string + read: + type: boolean + read_at_ms: + type: integer + format: int64 + MarkInboxSectionReadRequest: + type: object + required: + - user_id + - section + properties: + meta: + $ref: "#/definitions/RequestMeta" + user_id: + type: integer + format: int64 + section: + type: string + enum: + - system + - activity + MarkInboxSectionReadResponse: + type: object + properties: + section: + type: string + read_count: + type: integer + format: int64 + DeleteInboxMessageRequest: + type: object + required: + - user_id + - message_id + properties: + meta: + $ref: "#/definitions/RequestMeta" + user_id: + type: integer + format: int64 + message_id: + type: string + DeleteInboxMessageResponse: + type: object + properties: + message_id: + type: string + deleted: + type: boolean + CreateInboxMessageRequest: + type: object + required: + - target_user_id + - producer + - producer_event_id + - message_type + properties: + meta: + $ref: "#/definitions/RequestMeta" + target_user_id: + type: integer + format: int64 + producer: + type: string + producer_event_id: + type: string + producer_event_type: + type: string + message_type: + type: string + enum: + - system + - activity + aggregate_type: + type: string + aggregate_id: + type: string + template_id: + type: string + template_version: + type: string + title: + type: string + summary: + type: string + body: + type: string + icon_url: + type: string + image_url: + type: string + action_type: + type: string + action_param: + type: string + priority: + type: integer + format: int32 + sent_at_ms: + type: integer + format: int64 + expire_at_ms: + type: integer + format: int64 + metadata_json: + type: string + description: 低敏业务快照 JSON 字符串。 + CreateInboxMessageResponse: + type: object + properties: + message_id: + type: string + created: + type: boolean + CreateFanoutJobRequest: + type: object + required: + - command_id + - message_type + - target_scope + - target_filter_json + - template_snapshot_json + - created_by + properties: + meta: + $ref: "#/definitions/RequestMeta" + command_id: + type: string + message_type: + type: string + enum: + - system + - activity + target_scope: + type: string + enum: + - single_user + - user_ids + - region + - country + - all_active_users + target_filter_json: + type: string + template_snapshot_json: + type: string + batch_size: + type: integer + format: int32 + created_by: + type: string + CreateFanoutJobResponse: + type: object + properties: + job_id: + type: string + status: + type: string + created: + type: boolean HealthCheckRequest: type: object properties: diff --git a/docs/openapi/gateway.swagger.yaml b/docs/openapi/gateway.swagger.yaml index 0282f05f..350dcfd7 100644 --- a/docs/openapi/gateway.swagger.yaml +++ b/docs/openapi/gateway.swagger.yaml @@ -31,12 +31,16 @@ tags: description: App 注册页国家选择公开读接口。 - name: app-config description: App 运行时配置公开读接口。 + - name: devices + description: App 设备推送 token 绑定和失效。 - name: rooms description: 房间命令入口,最终由 room-service 执行。 - name: wallet description: App 钱包余额、币商转账和充值口径入口。 - name: resources description: App 资源库、资源组、礼物配置和我的资源入口。 + - name: messages + description: App 消息 tab,后端只负责 system/activity inbox,用户私聊来自腾讯云 IM SDK。 securityDefinitions: BearerAuth: type: apiKey @@ -330,6 +334,20 @@ paths: $ref: "#/definitions/CountryListEnvelope" "502": $ref: "#/responses/UpstreamError" + /api/v1/app/bootstrap: + get: + tags: + - app-config + summary: 获取 App 启动配置摘要 + operationId: getAppBootstrap + description: 公开读接口,只返回版本、维护、feature flags、底部 tab 和配置版本号,不返回 banner、礼物或资源大列表。 + parameters: + - $ref: "#/parameters/RequestIDHeader" + responses: + "200": + description: 查询成功,`data` 返回 App 启动状态机需要的轻量配置摘要。 + schema: + $ref: "#/definitions/AppBootstrapEnvelope" /api/v1/app/h5-links: get: tags: @@ -508,6 +526,63 @@ paths: $ref: "#/responses/Unauthorized" "502": $ref: "#/responses/UpstreamError" + /api/v1/devices/push-token: + post: + tags: + - devices + summary: 绑定设备推送 token + operationId: bindPushToken + description: 资料完成后由客户端上报系统推送 token;gateway 只使用 access token 中的用户身份,user-service 负责落库。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: body + in: body + required: true + schema: + $ref: "#/definitions/BindPushTokenRequest" + responses: + "200": + description: 绑定成功。 + schema: + $ref: "#/definitions/BindPushTokenEnvelope" + "400": + $ref: "#/responses/BadRequest" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "502": + $ref: "#/responses/UpstreamError" + delete: + tags: + - devices + summary: 删除设备推送 token + operationId: deletePushToken + description: 登出、关闭通知或 token 失效时调用;`push_token` 可为空,为空时按当前用户和 `device_id` 失效。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: body + in: body + required: true + schema: + $ref: "#/definitions/DeletePushTokenRequest" + responses: + "200": + description: 删除或失效处理完成。 + schema: + $ref: "#/definitions/DeletePushTokenEnvelope" + "400": + $ref: "#/responses/BadRequest" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "502": + $ref: "#/responses/UpstreamError" /api/v1/tencent-im/callback: post: tags: @@ -559,6 +634,35 @@ paths: $ref: "#/responses/Internal" "502": $ref: "#/responses/UpstreamError" + /api/v1/users/profiles:batch: + get: + tags: + - users + summary: 批量查询会话展示资料 + operationId: batchUserProfiles + description: 用于腾讯云 IM 会话列表补头像、昵称和短号;只返回展示字段,不返回登录、实名或后台身份信息。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: user_ids + in: query + required: true + type: string + description: 逗号分隔或重复传入的用户 ID,最多 100 个。 + responses: + "200": + description: 查询成功。 + schema: + $ref: "#/definitions/UserProfilesBatchEnvelope" + "400": + $ref: "#/responses/BadRequest" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "502": + $ref: "#/responses/UpstreamError" /api/v1/users/me/identity: get: tags: @@ -604,6 +708,32 @@ paths: $ref: "#/responses/Forbidden" "502": $ref: "#/responses/UpstreamError" + /api/v1/users/me/overview: + get: + tags: + - users + summary: 我的页首屏聚合摘要 + operationId: getMyOverview + description: 聚合当前用户资料、固定三类钱包余额、Host/Agency/BD/币商身份、消息红点和入口显隐。该接口不查流水、不扫成员、不计算工资;钱包、角色和消息上游失败时按字段 `unavailable=true` 局部降级。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + responses: + "200": + description: 查询成功,`data` 返回我的页首屏渲染摘要。 + schema: + $ref: "#/definitions/MyOverviewEnvelope" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "404": + $ref: "#/responses/NotFound" + "500": + $ref: "#/responses/Internal" + "502": + $ref: "#/responses/UpstreamError" /api/v1/users/me/onboarding/complete: post: tags: @@ -763,6 +893,62 @@ paths: $ref: "#/responses/Internal" "502": $ref: "#/responses/UpstreamError" + /api/v1/rooms/current: + get: + tags: + - rooms + summary: 查询当前可恢复房间 + operationId: getCurrentRoom + description: App 启动、回前台或网络恢复时调用;gateway 使用 access token user_id,room-service 用 presence 读模型和 Room Cell 快照二次校验,不会隐式 JoinRoom。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + responses: + "200": + description: 查询成功,`data.has_current_room=false` 表示无需恢复。 + schema: + $ref: "#/definitions/CurrentRoomEnvelope" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "502": + $ref: "#/responses/UpstreamError" + /api/v1/rooms/snapshot: + get: + tags: + - rooms + summary: 查询房间完整快照 + operationId: getRoomSnapshot + description: 房间页主动同步当前 Room Cell 快照;只读,不刷新 heartbeat,不隐式 JoinRoom。gateway 使用 access token user_id 作为 viewer,room-service 要求 viewer 仍在该房间。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: room_id + in: query + required: true + type: string + pattern: "^[A-Za-z0-9_-]{1,48}$" + maxLength: 48 + responses: + "200": + description: 查询成功,`data.room` 返回完整房间快照。 + schema: + $ref: "#/definitions/RoomSnapshotEnvelope" + "400": + $ref: "#/responses/BadRequest" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "404": + $ref: "#/responses/NotFound" + "409": + $ref: "#/responses/Conflict" + "502": + $ref: "#/responses/UpstreamError" /api/v1/rooms/create: post: tags: @@ -1470,6 +1656,149 @@ paths: $ref: "#/responses/NotFound" "502": $ref: "#/responses/UpstreamError" + /api/v1/messages/tabs: + get: + tags: + - messages + summary: 消息 tab 分区摘要 + operationId: listMessageTabs + description: 返回 user/system/activity 三个分区;user 分区只声明来源为腾讯云 IM SDK,不返回私聊内容。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + responses: + "200": + description: 查询成功。 + schema: + $ref: "#/definitions/MessageTabsEnvelope" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "502": + $ref: "#/responses/UpstreamError" + /api/v1/messages: + get: + tags: + - messages + summary: system/activity 消息列表 + operationId: listInboxMessages + description: 只读取当前 app_code 和当前用户下 visible、未删除、未过期的 system/activity 消息,按 sent_at_ms 倒序游标分页。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: section + in: query + required: true + type: string + enum: [system, activity] + - name: page_size + in: query + required: false + type: integer + format: int32 + - name: page_token + in: query + required: false + type: string + responses: + "200": + description: 查询成功。 + schema: + $ref: "#/definitions/MessageListEnvelope" + "400": + $ref: "#/responses/BadRequest" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "502": + $ref: "#/responses/UpstreamError" + /api/v1/messages/read-all: + post: + tags: + - messages + summary: 标记分区全部已读 + operationId: markInboxSectionRead + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: body + in: body + required: true + schema: + $ref: "#/definitions/MessageReadAllRequest" + responses: + "200": + description: 已读成功;重复请求成功且 read_count 可为 0。 + schema: + $ref: "#/definitions/MessageReadAllEnvelope" + "400": + $ref: "#/responses/BadRequest" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "502": + $ref: "#/responses/UpstreamError" + /api/v1/messages/{message_id}/read: + post: + tags: + - messages + summary: 标记单条消息已读 + operationId: markInboxMessageRead + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: message_id + in: path + required: true + type: string + responses: + "200": + description: 已读成功;重复请求不覆盖首次 read_at_ms。 + schema: + $ref: "#/definitions/MessageReadEnvelope" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "404": + $ref: "#/responses/NotFound" + "502": + $ref: "#/responses/UpstreamError" + /api/v1/messages/{message_id}: + delete: + tags: + - messages + summary: 删除单条消息 + operationId: deleteInboxMessage + description: 删除是当前用户侧隐藏,不物理删除 inbox 事实;不存在、已删除或不属于当前用户均返回 NOT_FOUND。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: message_id + in: path + required: true + type: string + responses: + "200": + description: 删除成功。 + schema: + $ref: "#/definitions/MessageDeleteEnvelope" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "404": + $ref: "#/responses/NotFound" + "502": + $ref: "#/responses/UpstreamError" /api/v1/wallet/coin-seller/transfer: post: tags: @@ -1846,6 +2175,73 @@ definitions: type: integer format: int64 description: 上传文件字节数。 + BindPushTokenRequest: + type: object + required: + - device_id + - push_token + - platform + properties: + device_id: + type: string + maxLength: 128 + description: App 安装级稳定 ID。 + push_token: + type: string + maxLength: 512 + description: APNS/FCM 等系统推送 token。 + provider: + type: string + maxLength: 32 + description: 可选;为空时 android 默认 fcm,ios 默认 apns。 + platform: + type: string + enum: + - android + - ios + app_version: + type: string + maxLength: 64 + language: + type: string + maxLength: 32 + timezone: + type: string + maxLength: 64 + DeletePushTokenRequest: + type: object + required: + - device_id + properties: + device_id: + type: string + maxLength: 128 + push_token: + type: string + maxLength: 512 + description: 可选;为空时按当前用户和 device_id 失效 active token。 + BindPushTokenData: + type: object + required: + - bound + - updated_at_ms + properties: + bound: + type: boolean + updated_at_ms: + type: integer + format: int64 + DeletePushTokenData: + type: object + required: + - deleted + - updated_at_ms + properties: + deleted: + type: boolean + updated_at_ms: + type: integer + format: int64 TencentIMCallbackRequest: type: object properties: @@ -1970,6 +2366,146 @@ definitions: is_coin_seller: type: boolean description: 用户是否拥有 active 币商身份。 + MyOverviewRolesData: + type: object + required: + - is_host + - is_agent + - is_bd + - is_bd_leader + - is_coin_seller + properties: + is_host: + type: boolean + is_agent: + type: boolean + is_bd: + type: boolean + is_bd_leader: + type: boolean + is_coin_seller: + type: boolean + unavailable: + type: boolean + description: 角色上游不可用时为 true;此时所有特权身份按 false 返回。 + MyOverviewAssetBalanceData: + type: object + required: + - asset_type + - available_amount + - frozen_amount + - version + properties: + asset_type: + type: string + enum: + - COIN + - DIAMOND + - USD_BALANCE + available_amount: + type: integer + format: int64 + frozen_amount: + type: integer + format: int64 + version: + type: integer + format: int64 + MyOverviewWalletData: + type: object + required: + - balances + - recharge_enabled + - diamond_exchange_enabled + - withdraw_enabled + properties: + balances: + type: array + description: 固定只返回 COIN、DIAMOND、USD_BALANCE;钱包账户行缺失时投影为 0,不返回 GIFT_POINT。 + items: + $ref: "#/definitions/MyOverviewAssetBalanceData" + recharge_enabled: + type: boolean + diamond_exchange_enabled: + type: boolean + withdraw_enabled: + type: boolean + unavailable: + type: boolean + description: 钱包上游不可用时为 true;此时 balances 为空。 + MyOverviewBadgesData: + type: object + required: + - unread_system_messages + - unread_activity_messages + - pending_role_invitations + properties: + unread_system_messages: + type: integer + format: int64 + unread_activity_messages: + type: integer + format: int64 + pending_role_invitations: + type: integer + format: int64 + description: 当前没有独立 counter 时返回 0,不扫邀请列表。 + unavailable: + type: boolean + description: 消息上游不可用时为 true;未读数按 0 返回。 + MyOverviewEntryData: + type: object + required: + - key + - title + - visible + - badge_count + properties: + key: + type: string + enum: + - wallet + - host_center + - apply_host + - agency_center + - bd_center + - bd_leader_center + - coin_seller_center + - backpack + - settings + - support + title: + type: string + visible: + type: boolean + badge_count: + type: integer + format: int64 + MyOverviewData: + type: object + required: + - profile + - wallet + - roles + - badges + - entries + - server_time_ms + properties: + profile: + $ref: "#/definitions/UserProfileData" + wallet: + $ref: "#/definitions/MyOverviewWalletData" + roles: + $ref: "#/definitions/MyOverviewRolesData" + badges: + $ref: "#/definitions/MyOverviewBadgesData" + entries: + type: array + items: + $ref: "#/definitions/MyOverviewEntryData" + server_time_ms: + type: integer + format: int64 UserProfileData: type: object properties: @@ -2041,6 +2577,172 @@ definitions: next_country_change_allowed_at_ms: type: integer format: int64 + UserProfileBatchData: + type: object + required: + - user_id + - display_user_id + - username + - app_code + properties: + user_id: + type: string + description: 数值型用户 ID 的字符串形式,避免客户端 JS 精度丢失。 + display_user_id: + type: string + username: + type: string + avatar: + type: string + gender: + type: string + country: + type: string + region_id: + type: integer + format: int64 + app_code: + type: string + description: 腾讯云 IM 会话列表展示资料;不包含手机号、登录凭证、实名或后台身份字段。 + UserProfilesBatchData: + type: object + required: + - profiles + properties: + profiles: + type: array + items: + $ref: "#/definitions/UserProfileBatchData" + MessageTabSectionData: + type: object + required: + - section + - title + - unread_count + - source + properties: + section: + type: string + enum: + - user + - system + - activity + title: + type: string + unread_count: + type: integer + format: int64 + source: + type: string + enum: + - tencent_im_sdk + - backend + MessageTabsData: + type: object + required: + - sections + properties: + sections: + type: array + items: + $ref: "#/definitions/MessageTabSectionData" + InboxMessageData: + type: object + required: + - message_id + - title + - summary + - read + - sent_at_ms + properties: + message_id: + type: string + title: + type: string + summary: + type: string + body: + type: string + icon_url: + type: string + image_url: + type: string + action_type: + type: string + description: 服务端白名单动作,例如 wallet_withdraw_detail、activity_detail、room_detail。 + action_param: + type: string + read: + type: boolean + sent_at_ms: + type: integer + format: int64 + MessageListData: + type: object + required: + - section + - items + - next_page_token + properties: + section: + type: string + enum: + - system + - activity + items: + type: array + items: + $ref: "#/definitions/InboxMessageData" + next_page_token: + type: string + MessageReadAllRequest: + type: object + required: + - section + properties: + section: + type: string + enum: + - system + - activity + MessageReadData: + type: object + required: + - message_id + - read + - read_at_ms + properties: + message_id: + type: string + read: + type: boolean + read_at_ms: + type: integer + format: int64 + MessageReadAllData: + type: object + required: + - section + - read_count + properties: + section: + type: string + enum: + - system + - activity + read_count: + type: integer + format: int64 + MessageDeleteData: + type: object + required: + - message_id + - deleted + properties: + message_id: + type: string + deleted: + type: boolean CountryData: type: object properties: @@ -2106,6 +2808,47 @@ definitions: total: type: integer format: int32 + AppBootstrapTab: + type: object + properties: + key: + type: string + enum: + - rooms + - messages + - me + title: + type: string + enabled: + type: boolean + AppBootstrapData: + type: object + properties: + app_code: + type: string + server_time_ms: + type: integer + format: int64 + force_upgrade: + type: boolean + maintenance: + type: boolean + minimum_version: + type: string + latest_version: + type: string + feature_flags: + type: object + additionalProperties: + type: boolean + bottom_tabs: + type: array + items: + $ref: "#/definitions/AppBootstrapTab" + config_versions: + type: object + additionalProperties: + type: string CompleteOnboardingRequest: type: object required: @@ -2817,6 +3560,59 @@ definitions: version: type: integer format: int64 + CurrentRoomData: + type: object + required: + - has_current_room + - room_id + - room_version + - role + - mic_session_id + - publish_state + - need_join_im_group + - need_rtc_token + - server_time_ms + properties: + has_current_room: + type: boolean + room_id: + type: string + room_version: + type: integer + format: int64 + role: + type: string + enum: + - owner + - host + - admin + - audience + mic_session_id: + type: string + publish_state: + type: string + enum: + - "" + - pending_publish + - publishing + need_join_im_group: + type: boolean + need_rtc_token: + type: boolean + server_time_ms: + type: integer + format: int64 + RoomSnapshotData: + type: object + required: + - room + - server_time_ms + properties: + room: + $ref: "#/definitions/RoomSnapshot" + server_time_ms: + type: integer + format: int64 CreateRoomResponse: type: object properties: @@ -2998,6 +3794,20 @@ definitions: properties: data: $ref: "#/definitions/UploadFileData" + BindPushTokenEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/BindPushTokenData" + DeletePushTokenEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/DeletePushTokenData" UserIdentityEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" @@ -3012,6 +3822,13 @@ definitions: properties: data: $ref: "#/definitions/UserHostIdentityData" + MyOverviewEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/MyOverviewData" UserProfileEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" @@ -3019,6 +3836,48 @@ definitions: properties: data: $ref: "#/definitions/UserProfileData" + UserProfilesBatchEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/UserProfilesBatchData" + MessageTabsEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/MessageTabsData" + MessageListEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/MessageListData" + MessageReadEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/MessageReadData" + MessageReadAllEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/MessageReadAllData" + MessageDeleteEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/MessageDeleteData" CompleteOnboardingEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" @@ -3033,6 +3892,13 @@ definitions: properties: data: $ref: "#/definitions/CountryListData" + AppBootstrapEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/AppBootstrapData" H5LinkListEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" @@ -3082,6 +3948,20 @@ definitions: properties: data: $ref: "#/definitions/CreateRoomResponse" + CurrentRoomEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/CurrentRoomData" + RoomSnapshotEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/RoomSnapshotData" JoinRoomEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" diff --git a/docs/openapi/room.swagger.yaml b/docs/openapi/room.swagger.yaml index f736231b..d23f0790 100644 --- a/docs/openapi/room.swagger.yaml +++ b/docs/openapi/room.swagger.yaml @@ -17,6 +17,8 @@ produces: tags: - name: room-command description: RoomCommandService,改变房间状态的命令接口。 + - name: room-query + description: RoomQueryService,不改变 Room Cell 状态的读模型查询。 - name: room-guard description: RoomGuardService,腾讯云 IM 入群和发言前的同步守卫。 - name: health @@ -367,6 +369,48 @@ paths: $ref: "#/definitions/VerifyRoomPresenceResponse" default: $ref: "#/responses/GRPCError" + /hyapp.room.v1.RoomQueryService/GetCurrentRoom: + post: + tags: + - room-query + summary: 查询用户当前可恢复房间 + operationId: roomGetCurrentRoom + description: 启动、回前台和网络恢复时使用;只读 room_user_presence 投影并用 Room Cell 快照二次校验,不会隐式 JoinRoom 或刷新 presence。 + x-grpc-full-method: /hyapp.room.v1.RoomQueryService/GetCurrentRoom + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/GetCurrentRoomRequest" + responses: + "200": + description: 返回是否存在可恢复房间,以及是否需要重新入 IM 群和重新签 RTC token。 + schema: + $ref: "#/definitions/GetCurrentRoomResponse" + default: + $ref: "#/responses/GRPCError" + /hyapp.room.v1.RoomQueryService/GetRoomSnapshot: + post: + tags: + - room-query + summary: 查询房间完整快照 + operationId: roomGetRoomSnapshot + description: 房间页主动同步使用;只读 Room Cell/snapshot,不刷新 presence,不隐式 JoinRoom,viewer 必须仍在该房间。 + x-grpc-full-method: /hyapp.room.v1.RoomQueryService/GetRoomSnapshot + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/GetRoomSnapshotRequest" + responses: + "200": + description: 返回当前完整房间快照。 + schema: + $ref: "#/definitions/GetRoomSnapshotResponse" + default: + $ref: "#/responses/GRPCError" /grpc.health.v1.Health/Check: post: tags: @@ -921,6 +965,74 @@ definitions: room_version: type: integer format: int64 + GetCurrentRoomRequest: + type: object + required: + - meta + - user_id + properties: + meta: + $ref: "#/definitions/RequestMeta" + user_id: + type: integer + format: int64 + description: 由 gateway 从 token user_id 注入,客户端不能自报。 + GetCurrentRoomResponse: + type: object + properties: + has_current_room: + type: boolean + room_id: + type: string + room_version: + type: integer + format: int64 + role: + type: string + description: 用户在房间快照中的角色。 + mic_session_id: + type: string + description: 用户当前在麦时返回;客户端确认发流必须带回该 session。 + publish_state: + type: string + enum: + - pending_publish + - publishing + - idle + need_join_im_group: + type: boolean + description: true 表示客户端应重新确保加入腾讯云 IM 群。 + need_rtc_token: + type: boolean + description: true 表示用户处于 pending_publish/publishing,需要重新获取 RTC token。 + server_time_ms: + type: integer + format: int64 + GetRoomSnapshotRequest: + type: object + required: + - meta + - room_id + - viewer_user_id + properties: + meta: + $ref: "#/definitions/RequestMeta" + room_id: + type: string + pattern: "^[A-Za-z0-9_-]{1,48}$" + maxLength: 48 + viewer_user_id: + type: integer + format: int64 + description: 由 gateway 从 token user_id 注入,客户端不能自报。 + GetRoomSnapshotResponse: + type: object + properties: + room: + $ref: "#/definitions/RoomSnapshot" + server_time_ms: + type: integer + format: int64 RoomSystemMessage: type: object properties: diff --git a/docs/openapi/user.swagger.yaml b/docs/openapi/user.swagger.yaml index b826e5f6..12243029 100644 --- a/docs/openapi/user.swagger.yaml +++ b/docs/openapi/user.swagger.yaml @@ -18,6 +18,8 @@ tags: description: AuthService,登录注册和 token 生命周期。 - name: users description: UserService,用户主状态读取。 + - name: user-devices + description: UserDeviceService,App 设备推送 token 绑定和失效。 - name: user-identity description: UserIdentityService,展示短号解析和变更。 - name: country-admin @@ -174,6 +176,26 @@ paths: $ref: "#/definitions/BatchGetUsersResponse" default: $ref: "#/responses/GRPCError" + /hyapp.user.v1.UserService/ListUserIDs: + post: + tags: + - users + summary: 后台任务按 user_id 游标查询目标用户 + operationId: userListUserIDs + x-grpc-full-method: /hyapp.user.v1.UserService/ListUserIDs + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/ListUserIDsRequest" + responses: + "200": + description: 返回递增 user_id 页;调用方用 next_cursor_user_id 继续。 + schema: + $ref: "#/definitions/ListUserIDsResponse" + default: + $ref: "#/responses/GRPCError" /hyapp.user.v1.UserService/UpdateUserProfile: post: tags: @@ -236,6 +258,48 @@ paths: $ref: "#/definitions/CompleteOnboardingResponse" default: $ref: "#/responses/GRPCError" + /hyapp.user.v1.UserDeviceService/BindPushToken: + post: + tags: + - user-devices + summary: 绑定当前登录用户的系统推送 token + operationId: userBindPushToken + description: push token 只服务离线触达,不作为登录凭证或设备身份凭证;同一 provider/token 被新设备绑定时会失效旧归属。 + x-grpc-full-method: /hyapp.user.v1.UserDeviceService/BindPushToken + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/BindPushTokenRequest" + responses: + "200": + description: 绑定成功或幂等更新成功。 + schema: + $ref: "#/definitions/BindPushTokenResponse" + default: + $ref: "#/responses/GRPCError" + /hyapp.user.v1.UserDeviceService/DeletePushToken: + post: + tags: + - user-devices + summary: 失效当前登录用户的系统推送 token + operationId: userDeletePushToken + description: push_token 为空时按 user_id + device_id 失效该设备的 active token。 + x-grpc-full-method: /hyapp.user.v1.UserDeviceService/DeletePushToken + parameters: + - name: body + in: body + required: true + schema: + $ref: "#/definitions/DeletePushTokenRequest" + responses: + "200": + description: 删除成功;没有匹配 token 时返回 deleted=false。 + schema: + $ref: "#/definitions/DeletePushTokenResponse" + default: + $ref: "#/responses/GRPCError" /hyapp.user.v1.CountryAdminService/CreateCountry: post: tags: @@ -933,6 +997,44 @@ definitions: type: object additionalProperties: $ref: "#/definitions/User" + ListUserIDsRequest: + type: object + required: + - target_scope + properties: + meta: + $ref: "#/definitions/RequestMeta" + target_scope: + type: string + enum: + - all_active_users + - region + - country + cursor_user_id: + type: integer + format: int64 + page_size: + type: integer + format: int32 + region_id: + type: integer + format: int64 + country: + type: string + description: "`target_scope=country` 时使用的国家码。" + ListUserIDsResponse: + type: object + properties: + user_ids: + type: array + items: + type: integer + format: int64 + next_cursor_user_id: + type: integer + format: int64 + done: + type: boolean UpdateUserProfileRequest: type: object properties: @@ -987,6 +1089,80 @@ definitions: format: int64 onboarding_status: type: string + BindPushTokenRequest: + type: object + required: + - meta + - user_id + - device_id + - push_token + - platform + properties: + meta: + $ref: "#/definitions/RequestMeta" + user_id: + type: integer + format: int64 + device_id: + type: string + maxLength: 128 + description: App 安装维度稳定 ID;不是登录凭证。 + push_token: + type: string + maxLength: 512 + provider: + type: string + maxLength: 32 + description: 推送服务提供方;为空时服务端按 platform 默认 android=fcm、ios=apns。 + platform: + type: string + enum: + - android + - ios + app_version: + type: string + maxLength: 64 + language: + type: string + maxLength: 32 + timezone: + type: string + maxLength: 64 + BindPushTokenResponse: + type: object + properties: + bound: + type: boolean + updated_at_ms: + type: integer + format: int64 + DeletePushTokenRequest: + type: object + required: + - meta + - user_id + - device_id + properties: + meta: + $ref: "#/definitions/RequestMeta" + user_id: + type: integer + format: int64 + device_id: + type: string + maxLength: 128 + push_token: + type: string + maxLength: 512 + description: 可选;为空时删除该设备当前 active token。 + DeletePushTokenResponse: + type: object + properties: + deleted: + type: boolean + updated_at_ms: + type: integer + format: int64 ChangeUserCountryRequest: type: object properties: diff --git a/docs/voice-room-client-api-flow.md b/docs/voice-room-client-api-flow.md new file mode 100644 index 00000000..d600f3b6 --- /dev/null +++ b/docs/voice-room-client-api-flow.md @@ -0,0 +1,493 @@ +# Voice Room Client API Flow + +本文定义用户进入语音房后的客户端接口调用顺序、触发条件和服务边界。本文只描述 App 侧要调用的 gateway HTTP 接口、腾讯云 IM/RTC SDK 动作,以及不能由客户端直接调用的内部守卫接口。 + +## Scope + +| Area | Owner | Rule | +| --- | --- | --- | +| HTTP 入口 | `gateway-service` | 鉴权、profile gate、协议转换、腾讯 IM/RTC token 签发 | +| 房间业务状态 | `room-service` | Room Cell、presence、麦位、房管、snapshot、outbox | +| 房间长连接和公屏 | 腾讯云 IM SDK | 客户端登录、房间群、公屏、系统消息接收 | +| 真实音频频道 | 腾讯云 RTC SDK | 进 RTC 房、切换 audience/anchor、发音频 | +| 用户主数据 | `user-service` | 登录、资料完成状态、用户区域、push token | + +关键边界: + +- 客户端进入语音房必须先 `JoinRoom` 写入 room-service 业务 presence,再进 IM 群和 RTC 房。 +- `room-service` 不保存客户端 socket,也不保存腾讯云 RTC 连接态。 +- 腾讯云 IM 群成员关系不是业务 presence;是否允许进群、发言、签 RTC token 仍以 room-service 守卫为准。 +- gateway 只使用 access token 中的 `user_id` 作为 actor,客户端不能自报 `actor_user_id`、`owner_user_id`、`host_user_id`。 +- 所有 `/api/v1` 业务响应使用 `{code,message,request_id,data}` envelope。 + +## Minimal Enter Room Flow + +```mermaid +sequenceDiagram + participant C as Client + participant G as gateway-service + participant R as room-service + participant IM as Tencent IM SDK + participant RTC as Tencent RTC SDK + + C->>G: POST /api/v1/rooms/join + G->>R: JoinRoom(actor_user_id from token) + R-->>G: room snapshot + user presence + G-->>C: room snapshot + + C->>G: GET /api/v1/im/usersig + G-->>C: IM user_sig + C->>IM: login(user_id, user_sig) + C->>IM: joinGroup(room_id) + + C->>G: POST /api/v1/rtc/token + G->>R: VerifyRoomPresence(room_id, user_id) + G-->>C: RTC user_sig, str_room_id, role=audience + C->>RTC: enterRoom(strRoomId, audience) + + loop while room page is active + C->>G: POST /api/v1/rooms/heartbeat + end +``` + +### Required Order + +| Step | Interface | Required | Reason | +| --- | --- | --- | --- | +| 1 | `POST /api/v1/rooms/join` | yes | 建立业务 presence,后续 IM/RTC 守卫依赖它 | +| 2 | `GET /api/v1/im/usersig` | yes | 登录腾讯云 IM,接收房间群消息和系统事件 | +| 3 | Tencent IM SDK `login` + `joinGroup` | yes | 本仓库不承载房间长连接 | +| 4 | `POST /api/v1/rtc/token` | yes for voice room audio | 签发 TRTC 票据;当前返回 `role=audience` | +| 5 | Tencent RTC SDK `enterRoom` | yes for voice room audio | 进入真实音频频道旁听 | +| 6 | `POST /api/v1/rooms/heartbeat` | yes | 刷新业务 presence,避免 stale timeout | + +如果产品允许“只看公屏不听语音”,第 4、5 步可以延迟到用户打开音频时。但语音房默认应进入 RTC audience,以保证打开房间即可听到声音。 + +## Core Interfaces + +### Join Room + +```http +POST /api/v1/rooms/join +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx", + "command_id": "cmd_join___", + "role": "audience" +} +``` + +Response `data`: + +```json +{ + "result": { + "applied": true, + "room_version": 2, + "server_time_ms": 1778000000000 + }, + "user": { + "user_id": 10001, + "role": "audience", + "joined_at_ms": 1778000000000, + "last_seen_at_ms": 1778000000000 + }, + "room": {} +} +``` + +Rules: + +- `room_id` 必须来自房间列表、分享或恢复接口,不能由客户端拼业务含义。 +- `command_id` 用于房间命令幂等;客户端重试同一次进房必须复用同一个值。 +- `role` 只作为展示默认值,不能通过自报 `admin/host/owner` 获得权限。 +- JoinRoom 成功后才能登录 IM 进群和获取 RTC token。 + +### IM UserSig + +```http +GET /api/v1/im/usersig +Authorization: Bearer +``` + +Response `data`: + +```json +{ + "sdk_app_id": 20036101, + "user_id": "10001", + "user_sig": "xxx", + "expire_at_ms": 1778086400000 +} +``` + +Rules: + +- 当前 gateway 路由是 `GET /api/v1/im/usersig`。 +- `user_id` 是内部不可变长 `user_id` 的十进制字符串,必须直接作为腾讯云 IM identifier。 +- UserSig 只用于腾讯云 IM SDK 登录,不用于本仓库鉴权。 +- 未完成资料用户会被 profile gate 拒绝。 + +Client SDK action: + +```text +Tencent IM SDK login(user_id, user_sig) +Tencent IM SDK joinGroup(room_id) +``` + +### RTC Token + +```http +POST /api/v1/rtc/token +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx" +} +``` + +Response `data`: + +```json +{ + "sdk_app_id": 20036101, + "user_id": "10001", + "rtc_user_id": "10001", + "user_sig": "xxx", + "expire_at_ms": 1778007200000, + "room_id": "lalu_xxx", + "rtc_room_id": "lalu_xxx", + "rtc_room_id_type": "string", + "str_room_id": "lalu_xxx", + "app_scene": "voice_chat_room", + "role": "audience" +} +``` + +Rules: + +- gateway 会先调用 room-service `VerifyRoomPresence`,用户不在房间、被踢、被 ban 时不会签发 RTC token。 +- 当前只支持 TRTC `strRoomId`,客户端不能把 `room_id` 转为数字 `roomId`。 +- 当前 token 返回 `role=audience`;上麦成功后由客户端切 `anchor` 并确认发流。 +- token 过期时重新调用该接口,不使用 refresh token。 + +Client SDK action: + +```text +Tencent RTC SDK enterRoom(strRoomId=resp.str_room_id, userId=resp.rtc_user_id, role=audience) +``` + +### Heartbeat + +```http +POST /api/v1/rooms/heartbeat +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx", + "command_id": "cmd_heartbeat___" +} +``` + +Rules: + +- 只刷新已经存在的业务 presence,不能替代 JoinRoom。 +- 用户已经离房、被踢或房间关闭时,客户端应停止心跳并清理本地房间态。 +- 心跳间隔由客户端配置控制,但必须小于 room-service 的 presence stale 窗口。 + +### Leave Room + +```http +POST /api/v1/rooms/leave +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx", + "command_id": "cmd_leave___" +} +``` + +Rules: + +- 主动关闭房间页、切换账号、被客户端确认退出时调用。 +- 如果用户在麦上,LeaveRoom 会释放麦位。 +- LeaveRoom 后客户端必须停止 heartbeat、退出 RTC 房、退出或忽略 IM 房间群消息。 + +## Mic Flow + +### Mic Up + +```http +POST /api/v1/rooms/mic/up +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx", + "command_id": "cmd_mic_up___", + "seat_no": 1 +} +``` + +Response `data`: + +```json +{ + "result": {}, + "seat_no": 1, + "mic_session_id": "mic_xxx", + "publish_deadline_ms": 1778000015000, + "room": {} +} +``` + +Client actions after success: + +1. 保存 `mic_session_id`、`room.version` 和 `publish_deadline_ms`。 +2. 确保已有 RTC token;没有或过期则调用 `POST /api/v1/rtc/token`。 +3. RTC SDK 切换 `anchor`。 +4. RTC SDK 调 `startLocalAudio`。 +5. SDK 本地发流成功后调用 `POST /api/v1/rooms/mic/publishing/confirm`。 + +Rules: + +- `MicUp` 成功只代表业务麦位占用成功,不代表 RTC 已经发布音频成功。 +- 服务端状态先进入 `pending_publish`。 +- 超过 `publish_deadline_ms` 未确认,room-service 会自动 MicDown,reason 为 `publish_timeout`。 + +### Confirm Mic Publishing + +```http +POST /api/v1/rooms/mic/publishing/confirm +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx", + "command_id": "cmd_confirm_publish___", + "target_user_id": 0, + "mic_session_id": "mic_xxx", + "room_version": 12, + "event_time_ms": 1778000001000, + "source": "client" +} +``` + +Rules: + +- `target_user_id=0` 表示确认当前 actor;RTC webhook 路径才需要显式 target。 +- `mic_session_id` 必须等于当前麦位会话。 +- `room_version` 和 `event_time_ms` 用于丢弃旧事件,避免旧 audience/leave 事件清理新会话。 +- 成功后麦位 `publish_state=publishing`。 + +### Mic Down + +```http +POST /api/v1/rooms/mic/down +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx", + "command_id": "cmd_mic_down___", + "target_user_id": 0, + "reason": "user_action" +} +``` + +Rules: + +- 普通用户下自己麦时 `target_user_id` 可传 0 或自己 user_id。 +- 房管下别人麦时传目标用户 `target_user_id`。 +- 客户端收到成功响应或房间系统消息后必须停止本地音频并切回 `audience`。 + +### Change Mic Seat + +```http +POST /api/v1/rooms/mic/change +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx", + "command_id": "cmd_change_mic___", + "target_user_id": 10002, + "seat_no": 2 +} +``` + +Rules: + +- 换麦位只更新业务麦位和 UI,不需要重新进入 RTC。 +- 如果 target 当前在发流,客户端继续保持 RTC 上行。 + +## Room Management APIs + +这些接口只允许有权限的 owner/host/admin 调用;gateway 不判断权限,最终由 room-service Room Cell 判断。 + +| Interface | Body | Result | +| --- | --- | --- | +| `POST /api/v1/rooms/mic/lock` | `room_id, command_id, seat_no, locked` | 锁/解锁麦位 | +| `POST /api/v1/rooms/chat/enabled` | `room_id, command_id, enabled` | 开/关公屏,影响发言守卫 | +| `POST /api/v1/rooms/admin/set` | `room_id, command_id, target_user_id, is_admin` | 设置或取消房管 | +| `POST /api/v1/rooms/host/transfer` | `room_id, command_id, target_user_id` | 转移主持人 | +| `POST /api/v1/rooms/user/mute` | `room_id, command_id, target_user_id, muted, reason` | 禁言或解禁 | +| `POST /api/v1/rooms/user/kick` | `room_id, command_id, target_user_id, reason` | 踢人并 ban,释放 presence 和麦位 | +| `POST /api/v1/rooms/user/unban` | `room_id, command_id, target_user_id, reason` | 解除房间 ban | + +Management event handling: + +- 管理动作成功后,room-service 写 command log、snapshot 和 outbox。 +- 客户端应通过腾讯云 IM 房间系统消息更新 UI。 +- 如果本地 UI 状态和系统消息冲突,以最新 room snapshot 和 `room_version` 为准。 + +## Gift And Interaction + +```http +POST /api/v1/rooms/gift/send +Authorization: Bearer +Content-Type: application/json +``` + +Request: + +```json +{ + "room_id": "lalu_xxx", + "command_id": "cmd_send_gift___", + "target_user_id": 10002, + "gift_id": "rose", + "gift_count": 1 +} +``` + +Rules: + +- `SendGift` 必须先由 wallet-service 扣费成功,再落房间表现。 +- 房间表现、热度、本地榜通过 room snapshot 和房间系统消息同步。 +- 公屏文本消息不走 gateway HTTP;客户端使用腾讯云 IM 群消息。 + +## Restore And Reconnect + +### Current Room + +```http +GET /api/v1/rooms/current +Authorization: Bearer +``` + +Response `data`: + +```json +{ + "has_current_room": true, + "room_id": "lalu_xxx", + "room_version": 12, + "role": "audience", + "mic_session_id": "", + "publish_state": "", + "need_join_im_group": true, + "need_rtc_token": false, + "server_time_ms": 1778000000000 +} +``` + +Client restore rules: + +| Response | Client Action | +| --- | --- | +| `has_current_room=false` | 清理本地房间态,不展示恢复入口 | +| `need_join_im_group=true` | 调 `GET /api/v1/im/usersig`,重新登录 IM 并 join group | +| `need_rtc_token=true` | 调 `POST /api/v1/rtc/token`,重新进入 RTC | +| `publish_state=pending_publish` | 重新执行 SDK 发流并确认当前 `mic_session_id` | +| `publish_state=publishing` | 确认本地 RTC 上行是否仍存在;不确定时重新发流并确认 | + +`rooms/current` 是只读恢复探测,不会隐式 JoinRoom,不刷新 heartbeat,也不改变 Room Cell。 + +### Reconnect Order + +1. access token 有效时先调 `GET /api/v1/rooms/current`。 +2. 如果 `has_current_room=false`,回房间列表或主界面。 +3. 如果 `has_current_room=true`,先恢复 IM,再恢复 RTC。 +4. 如果用户原本在麦上,必须使用返回的 `mic_session_id` 继续确认或等待服务端超时下麦。 +5. 恢复成功后恢复 `POST /api/v1/rooms/heartbeat` 定时器。 + +## Server Callback Boundaries + +客户端不要直接调用这些接口或内部 RPC: + +| Interface | Caller | Purpose | +| --- | --- | --- | +| `POST /api/v1/tencent-im/callback` | Tencent IM | 入群、发言等服务端回调入口 | +| `POST /api/v1/tencent-rtc/callback` | Tencent RTC | RTC 音频事件回调入口 | +| `room-service.VerifyRoomPresence` | gateway / callback | 判断用户是否仍在房间、是否被 ban | +| `room-service.CheckSpeakPermission` | gateway / callback | 判断用户是否允许发公屏 | + +客户端只消费这些回调产生的房间系统消息和最新 snapshot,不直接操作内部守卫。 + +## Error Handling + +| Error | Meaning | Client Action | +| --- | --- | --- | +| `UNAUTHORIZED` / `AUTH_REQUIRED` | access token 无效 | refresh 成功后重试;refresh 失败回登录 | +| `PROFILE_REQUIRED` | 资料未完成 | 跳资料补全页,不能进入房间 | +| `NOT_FOUND` | 房间或用户事实不存在 | 清本地目标房间,回列表 | +| `ROOM_CLOSED` | 房间已关闭 | 清房间态,回列表 | +| `PERMISSION_DENIED` | 被踢、被 ban、无权限 | 停止对应操作,按系统消息更新 UI | +| `CONFLICT` | 麦位占用、命令冲突、状态冲突 | 拉最新 snapshot 或等待房间系统消息修正 | +| `UPSTREAM_ERROR` | 内部服务或腾讯云依赖异常 | 保留本地登录态,展示重试 | + +不要因为普通网络失败或 5xx 清空登录态。只有 refresh 明确失败、session revoked 或用户主动 logout 才清 token。 + +## Room Snapshot Sync + +当前客户端拿完整房间状态的来源: + +- `JoinRoom` 响应里的 room snapshot。 +- 房间命令响应里的 room snapshot。 +- 腾讯云 IM 房间系统消息。 +- `rooms/current` 的恢复摘要。 +- `GET /api/v1/rooms/snapshot?room_id=` 主动同步接口。 + +```http +GET /api/v1/rooms/snapshot?room_id= +``` + +该接口只读 Room Cell/snapshot,不刷新 presence,不隐式 JoinRoom,不替代 heartbeat。gateway 使用 access token user_id 作为 viewer,room-service 要求 viewer 仍在该房间;未进房、被踢或被 ban 的用户不能读取完整在线用户和麦位快照。 diff --git a/pkg/xerr/errors.go b/pkg/xerr/errors.go index 639b4307..6ab927ee 100644 --- a/pkg/xerr/errors.go +++ b/pkg/xerr/errors.go @@ -81,6 +81,19 @@ const ( EventAlreadyConsumed Code = "EVENT_ALREADY_CONSUMED" // RewardPending 表示奖励仍在处理中,不能重复结算。 RewardPending Code = "REWARD_PENDING" + + // InvalidSection 表示 App 消息分区不属于 system/activity。 + InvalidSection Code = "INVALID_SECTION" + // MessageNotFound 表示消息不存在、已删除、已过期、已撤回或不属于当前用户。 + MessageNotFound Code = "MESSAGE_NOT_FOUND" + // MessageRecalled 表示消息已撤回,不能继续展示或操作。 + MessageRecalled Code = "MESSAGE_RECALLED" + // PageTokenInvalid 表示分页游标不能解析或不属于当前查询。 + PageTokenInvalid Code = "PAGE_TOKEN_INVALID" + // RequestConflict 表示同 command_id 的 fanout 请求 payload 冲突。 + RequestConflict Code = "REQUEST_CONFLICT" + // ProducerEventConflict 表示同 producer_event_id 的入箱请求 payload 冲突。 + ProducerEventConflict Code = "PRODUCER_EVENT_CONFLICT" ) // Error 是 domain/service 层统一返回的业务错误。 diff --git a/pkg/xerr/grpc.go b/pkg/xerr/grpc.go index 73169f84..51f96462 100644 --- a/pkg/xerr/grpc.go +++ b/pkg/xerr/grpc.go @@ -14,11 +14,11 @@ const errorDomain = "hyapp" // gateway 后续只需要读取 gRPC code 和 ErrorInfo.reason 即可生成 HTTP envelope。 func GRPCCode(code Code) codes.Code { switch code { - case InvalidArgument, DisplayUserIDInvalid: + case InvalidArgument, DisplayUserIDInvalid, InvalidSection, PageTokenInvalid: return codes.InvalidArgument - case NotFound, DisplayUserIDNotFound, CountryNotFound, RegionNotFound: + case NotFound, DisplayUserIDNotFound, CountryNotFound, RegionNotFound, MessageNotFound, MessageRecalled: return codes.NotFound - case Conflict, RoomClosed, RegionCountryConflict, RegionDisabled: + case Conflict, RoomClosed, RegionCountryConflict, RegionDisabled, RequestConflict, ProducerEventConflict: return codes.FailedPrecondition case Unauthorized, AuthFailed, SessionExpired, SessionRevoked: return codes.Unauthenticated diff --git a/services/activity-service/configs/config.docker.yaml b/services/activity-service/configs/config.docker.yaml index d565fee9..d66a33c1 100644 --- a/services/activity-service/configs/config.docker.yaml +++ b/services/activity-service/configs/config.docker.yaml @@ -2,7 +2,16 @@ service_name: activity-service node_id: activity-docker grpc_addr: ":13006" mysql_dsn: "hyapp:hyapp@tcp(mysql:3306)/hyapp_activity?parseTime=true&charset=utf8mb4&loc=Local" +user_service_addr: "user-service:13005" mysql_auto_migrate: false consumer: room_outbox_poll_interval_ms: 1000 batch_size: 100 +message_inbox: + unread_cache_ttl: "60s" + fanout_worker: + enabled: true + poll_interval: "1s" + batch_size: 500 + lock_ttl: "30s" + max_retry: 8 diff --git a/services/activity-service/configs/config.tencent.example.yaml b/services/activity-service/configs/config.tencent.example.yaml index 33745ee7..f2e6a837 100644 --- a/services/activity-service/configs/config.tencent.example.yaml +++ b/services/activity-service/configs/config.tencent.example.yaml @@ -2,7 +2,16 @@ service_name: activity-service node_id: activity-tencent grpc_addr: ":13006" mysql_dsn: "${TENCENT_MYSQL_ACTIVITY_DSN}" +user_service_addr: "user-service.internal:13005" mysql_auto_migrate: false consumer: room_outbox_poll_interval_ms: 1000 batch_size: 100 +message_inbox: + unread_cache_ttl: "60s" + fanout_worker: + enabled: true + poll_interval: "1s" + batch_size: 500 + lock_ttl: "30s" + max_retry: 8 diff --git a/services/activity-service/configs/config.yaml b/services/activity-service/configs/config.yaml index 9fcdf1ca..feadc911 100644 --- a/services/activity-service/configs/config.yaml +++ b/services/activity-service/configs/config.yaml @@ -2,7 +2,16 @@ service_name: activity-service node_id: activity-local grpc_addr: ":13006" mysql_dsn: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_activity?parseTime=true&charset=utf8mb4&loc=Local" +user_service_addr: "127.0.0.1:13005" mysql_auto_migrate: false consumer: room_outbox_poll_interval_ms: 1000 batch_size: 100 +message_inbox: + unread_cache_ttl: "60s" + fanout_worker: + enabled: true + poll_interval: "1s" + batch_size: 500 + lock_ttl: "30s" + max_retry: 8 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 6f7b434f..e994f2f8 100644 --- a/services/activity-service/deploy/mysql/initdb/001_activity_service.sql +++ b/services/activity-service/deploy/mysql/initdb/001_activity_service.sql @@ -41,3 +41,87 @@ CREATE TABLE IF NOT EXISTS activity_outbox ( PRIMARY KEY (app_code, outbox_id), KEY idx_activity_outbox_status_retry (app_code, status, next_retry_at_ms) ) 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, + template_version VARCHAR(64) NOT NULL, + message_type VARCHAR(32) NOT NULL, + locale VARCHAR(32) NOT NULL DEFAULT '', + title VARCHAR(160) NOT NULL, + summary VARCHAR(512) NOT NULL, + body VARCHAR(2048) NOT NULL DEFAULT '', + icon_url VARCHAR(512) NOT NULL DEFAULT '', + image_url VARCHAR(512) NOT NULL DEFAULT '', + action_type VARCHAR(64) NOT NULL DEFAULT '', + action_param VARCHAR(1024) NOT NULL DEFAULT '', + status VARCHAR(32) NOT NULL, + created_by VARCHAR(64) NOT NULL DEFAULT '', + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, template_id, template_version), + KEY idx_message_templates_type_status (app_code, message_type, status), + KEY idx_message_templates_template_status (app_code, template_id, status) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS user_inbox_messages ( + app_code VARCHAR(32) NOT NULL, + inbox_message_id VARCHAR(96) NOT NULL, + user_id BIGINT NOT NULL, + message_type VARCHAR(32) NOT NULL, + producer VARCHAR(64) NOT NULL, + producer_event_id VARCHAR(128) NOT NULL, + producer_event_type VARCHAR(96) NOT NULL DEFAULT '', + aggregate_type VARCHAR(64) NOT NULL DEFAULT '', + aggregate_id VARCHAR(128) NOT NULL DEFAULT '', + template_id VARCHAR(96) NOT NULL DEFAULT '', + template_version VARCHAR(64) NOT NULL DEFAULT '', + title VARCHAR(160) NOT NULL, + summary VARCHAR(512) NOT NULL, + body VARCHAR(2048) NOT NULL DEFAULT '', + icon_url VARCHAR(512) NOT NULL DEFAULT '', + image_url VARCHAR(512) NOT NULL DEFAULT '', + action_type VARCHAR(64) NOT NULL DEFAULT '', + action_param VARCHAR(1024) NOT NULL DEFAULT '', + priority INT NOT NULL DEFAULT 0, + status VARCHAR(32) NOT NULL, + read_at_ms BIGINT NULL, + deleted_at_ms BIGINT NULL, + sent_at_ms BIGINT NOT NULL, + expire_at_ms BIGINT NULL, + metadata_json JSON NULL, + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, inbox_message_id), + UNIQUE KEY uk_user_inbox_producer_event (app_code, user_id, producer, producer_event_id), + KEY idx_user_inbox_list (app_code, user_id, message_type, deleted_at_ms, status, sent_at_ms, inbox_message_id), + KEY idx_user_inbox_unread (app_code, user_id, message_type, read_at_ms, deleted_at_ms, status, expire_at_ms), + KEY idx_user_inbox_aggregate (app_code, user_id, aggregate_type, aggregate_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS message_fanout_jobs ( + app_code VARCHAR(32) NOT NULL, + job_id VARCHAR(96) NOT NULL, + command_id VARCHAR(128) NOT NULL, + message_type VARCHAR(32) NOT NULL, + target_scope VARCHAR(64) NOT NULL, + target_filter_json JSON NOT NULL, + template_snapshot_json JSON NOT NULL, + status VARCHAR(32) NOT NULL, + attempt_count INT NOT NULL DEFAULT 0, + cursor_user_id BIGINT NOT NULL DEFAULT 0, + total_count BIGINT NOT NULL DEFAULT 0, + success_count BIGINT NOT NULL DEFAULT 0, + failure_count BIGINT NOT NULL DEFAULT 0, + batch_size INT NOT NULL DEFAULT 500, + next_run_at_ms BIGINT NOT NULL DEFAULT 0, + locked_by VARCHAR(96) NOT NULL DEFAULT '', + locked_until_ms BIGINT NOT NULL DEFAULT 0, + error_message VARCHAR(512) NOT NULL DEFAULT '', + created_by VARCHAR(64) NOT NULL, + created_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, job_id), + UNIQUE KEY uk_message_fanout_command (app_code, command_id), + KEY idx_message_fanout_status (app_code, status, next_run_at_ms, updated_at_ms) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/services/activity-service/internal/app/app.go b/services/activity-service/internal/app/app.go index 3202ec5a..52a1c070 100644 --- a/services/activity-service/internal/app/app.go +++ b/services/activity-service/internal/app/app.go @@ -8,23 +8,32 @@ import ( "time" "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" healthgrpc "google.golang.org/grpc/health/grpc_health_v1" activityv1 "hyapp.local/api/proto/activity/v1" "hyapp/pkg/grpchealth" "hyapp/pkg/logx" + "hyapp/services/activity-service/internal/client" "hyapp/services/activity-service/internal/config" activityservice "hyapp/services/activity-service/internal/service/activity" + messageservice "hyapp/services/activity-service/internal/service/message" mysqlstorage "hyapp/services/activity-service/internal/storage/mysql" grpcserver "hyapp/services/activity-service/internal/transport/grpc" ) // App 装配 activity-service gRPC 入口和底座依赖。 type App struct { - server *grpc.Server - listener net.Listener - health *grpchealth.ServingChecker - mysqlRepo *mysqlstorage.Repository - closeOnce sync.Once + server *grpc.Server + listener net.Listener + health *grpchealth.ServingChecker + mysqlRepo *mysqlstorage.Repository + userConn *grpc.ClientConn + message *messageservice.Service + cfg config.Config + workerCtx context.Context + workerCancel context.CancelFunc + workerWG sync.WaitGroup + closeOnce sync.Once } // New 初始化 activity-service 应用。 @@ -43,24 +52,57 @@ func New(cfg config.Config) (*App, error) { _ = repository.Close() return nil, err } + userConn, err := grpc.Dial(cfg.UserServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + _ = listener.Close() + _ = repository.Close() + return nil, err + } server := grpc.NewServer(grpc.UnaryInterceptor(logx.UnaryServerInterceptor("activity-service"))) svc := activityservice.New(activityservice.Config{NodeID: cfg.NodeID}, repository) + messageSvc := messageservice.New(messageservice.Config{NodeID: cfg.NodeID}, repository, messageservice.WithTargetSource(client.NewGRPCUserTargetSource(userConn))) activityv1.RegisterActivityServiceServer(server, grpcserver.NewServer(svc)) + activityv1.RegisterMessageInboxServiceServer(server, grpcserver.NewMessageServer(messageSvc)) health := grpchealth.NewServingChecker("activity-service") healthgrpc.RegisterHealthServer(server, grpchealth.NewServer(health)) + workerCtx, workerCancel := context.WithCancel(context.Background()) return &App{ - server: server, - listener: listener, - health: health, - mysqlRepo: repository, + server: server, + listener: listener, + health: health, + mysqlRepo: repository, + userConn: userConn, + message: messageSvc, + cfg: cfg, + workerCtx: workerCtx, + workerCancel: workerCancel, }, nil } // Run 启动 gRPC 服务。 func (a *App) Run() error { a.health.MarkServing() + defer func() { + if a.workerCancel != nil { + a.workerCancel() + } + a.workerWG.Wait() + }() + if a.cfg.MessageInbox.FanoutWorker.Enabled { + a.workerWG.Add(1) + go func() { + defer a.workerWG.Done() + a.message.RunFanoutWorker(a.workerCtx, messageservice.FanoutWorkerOptions{ + WorkerID: a.cfg.NodeID, + PollInterval: parseDurationOrZero(a.cfg.MessageInbox.FanoutWorker.PollInterval), + LockTTL: parseDurationOrZero(a.cfg.MessageInbox.FanoutWorker.LockTTL), + BatchSize: a.cfg.MessageInbox.FanoutWorker.BatchSize, + MaxRetry: a.cfg.MessageInbox.FanoutWorker.MaxRetry, + }) + }() + } err := a.server.Serve(a.listener) a.health.MarkStopped() if errors.Is(err, grpc.ErrServerStopped) { @@ -74,10 +116,25 @@ func (a *App) Run() error { func (a *App) Close() { a.closeOnce.Do(func() { a.health.MarkDraining() + if a.workerCancel != nil { + a.workerCancel() + } + a.workerWG.Wait() a.server.GracefulStop() + if a.userConn != nil { + _ = a.userConn.Close() + } if a.mysqlRepo != nil { // MySQL 连接池最后关闭,保证 drain 中的查询或消费提交能完成。 _ = a.mysqlRepo.Close() } }) } + +func parseDurationOrZero(raw string) time.Duration { + duration, err := time.ParseDuration(raw) + if err != nil { + return 0 + } + return duration +} diff --git a/services/activity-service/internal/client/user_target_client.go b/services/activity-service/internal/client/user_target_client.go new file mode 100644 index 00000000..72db3476 --- /dev/null +++ b/services/activity-service/internal/client/user_target_client.go @@ -0,0 +1,40 @@ +package client + +import ( + "context" + + "google.golang.org/grpc" + userv1 "hyapp.local/api/proto/user/v1" + "hyapp/pkg/appcode" + messageservice "hyapp/services/activity-service/internal/service/message" +) + +// GRPCUserTargetSource reads fanout target user IDs from user-service instead of activity owning user data. +type GRPCUserTargetSource struct { + client userv1.UserServiceClient +} + +// NewGRPCUserTargetSource creates a user-service backed target source for message fanout workers. +func NewGRPCUserTargetSource(conn *grpc.ClientConn) *GRPCUserTargetSource { + return &GRPCUserTargetSource{client: userv1.NewUserServiceClient(conn)} +} + +// ListFanoutUserIDs returns a stable user_id cursor page for region/country/all-active fanout scopes. +func (s *GRPCUserTargetSource) ListFanoutUserIDs(ctx context.Context, query messageservice.TargetQuery) ([]int64, int64, bool, error) { + resp, err := s.client.ListUserIDs(ctx, &userv1.ListUserIDsRequest{ + Meta: &userv1.RequestMeta{ + RequestId: "message-fanout-worker", + Caller: "activity-service", + AppCode: appcode.FromContext(ctx), + }, + TargetScope: query.TargetScope, + CursorUserId: query.CursorUserID, + PageSize: int32(query.PageSize), + RegionId: query.RegionID, + Country: query.Country, + }) + if err != nil { + return nil, query.CursorUserID, false, err + } + return resp.GetUserIds(), resp.GetNextCursorUserId(), resp.GetDone(), nil +} diff --git a/services/activity-service/internal/config/config.go b/services/activity-service/internal/config/config.go index 0a32c2e1..07bd00f1 100644 --- a/services/activity-service/internal/config/config.go +++ b/services/activity-service/internal/config/config.go @@ -1,6 +1,10 @@ package config -import "hyapp/pkg/configx" +import ( + "strings" + + "hyapp/pkg/configx" +) // Config 描述 activity-service 启动配置。 type Config struct { @@ -9,9 +13,12 @@ type Config struct { GRPCAddr string `yaml:"grpc_addr"` // MySQLDSN 是活动状态、事件消费幂等和 outbox 的必需存储连接串。 MySQLDSN string `yaml:"mysql_dsn"` + // UserServiceAddr 是 fanout worker 读取目标用户游标的内部 gRPC 地址。 + UserServiceAddr string `yaml:"user_service_addr"` // MySQLAutoMigrate 保留给显式本地迁移;线上 schema 由发布流程或 initdb 管理。 - MySQLAutoMigrate bool `yaml:"mysql_auto_migrate"` - Consumer ConsumerConfig `yaml:"consumer"` + MySQLAutoMigrate bool `yaml:"mysql_auto_migrate"` + Consumer ConsumerConfig `yaml:"consumer"` + MessageInbox MessageInboxConfig `yaml:"message_inbox"` } // ConsumerConfig 保存 room outbox 消费底座配置。 @@ -20,6 +27,21 @@ type ConsumerConfig struct { BatchSize int `yaml:"batch_size"` } +// MessageInboxConfig 保存 App system/activity inbox 的缓存和 fanout worker 参数。 +type MessageInboxConfig struct { + UnreadCacheTTL string `yaml:"unread_cache_ttl"` + FanoutWorker MessageFanoutWorkerConfig `yaml:"fanout_worker"` +} + +// MessageFanoutWorkerConfig 描述后台消息 fanout worker 的 claim、批量和重试策略。 +type MessageFanoutWorkerConfig struct { + Enabled bool `yaml:"enabled"` + PollInterval string `yaml:"poll_interval"` + BatchSize int `yaml:"batch_size"` + LockTTL string `yaml:"lock_ttl"` + MaxRetry int `yaml:"max_retry"` +} + // Default 返回本地默认配置。 func Default() Config { return Config{ @@ -27,11 +49,22 @@ func Default() Config { NodeID: "activity-local", GRPCAddr: ":13006", MySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_activity?parseTime=true&charset=utf8mb4&loc=Local", + UserServiceAddr: "127.0.0.1:13005", MySQLAutoMigrate: false, Consumer: ConsumerConfig{ RoomOutboxPollIntervalMs: 1000, BatchSize: 100, }, + MessageInbox: MessageInboxConfig{ + UnreadCacheTTL: "60s", + FanoutWorker: MessageFanoutWorkerConfig{ + Enabled: true, + PollInterval: "1s", + BatchSize: 500, + LockTTL: "30s", + MaxRetry: 8, + }, + }, } } @@ -45,6 +78,9 @@ func Load(path string) (Config, error) { if err := configx.LoadYAML(path, &cfg); err != nil { return Config{}, err } + if strings.TrimSpace(cfg.UserServiceAddr) == "" { + cfg.UserServiceAddr = Default().UserServiceAddr + } return cfg, nil } diff --git a/services/activity-service/internal/domain/message/message.go b/services/activity-service/internal/domain/message/message.go new file mode 100644 index 00000000..c83adb97 --- /dev/null +++ b/services/activity-service/internal/domain/message/message.go @@ -0,0 +1,165 @@ +// Package message defines the App message tab inbox domain owned by activity-service. +package message + +const ( + // SectionUser is sourced from Tencent IM SDK and never persisted by this service. + SectionUser = "user" + // SectionSystem stores account, wallet, room and application notifications. + SectionSystem = "system" + // SectionActivity stores activity, reward and operational campaign notifications. + SectionActivity = "activity" + + SourceTencentIMSDK = "tencent_im_sdk" + SourceBackend = "backend" + + StatusVisible = "visible" + StatusRecalled = "recalled" + StatusHidden = "hidden" + StatusExpired = "expired" + + FanoutStatusPending = "pending" + FanoutStatusRunning = "running" + FanoutStatusRetrying = "retrying" + FanoutStatusFailed = "failed" + FanoutStatusComplete = "completed" + + TargetScopeSingleUser = "single_user" + TargetScopeUserIDs = "user_ids" + TargetScopeRegion = "region" + TargetScopeCountry = "country" + TargetScopeAllActiveUsers = "all_active_users" +) + +// TabSection is the message tab summary returned to App clients. +type TabSection struct { + Section string + Title string + UnreadCount int64 + Source string +} + +// InboxMessage is the user-visible snapshot stored in user_inbox_messages. +type InboxMessage struct { + AppCode string + MessageID string + UserID int64 + MessageType string + Producer string + ProducerEventID string + ProducerEventType string + AggregateType string + AggregateID string + TemplateID string + TemplateVersion string + Title string + Summary string + Body string + IconURL string + ImageURL string + ActionType string + ActionParam string + Priority int32 + Status string + ReadAtMS int64 + DeletedAtMS int64 + SentAtMS int64 + ExpireAtMS int64 + MetadataJSON string + CreatedAtMS int64 + UpdatedAtMS int64 +} + +// Read reports whether the user has marked the message as read. +func (m InboxMessage) Read() bool { + return m.ReadAtMS > 0 +} + +// MessageTemplate is an active server-owned content template snapshot source. +type MessageTemplate struct { + AppCode string + TemplateID string + TemplateVersion string + MessageType string + Locale string + Title string + Summary string + Body string + IconURL string + ImageURL string + ActionType string + ActionParam string + Status string + CreatedBy string + CreatedAtMS int64 + UpdatedAtMS int64 +} + +// ListQuery is the stable cursor query for system/activity inbox lists. +type ListQuery struct { + UserID int64 + Section string + Limit int + CursorSentAtMS int64 + CursorMessageID string + NowMS int64 +} + +// CreateInput carries a validated single-user inbox creation command. +type CreateInput struct { + TargetUserID int64 + Producer string + ProducerEventID string + ProducerEventType string + MessageType string + AggregateType string + AggregateID string + TemplateID string + TemplateVersion string + Title string + Summary string + Body string + IconURL string + ImageURL string + ActionType string + ActionParam string + Priority int32 + SentAtMS int64 + ExpireAtMS int64 + MetadataJSON string +} + +// FanoutJob stores a background fanout command without executing user selection in the request path. +type FanoutJob struct { + AppCode string + JobID string + CommandID string + MessageType string + TargetScope string + TargetFilterJSON string + TemplateSnapshotJSON string + Status string + AttemptCount int32 + CursorUserID int64 + TotalCount int64 + SuccessCount int64 + FailureCount int64 + BatchSize int32 + NextRunAtMS int64 + LockedBy string + LockedUntilMS int64 + ErrorMessage string + CreatedBy string + CreatedAtMS int64 + UpdatedAtMS int64 +} + +// CreateFanoutInput is the validated admin or producer command for fanout job creation. +type CreateFanoutInput struct { + CommandID string + MessageType string + TargetScope string + TargetFilterJSON string + TemplateSnapshotJSON string + BatchSize int32 + CreatedBy string +} diff --git a/services/activity-service/internal/service/message/fanout_worker.go b/services/activity-service/internal/service/message/fanout_worker.go new file mode 100644 index 00000000..6ba8415e --- /dev/null +++ b/services/activity-service/internal/service/message/fanout_worker.go @@ -0,0 +1,265 @@ +package message + +import ( + "context" + "encoding/json" + "fmt" + "sort" + "strings" + "time" + + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + messagedomain "hyapp/services/activity-service/internal/domain/message" +) + +const ( + defaultFanoutPollInterval = time.Second + defaultFanoutLockTTL = 30 * time.Second + defaultFanoutMaxRetry = 8 + fanoutProducer = "message-fanout" + fanoutProducerEventType = "message_fanout" +) + +// FanoutWorkerOptions carries runtime knobs for the durable fanout worker. +type FanoutWorkerOptions struct { + WorkerID string + PollInterval time.Duration + LockTTL time.Duration + BatchSize int + MaxRetry int +} + +type fanoutTargetFilter struct { + TargetUserID int64 `json:"target_user_id"` + UserID int64 `json:"user_id"` + UserIDs []int64 `json:"user_ids"` + RegionID int64 `json:"region_id"` + Country string `json:"country"` +} + +type fanoutTemplateSnapshot struct { + ProducerEventType string `json:"producer_event_type"` + AggregateType string `json:"aggregate_type"` + AggregateID string `json:"aggregate_id"` + TemplateID string `json:"template_id"` + TemplateVersion string `json:"template_version"` + Title string `json:"title"` + Summary string `json:"summary"` + Body string `json:"body"` + IconURL string `json:"icon_url"` + ImageURL string `json:"image_url"` + ActionType string `json:"action_type"` + ActionParam string `json:"action_param"` + Priority int32 `json:"priority"` + SentAtMS int64 `json:"sent_at_ms"` + ExpireAtMS int64 `json:"expire_at_ms"` + MetadataJSON json.RawMessage `json:"metadata_json"` +} + +// RunFanoutWorker continuously claims and processes fanout jobs until ctx is cancelled. +func (s *Service) RunFanoutWorker(ctx context.Context, options FanoutWorkerOptions) { + options = normalizeFanoutWorkerOptions(options, s.cfg.NodeID) + timer := time.NewTimer(0) + defer timer.Stop() + for { + select { + case <-ctx.Done(): + return + case <-timer.C: + processed, _ := s.ProcessNextFanoutJob(ctx, options) + delay := time.Duration(0) + if !processed { + delay = options.PollInterval + } + timer.Reset(delay) + } + } +} + +// ProcessNextFanoutJob claims one job, processes one target page, then commits progress. +func (s *Service) ProcessNextFanoutJob(ctx context.Context, options FanoutWorkerOptions) (bool, error) { + if err := s.requireRepository(); err != nil { + return false, err + } + options = normalizeFanoutWorkerOptions(options, s.cfg.NodeID) + nowMS := s.now().UnixMilli() + job, claimed, err := s.repository.ClaimFanoutJob(ctx, options.WorkerID, nowMS, nowMS+options.LockTTL.Milliseconds(), options.MaxRetry) + if err != nil || !claimed { + return claimed, err + } + + jobCtx := appcode.WithContext(ctx, job.AppCode) + progress, processErr := s.processFanoutJobPage(jobCtx, job, options) + if processErr != nil { + failErr := s.repository.FailFanoutJob(jobCtx, job.JobID, options.WorkerID, nowMS, nowMS+options.PollInterval.Milliseconds(), options.MaxRetry, processErr.Error()) + if failErr != nil { + return true, failErr + } + return true, processErr + } + if err := s.repository.FinishFanoutJobBatch(jobCtx, job.JobID, options.WorkerID, progress.nextCursorUserID, progress.totalDelta, progress.successDelta, progress.failureDelta, progress.done, nowMS, progress.errorMessage); err != nil { + return true, err + } + return true, nil +} + +type fanoutProgress struct { + nextCursorUserID int64 + totalDelta int64 + successDelta int64 + failureDelta int64 + done bool + errorMessage string +} + +func (s *Service) processFanoutJobPage(ctx context.Context, job messagedomain.FanoutJob, options FanoutWorkerOptions) (fanoutProgress, error) { + var target fanoutTargetFilter + if err := json.Unmarshal([]byte(job.TargetFilterJSON), &target); err != nil { + return fanoutProgress{}, xerr.New(xerr.InvalidArgument, "target_filter_json is invalid") + } + var snapshot fanoutTemplateSnapshot + if err := json.Unmarshal([]byte(job.TemplateSnapshotJSON), &snapshot); err != nil { + return fanoutProgress{}, xerr.New(xerr.InvalidArgument, "template_snapshot_json is invalid") + } + pageSize := int(normalizeBatchSize(firstPositiveInt32(job.BatchSize, int32(options.BatchSize)))) + userIDs, nextCursor, done, err := s.fanoutTargetPage(ctx, job, target, pageSize) + if err != nil { + return fanoutProgress{}, err + } + progress := fanoutProgress{nextCursorUserID: nextCursor, totalDelta: int64(len(userIDs)), done: done} + for _, userID := range userIDs { + _, _, err := s.CreateInboxMessage(ctx, messagedomain.CreateInput{ + TargetUserID: userID, + Producer: fanoutProducer, + ProducerEventID: fmt.Sprintf("fanout:%s:%d", job.JobID, userID), + ProducerEventType: firstNonEmpty(snapshot.ProducerEventType, fanoutProducerEventType), + MessageType: job.MessageType, + AggregateType: snapshot.AggregateType, + AggregateID: snapshot.AggregateID, + TemplateID: snapshot.TemplateID, + TemplateVersion: snapshot.TemplateVersion, + Title: snapshot.Title, + Summary: snapshot.Summary, + Body: snapshot.Body, + IconURL: snapshot.IconURL, + ImageURL: snapshot.ImageURL, + ActionType: snapshot.ActionType, + ActionParam: snapshot.ActionParam, + Priority: snapshot.Priority, + SentAtMS: snapshot.SentAtMS, + ExpireAtMS: snapshot.ExpireAtMS, + MetadataJSON: rawJSONToString(snapshot.MetadataJSON), + }) + if err != nil { + return fanoutProgress{}, err + } + progress.successDelta++ + } + return progress, nil +} + +func (s *Service) fanoutTargetPage(ctx context.Context, job messagedomain.FanoutJob, target fanoutTargetFilter, pageSize int) ([]int64, int64, bool, error) { + switch job.TargetScope { + case messagedomain.TargetScopeSingleUser: + userID := firstPositive(target.TargetUserID, target.UserID) + if userID <= 0 { + return nil, job.CursorUserID, false, xerr.New(xerr.InvalidArgument, "target_user_id is required") + } + if job.CursorUserID >= userID { + return nil, job.CursorUserID, true, nil + } + return []int64{userID}, userID, true, nil + case messagedomain.TargetScopeUserIDs: + return userIDsTargetPage(target.UserIDs, job.CursorUserID, pageSize) + case messagedomain.TargetScopeRegion, messagedomain.TargetScopeCountry, messagedomain.TargetScopeAllActiveUsers: + if s.targetSource == nil { + return nil, job.CursorUserID, false, xerr.New(xerr.Unavailable, "fanout target source is not configured") + } + return s.targetSource.ListFanoutUserIDs(ctx, TargetQuery{ + TargetScope: job.TargetScope, + CursorUserID: job.CursorUserID, + PageSize: pageSize, + RegionID: target.RegionID, + Country: target.Country, + }) + default: + return nil, job.CursorUserID, false, xerr.New(xerr.InvalidArgument, "target_scope is invalid") + } +} + +func userIDsTargetPage(userIDs []int64, cursorUserID int64, pageSize int) ([]int64, int64, bool, error) { + unique := make([]int64, 0, len(userIDs)) + seen := make(map[int64]bool, len(userIDs)) + for _, userID := range userIDs { + if userID <= 0 { + return nil, cursorUserID, false, xerr.New(xerr.InvalidArgument, "user_ids contains invalid value") + } + if !seen[userID] { + seen[userID] = true + unique = append(unique, userID) + } + } + sort.Slice(unique, func(i, j int) bool { return unique[i] < unique[j] }) + start := sort.Search(len(unique), func(i int) bool { return unique[i] > cursorUserID }) + if start >= len(unique) { + return nil, cursorUserID, true, nil + } + end := start + pageSize + if end > len(unique) { + end = len(unique) + } + page := append([]int64(nil), unique[start:end]...) + return page, page[len(page)-1], end >= len(unique), nil +} + +func normalizeFanoutWorkerOptions(options FanoutWorkerOptions, defaultWorkerID string) FanoutWorkerOptions { + options.WorkerID = strings.TrimSpace(options.WorkerID) + if options.WorkerID == "" { + options.WorkerID = firstNonEmpty(defaultWorkerID, "activity-fanout-worker") + } + if options.PollInterval <= 0 { + options.PollInterval = defaultFanoutPollInterval + } + if options.LockTTL <= 0 { + options.LockTTL = defaultFanoutLockTTL + } + if options.BatchSize <= 0 { + options.BatchSize = defaultBatchSize + } + if options.MaxRetry <= 0 { + options.MaxRetry = defaultFanoutMaxRetry + } + return options +} + +func rawJSONToString(raw json.RawMessage) string { + raw = json.RawMessage([]byte(strings.TrimSpace(string(raw)))) + if len(raw) == 0 || string(raw) == "null" { + return "" + } + var text string + if err := json.Unmarshal(raw, &text); err == nil { + return strings.TrimSpace(text) + } + return string(raw) +} + +func firstNonEmpty(values ...string) string { + for _, value := range values { + value = strings.TrimSpace(value) + if value != "" { + return value + } + } + return "" +} + +func firstPositiveInt32(values ...int32) int32 { + for _, value := range values { + if value > 0 { + return value + } + } + return 0 +} diff --git a/services/activity-service/internal/service/message/service.go b/services/activity-service/internal/service/message/service.go new file mode 100644 index 00000000..aea15f5d --- /dev/null +++ b/services/activity-service/internal/service/message/service.go @@ -0,0 +1,549 @@ +// Package message implements the App system/activity message inbox owner. +package message + +import ( + "context" + "encoding/base64" + "encoding/json" + "strings" + "time" + "unicode/utf8" + + "hyapp/pkg/idgen" + "hyapp/pkg/xerr" + messagedomain "hyapp/services/activity-service/internal/domain/message" +) + +const ( + defaultPageSize = 20 + maxPageSize = 100 + defaultBatchSize = 500 + maxBatchSize = 5000 +) + +// Repository is the storage boundary for MySQL-backed inbox facts. +type Repository interface { + GetActiveMessageTemplate(ctx context.Context, templateID string, templateVersion string, messageType string) (messagedomain.MessageTemplate, bool, error) + SaveInboxMessage(ctx context.Context, message messagedomain.InboxMessage) (bool, messagedomain.InboxMessage, error) + CountUnreadInboxMessages(ctx context.Context, userID int64, section string, nowMS int64) (int64, error) + ListInboxMessages(ctx context.Context, query messagedomain.ListQuery) ([]messagedomain.InboxMessage, error) + MarkInboxMessageRead(ctx context.Context, userID int64, messageID string, nowMS int64) (messagedomain.InboxMessage, error) + MarkInboxSectionRead(ctx context.Context, userID int64, section string, nowMS int64) (int64, error) + DeleteInboxMessage(ctx context.Context, userID int64, messageID string, nowMS int64) error + SaveFanoutJob(ctx context.Context, job messagedomain.FanoutJob) (bool, messagedomain.FanoutJob, error) + ClaimFanoutJob(ctx context.Context, workerID string, nowMS int64, lockUntilMS int64, maxRetry int) (messagedomain.FanoutJob, bool, error) + FinishFanoutJobBatch(ctx context.Context, jobID string, workerID string, cursorUserID int64, totalDelta int64, successDelta int64, failureDelta int64, done bool, nowMS int64, errorMessage string) error + FailFanoutJob(ctx context.Context, jobID string, workerID string, nowMS int64, nextRunAtMS int64, maxRetry int, errorMessage string) error +} + +// Config keeps service-level knobs that do not belong in transport code. +type Config struct { + NodeID string +} + +// TargetQuery describes the user-service cursor query needed by fanout worker scopes. +type TargetQuery struct { + TargetScope string + CursorUserID int64 + PageSize int + RegionID int64 + Country string +} + +// TargetSource hides user-service gRPC behind a minimal page query. +type TargetSource interface { + ListFanoutUserIDs(ctx context.Context, query TargetQuery) ([]int64, int64, bool, error) +} + +// Option adjusts message service dependencies. +type Option func(*Service) + +// Service owns system/activity inbox business rules. +type Service struct { + cfg Config + repository Repository + targetSource TargetSource + now func() time.Time +} + +// New creates a message inbox service using MySQL as source of truth. +func New(cfg Config, repository Repository, options ...Option) *Service { + service := &Service{cfg: cfg, repository: repository, now: time.Now} + for _, option := range options { + option(service) + } + return service +} + +// WithTargetSource connects fanout worker scopes to user-service without coupling to its storage. +func WithTargetSource(source TargetSource) Option { + return func(s *Service) { + s.targetSource = source + } +} + +// SetClock injects deterministic time for tests. +func (s *Service) SetClock(now func() time.Time) { + if now != nil { + s.now = now + } +} + +// ListMessageTabs returns the fixed App message tab summary. +func (s *Service) ListMessageTabs(ctx context.Context, userID int64) ([]messagedomain.TabSection, error) { + if err := s.requireRepository(); err != nil { + return nil, err + } + if userID <= 0 { + return nil, xerr.New(xerr.InvalidArgument, "user_id is required") + } + nowMS := s.now().UnixMilli() + systemUnread, err := s.repository.CountUnreadInboxMessages(ctx, userID, messagedomain.SectionSystem, nowMS) + if err != nil { + return nil, err + } + activityUnread, err := s.repository.CountUnreadInboxMessages(ctx, userID, messagedomain.SectionActivity, nowMS) + if err != nil { + return nil, err + } + + return []messagedomain.TabSection{ + {Section: messagedomain.SectionUser, Title: "用户", UnreadCount: 0, Source: messagedomain.SourceTencentIMSDK}, + {Section: messagedomain.SectionSystem, Title: "系统", UnreadCount: systemUnread, Source: messagedomain.SourceBackend}, + {Section: messagedomain.SectionActivity, Title: "活动", UnreadCount: activityUnread, Source: messagedomain.SourceBackend}, + }, nil +} + +// ListInboxMessages reads one cursor page for a backend-owned section. +func (s *Service) ListInboxMessages(ctx context.Context, userID int64, section string, pageSize int32, pageToken string) ([]messagedomain.InboxMessage, string, error) { + if err := s.requireRepository(); err != nil { + return nil, "", err + } + if userID <= 0 { + return nil, "", xerr.New(xerr.InvalidArgument, "user_id is required") + } + section = normalizeSection(section) + if !backendSection(section) { + return nil, "", xerr.New(xerr.InvalidSection, "section is invalid") + } + limit := normalizePageSize(pageSize) + cursor, err := decodeCursor(section, pageToken) + if err != nil { + return nil, "", err + } + + messages, err := s.repository.ListInboxMessages(ctx, messagedomain.ListQuery{ + UserID: userID, + Section: section, + Limit: limit + 1, + CursorSentAtMS: cursor.SentAtMS, + CursorMessageID: cursor.MessageID, + NowMS: s.now().UnixMilli(), + }) + if err != nil { + return nil, "", err + } + if len(messages) <= limit { + return messages, "", nil + } + page := messages[:limit] + next := encodeCursor(section, page[len(page)-1]) + return page, next, nil +} + +// MarkInboxMessageRead marks a single visible message read while preserving first read time. +func (s *Service) MarkInboxMessageRead(ctx context.Context, userID int64, messageID string) (messagedomain.InboxMessage, error) { + if err := s.requireRepository(); err != nil { + return messagedomain.InboxMessage{}, err + } + messageID = strings.TrimSpace(messageID) + if userID <= 0 || messageID == "" { + return messagedomain.InboxMessage{}, xerr.New(xerr.InvalidArgument, "user_id and message_id are required") + } + return s.repository.MarkInboxMessageRead(ctx, userID, messageID, s.now().UnixMilli()) +} + +// MarkInboxSectionRead marks all visible unread messages in a backend section. +func (s *Service) MarkInboxSectionRead(ctx context.Context, userID int64, section string) (int64, error) { + if err := s.requireRepository(); err != nil { + return 0, err + } + section = normalizeSection(section) + if userID <= 0 || !backendSection(section) { + return 0, xerr.New(xerr.InvalidSection, "section is invalid") + } + return s.repository.MarkInboxSectionRead(ctx, userID, section, s.now().UnixMilli()) +} + +// DeleteInboxMessage hides a visible message for the current user. +func (s *Service) DeleteInboxMessage(ctx context.Context, userID int64, messageID string) error { + if err := s.requireRepository(); err != nil { + return err + } + messageID = strings.TrimSpace(messageID) + if userID <= 0 || messageID == "" { + return xerr.New(xerr.InvalidArgument, "user_id and message_id are required") + } + return s.repository.DeleteInboxMessage(ctx, userID, messageID, s.now().UnixMilli()) +} + +// CreateInboxMessage materializes one producer event into a user inbox row. +func (s *Service) CreateInboxMessage(ctx context.Context, input messagedomain.CreateInput) (messagedomain.InboxMessage, bool, error) { + if err := s.requireRepository(); err != nil { + return messagedomain.InboxMessage{}, false, err + } + input = normalizeCreateInput(input) + if err := s.fillTemplateSnapshot(ctx, &input); err != nil { + return messagedomain.InboxMessage{}, false, err + } + if err := validateCreateInput(input); err != nil { + return messagedomain.InboxMessage{}, false, err + } + + nowMS := s.now().UnixMilli() + message := messagedomain.InboxMessage{ + MessageID: idgen.New("msg"), + UserID: input.TargetUserID, + MessageType: input.MessageType, + Producer: input.Producer, + ProducerEventID: input.ProducerEventID, + ProducerEventType: input.ProducerEventType, + AggregateType: input.AggregateType, + AggregateID: input.AggregateID, + TemplateID: input.TemplateID, + TemplateVersion: input.TemplateVersion, + Title: input.Title, + Summary: input.Summary, + Body: input.Body, + IconURL: input.IconURL, + ImageURL: input.ImageURL, + ActionType: input.ActionType, + ActionParam: input.ActionParam, + Priority: input.Priority, + Status: messagedomain.StatusVisible, + SentAtMS: firstPositive(input.SentAtMS, nowMS), + ExpireAtMS: input.ExpireAtMS, + MetadataJSON: input.MetadataJSON, + CreatedAtMS: nowMS, + UpdatedAtMS: nowMS, + } + created, existing, err := s.repository.SaveInboxMessage(ctx, message) + if err != nil { + return messagedomain.InboxMessage{}, false, err + } + if !created { + if !sameInboxPayload(existing, message) { + return messagedomain.InboxMessage{}, false, xerr.New(xerr.ProducerEventConflict, "producer event payload conflicts with existing inbox message") + } + return existing, false, nil + } + return existing, true, nil +} + +// CreateFanoutJob records an async fanout job and keeps large broadcasts off the request path. +func (s *Service) CreateFanoutJob(ctx context.Context, input messagedomain.CreateFanoutInput) (messagedomain.FanoutJob, bool, error) { + if err := s.requireRepository(); err != nil { + return messagedomain.FanoutJob{}, false, err + } + input = normalizeFanoutInput(input) + if err := validateFanoutInput(input); err != nil { + return messagedomain.FanoutJob{}, false, err + } + nowMS := s.now().UnixMilli() + job := messagedomain.FanoutJob{ + JobID: idgen.New("mfan"), + CommandID: input.CommandID, + MessageType: input.MessageType, + TargetScope: input.TargetScope, + TargetFilterJSON: input.TargetFilterJSON, + TemplateSnapshotJSON: input.TemplateSnapshotJSON, + Status: messagedomain.FanoutStatusPending, + BatchSize: normalizeBatchSize(input.BatchSize), + CreatedBy: input.CreatedBy, + CreatedAtMS: nowMS, + UpdatedAtMS: nowMS, + } + created, existing, err := s.repository.SaveFanoutJob(ctx, job) + if err != nil { + return messagedomain.FanoutJob{}, false, err + } + if !created { + if !sameFanoutPayload(existing, job) { + return messagedomain.FanoutJob{}, false, xerr.New(xerr.RequestConflict, "fanout command payload conflicts with existing job") + } + return existing, false, nil + } + return existing, true, nil +} + +func (s *Service) requireRepository() error { + if s == nil || s.repository == nil { + return xerr.New(xerr.Unavailable, "message repository is not configured") + } + return nil +} + +func (s *Service) fillTemplateSnapshot(ctx context.Context, input *messagedomain.CreateInput) error { + if input.Title != "" || input.Summary != "" { + return nil + } + if input.TemplateID == "" || input.TemplateVersion == "" { + return nil + } + template, exists, err := s.repository.GetActiveMessageTemplate(ctx, input.TemplateID, input.TemplateVersion, input.MessageType) + if err != nil { + return err + } + if !exists { + return xerr.New(xerr.NotFound, "message template not found") + } + input.Title = template.Title + input.Summary = template.Summary + input.Body = template.Body + input.IconURL = template.IconURL + input.ImageURL = template.ImageURL + input.ActionType = template.ActionType + input.ActionParam = template.ActionParam + return nil +} + +type pageCursor struct { + Section string `json:"section"` + SentAtMS int64 `json:"sent_at_ms"` + MessageID string `json:"message_id"` +} + +func encodeCursor(section string, message messagedomain.InboxMessage) string { + payload, err := json.Marshal(pageCursor{Section: section, SentAtMS: message.SentAtMS, MessageID: message.MessageID}) + if err != nil { + return "" + } + return base64.RawURLEncoding.EncodeToString(payload) +} + +func decodeCursor(section string, encoded string) (pageCursor, error) { + encoded = strings.TrimSpace(encoded) + if encoded == "" { + return pageCursor{Section: section}, nil + } + raw, err := base64.RawURLEncoding.DecodeString(encoded) + if err != nil { + return pageCursor{}, xerr.New(xerr.PageTokenInvalid, "page token is invalid") + } + var cursor pageCursor + if err := json.Unmarshal(raw, &cursor); err != nil { + return pageCursor{}, xerr.New(xerr.PageTokenInvalid, "page token is invalid") + } + if cursor.Section != section || cursor.SentAtMS <= 0 || strings.TrimSpace(cursor.MessageID) == "" { + return pageCursor{}, xerr.New(xerr.PageTokenInvalid, "page token is invalid") + } + return cursor, nil +} + +func normalizeCreateInput(input messagedomain.CreateInput) messagedomain.CreateInput { + input.Producer = strings.TrimSpace(input.Producer) + input.ProducerEventID = strings.TrimSpace(input.ProducerEventID) + input.ProducerEventType = strings.TrimSpace(input.ProducerEventType) + input.MessageType = normalizeSection(input.MessageType) + input.AggregateType = strings.TrimSpace(input.AggregateType) + input.AggregateID = strings.TrimSpace(input.AggregateID) + input.TemplateID = strings.TrimSpace(input.TemplateID) + input.TemplateVersion = strings.TrimSpace(input.TemplateVersion) + input.Title = strings.TrimSpace(input.Title) + input.Summary = strings.TrimSpace(input.Summary) + input.Body = strings.TrimSpace(input.Body) + input.IconURL = strings.TrimSpace(input.IconURL) + input.ImageURL = strings.TrimSpace(input.ImageURL) + input.ActionType = strings.TrimSpace(input.ActionType) + input.ActionParam = strings.TrimSpace(input.ActionParam) + input.MetadataJSON = strings.TrimSpace(input.MetadataJSON) + return input +} + +func validateCreateInput(input messagedomain.CreateInput) error { + if input.TargetUserID <= 0 || input.Producer == "" || input.ProducerEventID == "" { + return xerr.New(xerr.InvalidArgument, "target_user_id, producer and producer_event_id are required") + } + if !backendSection(input.MessageType) { + return xerr.New(xerr.InvalidSection, "message_type is invalid") + } + for _, field := range []struct { + name string + value string + max int + }{ + {"producer", input.Producer, 64}, + {"producer_event_id", input.ProducerEventID, 128}, + {"producer_event_type", input.ProducerEventType, 96}, + {"aggregate_type", input.AggregateType, 64}, + {"aggregate_id", input.AggregateID, 128}, + {"template_id", input.TemplateID, 96}, + {"template_version", input.TemplateVersion, 64}, + {"title", input.Title, 160}, + {"summary", input.Summary, 512}, + {"body", input.Body, 2048}, + {"icon_url", input.IconURL, 512}, + {"image_url", input.ImageURL, 512}, + {"action_type", input.ActionType, 64}, + {"action_param", input.ActionParam, 1024}, + } { + if utf8.RuneCountInString(field.value) > field.max { + return xerr.New(xerr.InvalidArgument, field.name+" is too long") + } + } + if input.Title == "" || input.Summary == "" { + return xerr.New(xerr.InvalidArgument, "title and summary are required") + } + if !allowedActionType(input.ActionType) { + return xerr.New(xerr.InvalidArgument, "action_type is invalid") + } + if input.ExpireAtMS > 0 && input.SentAtMS > 0 && input.ExpireAtMS <= input.SentAtMS { + return xerr.New(xerr.InvalidArgument, "expire_at_ms must be after sent_at_ms") + } + if input.MetadataJSON != "" && !json.Valid([]byte(input.MetadataJSON)) { + return xerr.New(xerr.InvalidArgument, "metadata_json is invalid") + } + return nil +} + +func normalizeFanoutInput(input messagedomain.CreateFanoutInput) messagedomain.CreateFanoutInput { + input.CommandID = strings.TrimSpace(input.CommandID) + input.MessageType = normalizeSection(input.MessageType) + input.TargetScope = strings.TrimSpace(input.TargetScope) + input.TargetFilterJSON = strings.TrimSpace(input.TargetFilterJSON) + input.TemplateSnapshotJSON = strings.TrimSpace(input.TemplateSnapshotJSON) + input.CreatedBy = strings.TrimSpace(input.CreatedBy) + return input +} + +func validateFanoutInput(input messagedomain.CreateFanoutInput) error { + if input.CommandID == "" || input.TargetScope == "" || input.CreatedBy == "" { + return xerr.New(xerr.InvalidArgument, "command_id, target_scope and created_by are required") + } + if !backendSection(input.MessageType) { + return xerr.New(xerr.InvalidSection, "message_type is invalid") + } + if !allowedFanoutScope(input.TargetScope) { + return xerr.New(xerr.InvalidArgument, "target_scope is invalid") + } + if input.TargetFilterJSON == "" || !json.Valid([]byte(input.TargetFilterJSON)) { + return xerr.New(xerr.InvalidArgument, "target_filter_json is invalid") + } + if input.TemplateSnapshotJSON == "" || !json.Valid([]byte(input.TemplateSnapshotJSON)) { + return xerr.New(xerr.InvalidArgument, "template_snapshot_json is invalid") + } + return nil +} + +func normalizeSection(section string) string { + return strings.ToLower(strings.TrimSpace(section)) +} + +func backendSection(section string) bool { + return section == messagedomain.SectionSystem || section == messagedomain.SectionActivity +} + +func normalizePageSize(value int32) int { + if value <= 0 { + return defaultPageSize + } + if value > maxPageSize { + return maxPageSize + } + return int(value) +} + +func normalizeBatchSize(value int32) int32 { + if value <= 0 { + return defaultBatchSize + } + if value > maxBatchSize { + return maxBatchSize + } + return value +} + +func allowedActionType(actionType string) bool { + switch actionType { + case "", "wallet_withdraw_detail", "host_application_detail", "activity_detail", "room_detail", "user_profile", "app_h5", "coin_seller_transfer_detail": + return true + default: + return false + } +} + +func allowedFanoutScope(scope string) bool { + switch scope { + case messagedomain.TargetScopeSingleUser, messagedomain.TargetScopeUserIDs, messagedomain.TargetScopeRegion, messagedomain.TargetScopeCountry, messagedomain.TargetScopeAllActiveUsers: + return true + default: + return false + } +} + +func firstPositive(values ...int64) int64 { + for _, value := range values { + if value > 0 { + return value + } + } + return 0 +} + +func sameInboxPayload(existing messagedomain.InboxMessage, next messagedomain.InboxMessage) bool { + return existing.UserID == next.UserID && + existing.MessageType == next.MessageType && + existing.Producer == next.Producer && + existing.ProducerEventID == next.ProducerEventID && + existing.ProducerEventType == next.ProducerEventType && + existing.AggregateType == next.AggregateType && + existing.AggregateID == next.AggregateID && + existing.TemplateID == next.TemplateID && + existing.TemplateVersion == next.TemplateVersion && + existing.Title == next.Title && + existing.Summary == next.Summary && + existing.Body == next.Body && + existing.IconURL == next.IconURL && + existing.ImageURL == next.ImageURL && + existing.ActionType == next.ActionType && + existing.ActionParam == next.ActionParam && + existing.Priority == next.Priority && + existing.ExpireAtMS == next.ExpireAtMS && + sameJSONText(existing.MetadataJSON, next.MetadataJSON) +} + +func sameFanoutPayload(existing messagedomain.FanoutJob, next messagedomain.FanoutJob) bool { + return existing.CommandID == next.CommandID && + existing.MessageType == next.MessageType && + existing.TargetScope == next.TargetScope && + sameJSONText(existing.TargetFilterJSON, next.TargetFilterJSON) && + sameJSONText(existing.TemplateSnapshotJSON, next.TemplateSnapshotJSON) && + existing.BatchSize == next.BatchSize && + existing.CreatedBy == next.CreatedBy +} + +func sameJSONText(left string, right string) bool { + left = strings.TrimSpace(left) + right = strings.TrimSpace(right) + if left == "" || left == "null" { + return right == "" || right == "null" + } + leftCanonical, leftOK := canonicalJSON(left) + rightCanonical, rightOK := canonicalJSON(right) + if leftOK && rightOK { + return leftCanonical == rightCanonical + } + return left == right +} + +func canonicalJSON(value string) (string, bool) { + var parsed any + if err := json.Unmarshal([]byte(value), &parsed); err != nil { + return "", false + } + encoded, err := json.Marshal(parsed) + if err != nil { + return "", false + } + return string(encoded), true +} diff --git a/services/activity-service/internal/service/message/service_test.go b/services/activity-service/internal/service/message/service_test.go new file mode 100644 index 00000000..eaa63903 --- /dev/null +++ b/services/activity-service/internal/service/message/service_test.go @@ -0,0 +1,229 @@ +package message_test + +import ( + "context" + "testing" + "time" + + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + messagedomain "hyapp/services/activity-service/internal/domain/message" + messageservice "hyapp/services/activity-service/internal/service/message" + "hyapp/services/activity-service/internal/testutil/mysqltest" +) + +func TestInboxMessageLifecycleUsesMySQLFacts(t *testing.T) { + ctx := appcode.WithContext(context.Background(), "lalu") + repository := mysqltest.NewRepository(t) + now := time.UnixMilli(1_800_000_000_000) + svc := messageservice.New(messageservice.Config{NodeID: "activity-a"}, repository) + svc.SetClock(func() time.Time { return now }) + + first, created, err := svc.CreateInboxMessage(ctx, messagedomain.CreateInput{ + TargetUserID: 42, + Producer: "wallet-service", + ProducerEventID: "withdraw-approved-1", + ProducerEventType: "withdraw_approved", + MessageType: messagedomain.SectionSystem, + Title: "提现审核通过", + Summary: "你的提现申请已通过。", + ActionType: "wallet_withdraw_detail", + ActionParam: "withdrawal_id=wd_01", + SentAtMS: 1_800_000_000_000, + }) + if err != nil || !created { + t.Fatalf("CreateInboxMessage failed: created=%v message=%+v err=%v", created, first, err) + } + second, created, err := svc.CreateInboxMessage(ctx, messagedomain.CreateInput{ + TargetUserID: 42, + Producer: "activity-service", + ProducerEventID: "reward-1", + ProducerEventType: "activity_reward", + MessageType: messagedomain.SectionActivity, + Title: "活动奖励到账", + Summary: "你的活动奖励已发放。", + ActionType: "activity_detail", + ActionParam: "activity_id=act_01", + SentAtMS: 1_800_000_000_100, + }) + if err != nil || !created { + t.Fatalf("CreateInboxMessage activity failed: created=%v message=%+v err=%v", created, second, err) + } + if _, created, err := svc.CreateInboxMessage(ctx, messagedomain.CreateInput{ + TargetUserID: 42, + Producer: "wallet-service", + ProducerEventID: "withdraw-approved-1", + ProducerEventType: "withdraw_approved", + MessageType: messagedomain.SectionSystem, + Title: "提现审核通过", + Summary: "你的提现申请已通过。", + ActionType: "wallet_withdraw_detail", + ActionParam: "withdrawal_id=wd_01", + SentAtMS: 1_800_000_000_000, + }); err != nil || created { + t.Fatalf("duplicate producer event should be idempotent: created=%v err=%v", created, err) + } + if _, _, err := svc.CreateInboxMessage(ctx, messagedomain.CreateInput{ + TargetUserID: 42, + Producer: "wallet-service", + ProducerEventID: "withdraw-approved-1", + MessageType: messagedomain.SectionSystem, + Title: "不同标题", + Summary: "你的提现申请已通过。", + ActionType: "wallet_withdraw_detail", + ActionParam: "withdrawal_id=wd_01", + SentAtMS: 1_800_000_000_000, + }); !xerr.IsCode(err, xerr.ProducerEventConflict) { + t.Fatalf("conflicting producer event should fail, got %v", err) + } + + tabs, err := svc.ListMessageTabs(ctx, 42) + if err != nil { + t.Fatalf("ListMessageTabs failed: %v", err) + } + if len(tabs) != 3 || tabs[0].Section != messagedomain.SectionUser || tabs[0].Source != messagedomain.SourceTencentIMSDK || tabs[1].UnreadCount != 1 || tabs[2].UnreadCount != 1 { + t.Fatalf("unexpected tabs: %+v", tabs) + } + + items, next, err := svc.ListInboxMessages(ctx, 42, messagedomain.SectionSystem, 1, "") + if err != nil || next != "" || len(items) != 1 || items[0].MessageID != first.MessageID || items[0].Read() { + t.Fatalf("system list mismatch: items=%+v next=%q err=%v", items, next, err) + } + + read, err := svc.MarkInboxMessageRead(ctx, 42, first.MessageID) + if err != nil || !read.Read() || read.ReadAtMS != now.UnixMilli() { + t.Fatalf("MarkInboxMessageRead failed: %+v err=%v", read, err) + } + now = now.Add(time.Minute) + readAgain, err := svc.MarkInboxMessageRead(ctx, 42, first.MessageID) + if err != nil || readAgain.ReadAtMS != read.ReadAtMS { + t.Fatalf("repeat read must preserve first read time: first=%+v second=%+v err=%v", read, readAgain, err) + } + readCount, err := svc.MarkInboxSectionRead(ctx, 42, messagedomain.SectionActivity) + if err != nil || readCount != 1 { + t.Fatalf("read-all activity failed: count=%d err=%v", readCount, err) + } + if err := svc.DeleteInboxMessage(ctx, 99, first.MessageID); !xerr.IsCode(err, xerr.MessageNotFound) { + t.Fatalf("other user delete must look not found, got %v", err) + } + if err := svc.DeleteInboxMessage(ctx, 42, first.MessageID); err != nil { + t.Fatalf("DeleteInboxMessage failed: %v", err) + } + items, _, err = svc.ListInboxMessages(ctx, 42, messagedomain.SectionSystem, 20, "") + if err != nil || len(items) != 0 { + t.Fatalf("deleted message should not be listed: items=%+v err=%v", items, err) + } +} + +func TestInboxListCursorAndExpiredMessages(t *testing.T) { + ctx := appcode.WithContext(context.Background(), "lalu") + repository := mysqltest.NewRepository(t) + now := time.UnixMilli(1_800_000_010_000) + svc := messageservice.New(messageservice.Config{NodeID: "activity-a"}, repository) + svc.SetClock(func() time.Time { return now }) + + for _, input := range []messagedomain.CreateInput{ + {TargetUserID: 42, Producer: "admin", ProducerEventID: "system-old", MessageType: messagedomain.SectionSystem, Title: "旧消息", Summary: "旧摘要", SentAtMS: 1_800_000_000_000}, + {TargetUserID: 42, Producer: "admin", ProducerEventID: "system-new", MessageType: messagedomain.SectionSystem, Title: "新消息", Summary: "新摘要", SentAtMS: 1_800_000_001_000}, + {TargetUserID: 42, Producer: "admin", ProducerEventID: "system-expired", MessageType: messagedomain.SectionSystem, Title: "过期消息", Summary: "过期摘要", SentAtMS: 1_800_000_000_000, ExpireAtMS: 1_800_000_005_000}, + } { + if _, _, err := svc.CreateInboxMessage(ctx, input); err != nil { + t.Fatalf("CreateInboxMessage failed: %+v err=%v", input, err) + } + } + + firstPage, next, err := svc.ListInboxMessages(ctx, 42, messagedomain.SectionSystem, 1, "") + if err != nil || len(firstPage) != 1 || firstPage[0].Title != "新消息" || next == "" { + t.Fatalf("first page mismatch: items=%+v next=%q err=%v", firstPage, next, err) + } + secondPage, next, err := svc.ListInboxMessages(ctx, 42, messagedomain.SectionSystem, 1, next) + if err != nil || len(secondPage) != 1 || secondPage[0].Title != "旧消息" || next != "" { + t.Fatalf("second page mismatch: items=%+v next=%q err=%v", secondPage, next, err) + } + if _, _, err := svc.ListInboxMessages(ctx, 42, messagedomain.SectionActivity, 1, "bad-token"); !xerr.IsCode(err, xerr.PageTokenInvalid) { + t.Fatalf("invalid cursor should fail with PAGE_TOKEN_INVALID, got %v", err) + } + tabs, err := svc.ListMessageTabs(ctx, 42) + if err != nil || tabs[1].UnreadCount != 2 { + t.Fatalf("expired message must not count unread: tabs=%+v err=%v", tabs, err) + } +} + +func TestCreateFanoutJobIsIdempotentAndDetectsCommandConflict(t *testing.T) { + ctx := appcode.WithContext(context.Background(), "lalu") + repository := mysqltest.NewRepository(t) + svc := messageservice.New(messageservice.Config{NodeID: "activity-a"}, repository) + svc.SetClock(func() time.Time { return time.UnixMilli(1_800_000_020_000) }) + + input := messagedomain.CreateFanoutInput{ + CommandID: "cmd-fanout-1", + MessageType: messagedomain.SectionActivity, + TargetScope: "user_ids", + TargetFilterJSON: `{"user_ids":[42,43]}`, + TemplateSnapshotJSON: `{"title":"活动上线","summary":"新活动已上线"}`, + BatchSize: 500, + CreatedBy: "admin:1", + } + job, created, err := svc.CreateFanoutJob(ctx, input) + if err != nil || !created || job.JobID == "" || job.Status != messagedomain.FanoutStatusPending { + t.Fatalf("CreateFanoutJob failed: created=%v job=%+v err=%v", created, job, err) + } + retry, created, err := svc.CreateFanoutJob(ctx, input) + if err != nil || created || retry.JobID != job.JobID { + t.Fatalf("retry should return existing job: created=%v retry=%+v err=%v", created, retry, err) + } + input.TargetFilterJSON = `{"user_ids":[99]}` + if _, _, err := svc.CreateFanoutJob(ctx, input); !xerr.IsCode(err, xerr.RequestConflict) { + t.Fatalf("conflicting fanout command should fail, got %v", err) + } +} + +func TestFanoutWorkerMaterializesUserIDTargetsByCursor(t *testing.T) { + ctx := appcode.WithContext(context.Background(), "lalu") + repository := mysqltest.NewRepository(t) + now := time.UnixMilli(1_800_000_030_000) + svc := messageservice.New(messageservice.Config{NodeID: "activity-a"}, repository) + svc.SetClock(func() time.Time { return now }) + + job, created, err := svc.CreateFanoutJob(ctx, messagedomain.CreateFanoutInput{ + CommandID: "cmd-fanout-worker-1", + MessageType: messagedomain.SectionActivity, + TargetScope: messagedomain.TargetScopeUserIDs, + TargetFilterJSON: `{"user_ids":[44,42,43,42]}`, + TemplateSnapshotJSON: `{"title":"活动上线","summary":"新活动已上线","action_type":"activity_detail","action_param":"activity_id=act_01","metadata_json":{"campaign":"spring"}}`, + BatchSize: 2, + CreatedBy: "admin:1", + }) + if err != nil || !created { + t.Fatalf("CreateFanoutJob failed: created=%v job=%+v err=%v", created, job, err) + } + + processed, err := svc.ProcessNextFanoutJob(ctx, messageservice.FanoutWorkerOptions{WorkerID: "worker-a", BatchSize: 2, MaxRetry: 3, LockTTL: time.Minute}) + if err != nil || !processed { + t.Fatalf("first fanout batch failed: processed=%v err=%v", processed, err) + } + stored, exists, err := repository.GetFanoutJobByCommand(ctx, "cmd-fanout-worker-1") + if err != nil || !exists || stored.Status != messagedomain.FanoutStatusPending || stored.CursorUserID != 43 || stored.SuccessCount != 2 || stored.TotalCount != 2 || stored.AttemptCount != 1 { + t.Fatalf("first batch progress mismatch: exists=%v job=%+v err=%v", exists, stored, err) + } + for _, userID := range []int64{42, 43} { + items, _, err := svc.ListInboxMessages(ctx, userID, messagedomain.SectionActivity, 20, "") + if err != nil || len(items) != 1 || items[0].Title != "活动上线" || items[0].ActionType != "activity_detail" { + t.Fatalf("user %d inbox mismatch after first batch: items=%+v err=%v", userID, items, err) + } + } + + now = now.Add(time.Second) + processed, err = svc.ProcessNextFanoutJob(ctx, messageservice.FanoutWorkerOptions{WorkerID: "worker-a", BatchSize: 2, MaxRetry: 3, LockTTL: time.Minute}) + if err != nil || !processed { + t.Fatalf("second fanout batch failed: processed=%v err=%v", processed, err) + } + stored, exists, err = repository.GetFanoutJobByCommand(ctx, "cmd-fanout-worker-1") + if err != nil || !exists || stored.Status != messagedomain.FanoutStatusComplete || stored.CursorUserID != 44 || stored.SuccessCount != 3 || stored.TotalCount != 3 || stored.AttemptCount != 2 { + t.Fatalf("second batch progress mismatch: exists=%v job=%+v err=%v", exists, stored, err) + } + items, _, err := svc.ListInboxMessages(ctx, 44, messagedomain.SectionActivity, 20, "") + if err != nil || len(items) != 1 || items[0].Summary != "新活动已上线" { + t.Fatalf("last user inbox mismatch: items=%+v err=%v", items, err) + } +} diff --git a/services/activity-service/internal/storage/mysql/message_repository.go b/services/activity-service/internal/storage/mysql/message_repository.go new file mode 100644 index 00000000..747e0004 --- /dev/null +++ b/services/activity-service/internal/storage/mysql/message_repository.go @@ -0,0 +1,564 @@ +package mysql + +import ( + "context" + "database/sql" + "errors" + + mysqlerr "github.com/go-sql-driver/mysql" + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + messagedomain "hyapp/services/activity-service/internal/domain/message" +) + +// SaveInboxMessage inserts one materialized user inbox row and returns an existing row on producer idempotency hits. +func (r *Repository) SaveInboxMessage(ctx context.Context, message messagedomain.InboxMessage) (bool, messagedomain.InboxMessage, error) { + if r == nil || r.db == nil { + return false, messagedomain.InboxMessage{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + app := appcode.FromContext(ctx) + message.AppCode = app + + _, err := r.db.ExecContext(ctx, ` + INSERT INTO user_inbox_messages ( + app_code, inbox_message_id, user_id, message_type, producer, producer_event_id, + producer_event_type, aggregate_type, aggregate_id, template_id, template_version, + title, summary, body, icon_url, image_url, action_type, action_param, priority, + status, read_at_ms, deleted_at_ms, sent_at_ms, expire_at_ms, metadata_json, created_at_ms, updated_at_ms + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?, ?)`, + app, + message.MessageID, + message.UserID, + message.MessageType, + message.Producer, + message.ProducerEventID, + message.ProducerEventType, + message.AggregateType, + message.AggregateID, + message.TemplateID, + message.TemplateVersion, + message.Title, + message.Summary, + message.Body, + message.IconURL, + message.ImageURL, + message.ActionType, + message.ActionParam, + message.Priority, + message.Status, + message.SentAtMS, + nullInt64(message.ExpireAtMS), + nullString(message.MetadataJSON), + message.CreatedAtMS, + message.UpdatedAtMS, + ) + if err == nil { + return true, message, nil + } + if !isMySQLDuplicate(err) { + return false, messagedomain.InboxMessage{}, err + } + + existing, exists, findErr := r.GetInboxMessageByProducerEvent(ctx, message.UserID, message.Producer, message.ProducerEventID) + if findErr != nil { + return false, messagedomain.InboxMessage{}, findErr + } + if exists { + return false, existing, nil + } + + return false, messagedomain.InboxMessage{}, xerr.New(xerr.Conflict, "inbox message id already exists") +} + +// GetInboxMessageByProducerEvent reads the idempotency target for a producer event. +func (r *Repository) GetInboxMessageByProducerEvent(ctx context.Context, userID int64, producer string, producerEventID string) (messagedomain.InboxMessage, bool, error) { + row := r.db.QueryRowContext(ctx, ` + SELECT app_code, inbox_message_id, user_id, message_type, producer, producer_event_id, + producer_event_type, aggregate_type, aggregate_id, template_id, template_version, + title, summary, body, icon_url, image_url, action_type, action_param, priority, + status, COALESCE(read_at_ms, 0), COALESCE(deleted_at_ms, 0), sent_at_ms, COALESCE(expire_at_ms, 0), + COALESCE(CAST(metadata_json AS CHAR), ''), created_at_ms, updated_at_ms + FROM user_inbox_messages + WHERE app_code = ? AND user_id = ? AND producer = ? AND producer_event_id = ?`, + appcode.FromContext(ctx), userID, producer, producerEventID, + ) + + message, err := scanInboxMessage(row) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return messagedomain.InboxMessage{}, false, nil + } + return messagedomain.InboxMessage{}, false, err + } + return message, true, nil +} + +// GetActiveMessageTemplate resolves a server-owned snapshot template. +func (r *Repository) GetActiveMessageTemplate(ctx context.Context, templateID string, templateVersion string, messageType string) (messagedomain.MessageTemplate, bool, error) { + if r == nil || r.db == nil { + return messagedomain.MessageTemplate{}, false, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + row := r.db.QueryRowContext(ctx, ` + SELECT app_code, template_id, template_version, message_type, locale, title, summary, body, + icon_url, image_url, action_type, action_param, status, created_by, created_at_ms, updated_at_ms + FROM message_templates + WHERE app_code = ? AND template_id = ? AND template_version = ? AND message_type = ? AND status = 'active'`, + appcode.FromContext(ctx), templateID, templateVersion, messageType, + ) + + var template messagedomain.MessageTemplate + if err := row.Scan(&template.AppCode, &template.TemplateID, &template.TemplateVersion, &template.MessageType, &template.Locale, &template.Title, &template.Summary, &template.Body, &template.IconURL, &template.ImageURL, &template.ActionType, &template.ActionParam, &template.Status, &template.CreatedBy, &template.CreatedAtMS, &template.UpdatedAtMS); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return messagedomain.MessageTemplate{}, false, nil + } + return messagedomain.MessageTemplate{}, false, err + } + return template, true, nil +} + +// CountUnreadInboxMessages counts visible, unexpired and undeleted unread messages by section. +func (r *Repository) CountUnreadInboxMessages(ctx context.Context, userID int64, section string, nowMS int64) (int64, error) { + if r == nil || r.db == nil { + return 0, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + row := r.db.QueryRowContext(ctx, ` + SELECT COUNT(*) + FROM user_inbox_messages + WHERE app_code = ? AND user_id = ? AND message_type = ? + AND status = 'visible' AND read_at_ms IS NULL AND deleted_at_ms IS NULL + AND (expire_at_ms IS NULL OR expire_at_ms > ?)`, + appcode.FromContext(ctx), userID, section, nowMS, + ) + var count int64 + if err := row.Scan(&count); err != nil { + return 0, err + } + return count, nil +} + +// ListInboxMessages reads one cursor page of visible messages for the current app and user. +func (r *Repository) ListInboxMessages(ctx context.Context, query messagedomain.ListQuery) ([]messagedomain.InboxMessage, error) { + if r == nil || r.db == nil { + return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + args := []any{appcode.FromContext(ctx), query.UserID, query.Section, query.NowMS} + cursorSQL := "" + if query.CursorSentAtMS > 0 || query.CursorMessageID != "" { + cursorSQL = " AND (sent_at_ms < ? OR (sent_at_ms = ? AND inbox_message_id < ?))" + args = append(args, query.CursorSentAtMS, query.CursorSentAtMS, query.CursorMessageID) + } + args = append(args, query.Limit) + + rows, err := r.db.QueryContext(ctx, ` + SELECT app_code, inbox_message_id, user_id, message_type, producer, producer_event_id, + producer_event_type, aggregate_type, aggregate_id, template_id, template_version, + title, summary, body, icon_url, image_url, action_type, action_param, priority, + status, COALESCE(read_at_ms, 0), COALESCE(deleted_at_ms, 0), sent_at_ms, COALESCE(expire_at_ms, 0), + COALESCE(CAST(metadata_json AS CHAR), ''), created_at_ms, updated_at_ms + FROM user_inbox_messages + WHERE app_code = ? AND user_id = ? AND message_type = ? + AND status = 'visible' AND deleted_at_ms IS NULL AND (expire_at_ms IS NULL OR expire_at_ms > ?)`+cursorSQL+` + ORDER BY sent_at_ms DESC, inbox_message_id DESC + LIMIT ?`, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + messages := make([]messagedomain.InboxMessage, 0, query.Limit) + for rows.Next() { + message, scanErr := scanInboxMessage(rows) + if scanErr != nil { + return nil, scanErr + } + messages = append(messages, message) + } + if err := rows.Err(); err != nil { + return nil, err + } + return messages, nil +} + +// MarkInboxMessageRead preserves the first read timestamp and treats repeated reads as success. +func (r *Repository) MarkInboxMessageRead(ctx context.Context, userID int64, messageID string, nowMS int64) (messagedomain.InboxMessage, error) { + if r == nil || r.db == nil { + return messagedomain.InboxMessage{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + message, exists, err := r.getVisibleInboxMessage(ctx, userID, messageID, nowMS) + if err != nil { + return messagedomain.InboxMessage{}, err + } + if !exists { + return messagedomain.InboxMessage{}, xerr.New(xerr.MessageNotFound, "message not found") + } + if message.ReadAtMS == 0 { + _, err = r.db.ExecContext(ctx, ` + UPDATE user_inbox_messages + SET read_at_ms = ?, updated_at_ms = ? + WHERE app_code = ? AND user_id = ? AND inbox_message_id = ? AND read_at_ms IS NULL`, + nowMS, nowMS, appcode.FromContext(ctx), userID, messageID, + ) + if err != nil { + return messagedomain.InboxMessage{}, err + } + message, _, err = r.getVisibleInboxMessage(ctx, userID, messageID, nowMS) + if err != nil { + return messagedomain.InboxMessage{}, err + } + } + return message, nil +} + +// MarkInboxSectionRead marks all current visible unread messages in a section. +func (r *Repository) MarkInboxSectionRead(ctx context.Context, userID int64, section string, nowMS int64) (int64, error) { + if r == nil || r.db == nil { + return 0, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + result, err := r.db.ExecContext(ctx, ` + UPDATE user_inbox_messages + SET read_at_ms = ?, updated_at_ms = ? + WHERE app_code = ? AND user_id = ? AND message_type = ? + AND status = 'visible' AND read_at_ms IS NULL AND deleted_at_ms IS NULL + AND (expire_at_ms IS NULL OR expire_at_ms > ?)`, + nowMS, nowMS, appcode.FromContext(ctx), userID, section, nowMS, + ) + if err != nil { + return 0, err + } + count, err := result.RowsAffected() + if err != nil { + return 0, err + } + return count, nil +} + +// DeleteInboxMessage hides one visible message for the current user without deleting audit facts. +func (r *Repository) DeleteInboxMessage(ctx context.Context, userID int64, messageID string, nowMS int64) error { + if r == nil || r.db == nil { + return xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + if _, exists, err := r.getVisibleInboxMessage(ctx, userID, messageID, nowMS); err != nil { + return err + } else if !exists { + return xerr.New(xerr.MessageNotFound, "message not found") + } + _, err := r.db.ExecContext(ctx, ` + UPDATE user_inbox_messages + SET deleted_at_ms = ?, updated_at_ms = ? + WHERE app_code = ? AND user_id = ? AND inbox_message_id = ? AND deleted_at_ms IS NULL`, + nowMS, nowMS, appcode.FromContext(ctx), userID, messageID, + ) + return err +} + +// SaveFanoutJob records an async fanout command; worker execution is intentionally outside HTTP request path. +func (r *Repository) SaveFanoutJob(ctx context.Context, job messagedomain.FanoutJob) (bool, messagedomain.FanoutJob, error) { + if r == nil || r.db == nil { + return false, messagedomain.FanoutJob{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + app := appcode.FromContext(ctx) + job.AppCode = app + _, err := r.db.ExecContext(ctx, ` + INSERT INTO message_fanout_jobs ( + app_code, job_id, command_id, message_type, target_scope, target_filter_json, template_snapshot_json, + status, attempt_count, cursor_user_id, total_count, success_count, failure_count, batch_size, next_run_at_ms, + locked_by, locked_until_ms, error_message, created_by, created_at_ms, updated_at_ms + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + app, + job.JobID, + job.CommandID, + job.MessageType, + job.TargetScope, + job.TargetFilterJSON, + job.TemplateSnapshotJSON, + job.Status, + job.AttemptCount, + job.CursorUserID, + job.TotalCount, + job.SuccessCount, + job.FailureCount, + job.BatchSize, + job.NextRunAtMS, + job.LockedBy, + job.LockedUntilMS, + job.ErrorMessage, + job.CreatedBy, + job.CreatedAtMS, + job.UpdatedAtMS, + ) + if err == nil { + return true, job, nil + } + if !isMySQLDuplicate(err) { + return false, messagedomain.FanoutJob{}, err + } + existing, exists, findErr := r.GetFanoutJobByCommand(ctx, job.CommandID) + if findErr != nil { + return false, messagedomain.FanoutJob{}, findErr + } + if exists { + return false, existing, nil + } + return false, messagedomain.FanoutJob{}, xerr.New(xerr.Conflict, "fanout job id already exists") +} + +// GetFanoutJobByCommand reads the idempotency target for admin command retries. +func (r *Repository) GetFanoutJobByCommand(ctx context.Context, commandID string) (messagedomain.FanoutJob, bool, error) { + row := r.db.QueryRowContext(ctx, ` + SELECT app_code, job_id, command_id, message_type, target_scope, CAST(target_filter_json AS CHAR), + CAST(template_snapshot_json AS CHAR), status, attempt_count, cursor_user_id, total_count, success_count, failure_count, + batch_size, next_run_at_ms, locked_by, locked_until_ms, error_message, created_by, created_at_ms, updated_at_ms + FROM message_fanout_jobs + WHERE app_code = ? AND command_id = ?`, + appcode.FromContext(ctx), commandID, + ) + var job messagedomain.FanoutJob + if err := scanFanoutJob(row, &job); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return messagedomain.FanoutJob{}, false, nil + } + return messagedomain.FanoutJob{}, false, err + } + return job, true, nil +} + +// ClaimFanoutJob commits ownership before processing so another worker can take over after lock expiry. +func (r *Repository) ClaimFanoutJob(ctx context.Context, workerID string, nowMS int64, lockUntilMS int64, maxRetry int) (messagedomain.FanoutJob, bool, error) { + if r == nil || r.db == nil { + return messagedomain.FanoutJob{}, false, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return messagedomain.FanoutJob{}, false, err + } + defer tx.Rollback() + + row := tx.QueryRowContext(ctx, ` + SELECT app_code, job_id, command_id, message_type, target_scope, CAST(target_filter_json AS CHAR), + CAST(template_snapshot_json AS CHAR), status, attempt_count, cursor_user_id, total_count, success_count, failure_count, + batch_size, next_run_at_ms, locked_by, locked_until_ms, error_message, created_by, created_at_ms, updated_at_ms + FROM message_fanout_jobs + WHERE next_run_at_ms <= ? AND attempt_count < ? + AND (status IN (?, ?) OR (status = ? AND locked_until_ms < ?)) + ORDER BY next_run_at_ms ASC, updated_at_ms ASC, job_id ASC + LIMIT 1 + FOR UPDATE SKIP LOCKED`, + nowMS, + maxRetry, + messagedomain.FanoutStatusPending, + messagedomain.FanoutStatusRetrying, + messagedomain.FanoutStatusRunning, + nowMS, + ) + var job messagedomain.FanoutJob + if err := scanFanoutJob(row, &job); err != nil { + if errors.Is(err, sql.ErrNoRows) { + if commitErr := tx.Commit(); commitErr != nil { + return messagedomain.FanoutJob{}, false, commitErr + } + return messagedomain.FanoutJob{}, false, nil + } + return messagedomain.FanoutJob{}, false, err + } + _, err = tx.ExecContext(ctx, ` + UPDATE message_fanout_jobs + SET status = ?, locked_by = ?, locked_until_ms = ?, attempt_count = attempt_count + 1, updated_at_ms = ? + WHERE app_code = ? AND job_id = ?`, + messagedomain.FanoutStatusRunning, workerID, lockUntilMS, nowMS, job.AppCode, job.JobID, + ) + if err != nil { + return messagedomain.FanoutJob{}, false, err + } + if err := tx.Commit(); err != nil { + return messagedomain.FanoutJob{}, false, err + } + job.Status = messagedomain.FanoutStatusRunning + job.LockedBy = workerID + job.LockedUntilMS = lockUntilMS + job.AttemptCount++ + job.UpdatedAtMS = nowMS + return job, true, nil +} + +// FinishFanoutJobBatch commits one processed cursor page and clears the durable worker lock. +func (r *Repository) FinishFanoutJobBatch(ctx context.Context, jobID string, workerID string, cursorUserID int64, totalDelta int64, successDelta int64, failureDelta int64, done bool, nowMS int64, errorMessage string) error { + if r == nil || r.db == nil { + return xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + status := messagedomain.FanoutStatusPending + if done { + status = messagedomain.FanoutStatusComplete + } + result, err := r.db.ExecContext(ctx, ` + UPDATE message_fanout_jobs + SET status = ?, cursor_user_id = ?, total_count = total_count + ?, success_count = success_count + ?, + failure_count = failure_count + ?, next_run_at_ms = ?, locked_by = '', locked_until_ms = 0, + error_message = ?, updated_at_ms = ? + WHERE app_code = ? AND job_id = ? AND status = ? AND locked_by = ?`, + status, + cursorUserID, + totalDelta, + successDelta, + failureDelta, + nowMS, + truncateFanoutError(errorMessage), + nowMS, + appcode.FromContext(ctx), + jobID, + messagedomain.FanoutStatusRunning, + workerID, + ) + if err != nil { + return err + } + affected, err := result.RowsAffected() + if err != nil { + return err + } + if affected == 0 { + return xerr.New(xerr.Conflict, "fanout job lock is lost") + } + return nil +} + +// FailFanoutJob releases a failed claim; exhausted jobs become failed instead of retrying forever. +func (r *Repository) FailFanoutJob(ctx context.Context, jobID string, workerID string, nowMS int64, nextRunAtMS int64, maxRetry int, errorMessage string) error { + if r == nil || r.db == nil { + return xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + result, err := r.db.ExecContext(ctx, ` + UPDATE message_fanout_jobs + SET status = CASE WHEN attempt_count >= ? THEN ? ELSE ? END, + next_run_at_ms = CASE WHEN attempt_count >= ? THEN 0 ELSE ? END, + locked_by = '', locked_until_ms = 0, error_message = ?, updated_at_ms = ? + WHERE app_code = ? AND job_id = ? AND status = ? AND locked_by = ?`, + maxRetry, + messagedomain.FanoutStatusFailed, + messagedomain.FanoutStatusRetrying, + maxRetry, + nextRunAtMS, + truncateFanoutError(errorMessage), + nowMS, + appcode.FromContext(ctx), + jobID, + messagedomain.FanoutStatusRunning, + workerID, + ) + if err != nil { + return err + } + affected, err := result.RowsAffected() + if err != nil { + return err + } + if affected == 0 { + return xerr.New(xerr.Conflict, "fanout job lock is lost") + } + return nil +} + +func (r *Repository) getVisibleInboxMessage(ctx context.Context, userID int64, messageID string, nowMS int64) (messagedomain.InboxMessage, bool, error) { + row := r.db.QueryRowContext(ctx, ` + SELECT app_code, inbox_message_id, user_id, message_type, producer, producer_event_id, + producer_event_type, aggregate_type, aggregate_id, template_id, template_version, + title, summary, body, icon_url, image_url, action_type, action_param, priority, + status, COALESCE(read_at_ms, 0), COALESCE(deleted_at_ms, 0), sent_at_ms, COALESCE(expire_at_ms, 0), + COALESCE(CAST(metadata_json AS CHAR), ''), created_at_ms, updated_at_ms + FROM user_inbox_messages + WHERE app_code = ? AND user_id = ? AND inbox_message_id = ? + AND status = 'visible' AND deleted_at_ms IS NULL AND (expire_at_ms IS NULL OR expire_at_ms > ?)`, + appcode.FromContext(ctx), userID, messageID, nowMS, + ) + message, err := scanInboxMessage(row) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return messagedomain.InboxMessage{}, false, nil + } + return messagedomain.InboxMessage{}, false, err + } + return message, true, nil +} + +type inboxScanner interface { + Scan(dest ...any) error +} + +func scanFanoutJob(scanner inboxScanner, job *messagedomain.FanoutJob) error { + return scanner.Scan( + &job.AppCode, + &job.JobID, + &job.CommandID, + &job.MessageType, + &job.TargetScope, + &job.TargetFilterJSON, + &job.TemplateSnapshotJSON, + &job.Status, + &job.AttemptCount, + &job.CursorUserID, + &job.TotalCount, + &job.SuccessCount, + &job.FailureCount, + &job.BatchSize, + &job.NextRunAtMS, + &job.LockedBy, + &job.LockedUntilMS, + &job.ErrorMessage, + &job.CreatedBy, + &job.CreatedAtMS, + &job.UpdatedAtMS, + ) +} + +func scanInboxMessage(scanner inboxScanner) (messagedomain.InboxMessage, error) { + var message messagedomain.InboxMessage + err := scanner.Scan( + &message.AppCode, + &message.MessageID, + &message.UserID, + &message.MessageType, + &message.Producer, + &message.ProducerEventID, + &message.ProducerEventType, + &message.AggregateType, + &message.AggregateID, + &message.TemplateID, + &message.TemplateVersion, + &message.Title, + &message.Summary, + &message.Body, + &message.IconURL, + &message.ImageURL, + &message.ActionType, + &message.ActionParam, + &message.Priority, + &message.Status, + &message.ReadAtMS, + &message.DeletedAtMS, + &message.SentAtMS, + &message.ExpireAtMS, + &message.MetadataJSON, + &message.CreatedAtMS, + &message.UpdatedAtMS, + ) + return message, err +} + +func nullInt64(value int64) sql.NullInt64 { + return sql.NullInt64{Int64: value, Valid: value > 0} +} + +func nullString(value string) sql.NullString { + return sql.NullString{String: value, Valid: value != ""} +} + +func truncateFanoutError(message string) string { + if len(message) <= 512 { + return message + } + return message[:512] +} + +func isMySQLDuplicate(err error) bool { + var mysqlErr *mysqlerr.MySQLError + return errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 +} diff --git a/services/activity-service/internal/transport/grpc/message_server.go b/services/activity-service/internal/transport/grpc/message_server.go new file mode 100644 index 00000000..21a35bb3 --- /dev/null +++ b/services/activity-service/internal/transport/grpc/message_server.go @@ -0,0 +1,143 @@ +package grpc + +import ( + "context" + + activityv1 "hyapp.local/api/proto/activity/v1" + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + messagedomain "hyapp/services/activity-service/internal/domain/message" + messageservice "hyapp/services/activity-service/internal/service/message" +) + +// MessageServer adapts the message inbox owner to gRPC without mixing it into activity status APIs. +type MessageServer struct { + activityv1.UnimplementedMessageInboxServiceServer + + svc *messageservice.Service +} + +// NewMessageServer creates the gRPC adapter for system/activity inbox RPCs. +func NewMessageServer(svc *messageservice.Service) *MessageServer { + return &MessageServer{svc: svc} +} + +func (s *MessageServer) ListMessageTabs(ctx context.Context, req *activityv1.ListMessageTabsRequest) (*activityv1.ListMessageTabsResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + sections, err := s.svc.ListMessageTabs(ctx, req.GetUserId()) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + result := make([]*activityv1.MessageTabSection, 0, len(sections)) + for _, section := range sections { + result = append(result, &activityv1.MessageTabSection{ + Section: section.Section, + Title: section.Title, + UnreadCount: section.UnreadCount, + Source: section.Source, + }) + } + return &activityv1.ListMessageTabsResponse{Sections: result}, nil +} + +func (s *MessageServer) ListInboxMessages(ctx context.Context, req *activityv1.ListInboxMessagesRequest) (*activityv1.ListInboxMessagesResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + messages, nextPageToken, err := s.svc.ListInboxMessages(ctx, req.GetUserId(), req.GetSection(), req.GetPageSize(), req.GetPageToken()) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + items := make([]*activityv1.InboxMessage, 0, len(messages)) + for _, message := range messages { + items = append(items, inboxMessageProto(message)) + } + return &activityv1.ListInboxMessagesResponse{Section: req.GetSection(), Items: items, NextPageToken: nextPageToken}, nil +} + +func (s *MessageServer) MarkInboxMessageRead(ctx context.Context, req *activityv1.MarkInboxMessageReadRequest) (*activityv1.MarkInboxMessageReadResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + message, err := s.svc.MarkInboxMessageRead(ctx, req.GetUserId(), req.GetMessageId()) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.MarkInboxMessageReadResponse{MessageId: message.MessageID, Read: true, ReadAtMs: message.ReadAtMS}, nil +} + +func (s *MessageServer) MarkInboxSectionRead(ctx context.Context, req *activityv1.MarkInboxSectionReadRequest) (*activityv1.MarkInboxSectionReadResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + count, err := s.svc.MarkInboxSectionRead(ctx, req.GetUserId(), req.GetSection()) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.MarkInboxSectionReadResponse{Section: req.GetSection(), ReadCount: count}, nil +} + +func (s *MessageServer) DeleteInboxMessage(ctx context.Context, req *activityv1.DeleteInboxMessageRequest) (*activityv1.DeleteInboxMessageResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + if err := s.svc.DeleteInboxMessage(ctx, req.GetUserId(), req.GetMessageId()); err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.DeleteInboxMessageResponse{MessageId: req.GetMessageId(), Deleted: true}, nil +} + +func (s *MessageServer) CreateInboxMessage(ctx context.Context, req *activityv1.CreateInboxMessageRequest) (*activityv1.CreateInboxMessageResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + message, created, err := s.svc.CreateInboxMessage(ctx, messagedomain.CreateInput{ + TargetUserID: req.GetTargetUserId(), + Producer: req.GetProducer(), + ProducerEventID: req.GetProducerEventId(), + ProducerEventType: req.GetProducerEventType(), + MessageType: req.GetMessageType(), + AggregateType: req.GetAggregateType(), + AggregateID: req.GetAggregateId(), + TemplateID: req.GetTemplateId(), + TemplateVersion: req.GetTemplateVersion(), + Title: req.GetTitle(), + Summary: req.GetSummary(), + Body: req.GetBody(), + IconURL: req.GetIconUrl(), + ImageURL: req.GetImageUrl(), + ActionType: req.GetActionType(), + ActionParam: req.GetActionParam(), + Priority: req.GetPriority(), + SentAtMS: req.GetSentAtMs(), + ExpireAtMS: req.GetExpireAtMs(), + MetadataJSON: req.GetMetadataJson(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.CreateInboxMessageResponse{MessageId: message.MessageID, Created: created}, nil +} + +func (s *MessageServer) CreateFanoutJob(ctx context.Context, req *activityv1.CreateFanoutJobRequest) (*activityv1.CreateFanoutJobResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + job, created, err := s.svc.CreateFanoutJob(ctx, messagedomain.CreateFanoutInput{ + CommandID: req.GetCommandId(), + MessageType: req.GetMessageType(), + TargetScope: req.GetTargetScope(), + TargetFilterJSON: req.GetTargetFilterJson(), + TemplateSnapshotJSON: req.GetTemplateSnapshotJson(), + BatchSize: req.GetBatchSize(), + CreatedBy: req.GetCreatedBy(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &activityv1.CreateFanoutJobResponse{JobId: job.JobID, Status: job.Status, Created: created}, nil +} + +func inboxMessageProto(message messagedomain.InboxMessage) *activityv1.InboxMessage { + return &activityv1.InboxMessage{ + MessageId: message.MessageID, + Section: message.MessageType, + Title: message.Title, + Summary: message.Summary, + Body: message.Body, + IconUrl: message.IconURL, + ImageUrl: message.ImageURL, + ActionType: message.ActionType, + ActionParam: message.ActionParam, + Read: message.Read(), + SentAtMs: message.SentAtMS, + } +} diff --git a/services/gateway-service/configs/config.docker.yaml b/services/gateway-service/configs/config.docker.yaml index 5dd58276..df14f3dd 100644 --- a/services/gateway-service/configs/config.docker.yaml +++ b/services/gateway-service/configs/config.docker.yaml @@ -3,6 +3,7 @@ jwt_secret: "dev-shared-secret" room_service_addr: "room-service:13001" user_service_addr: "user-service:13005" wallet_service_addr: "wallet-service:13004" +activity_service_addr: "activity-service:13006" app_config: # H5 地址由后台 APP配置/H5配置 写入 hyapp_admin.admin_app_configs,gateway 只读下发给 App。 mysql_dsn: "hyapp:hyapp@tcp(mysql:3306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=Local" diff --git a/services/gateway-service/configs/config.tencent.example.yaml b/services/gateway-service/configs/config.tencent.example.yaml index 7814511e..4c55d97c 100644 --- a/services/gateway-service/configs/config.tencent.example.yaml +++ b/services/gateway-service/configs/config.tencent.example.yaml @@ -3,6 +3,7 @@ jwt_secret: "REPLACE_WITH_GATEWAY_JWT_SECRET" room_service_addr: "room-service.internal:13001" user_service_addr: "user-service.internal:13005" wallet_service_addr: "wallet-service.internal:13004" +activity_service_addr: "activity-service.internal:13006" app_config: # H5 地址由后台 APP配置/H5配置 写入 hyapp_admin.admin_app_configs,gateway 只读下发给 App。 mysql_dsn: "TENCENT_MYSQL_USER:TENCENT_MYSQL_PASSWORD@tcp(TENCENT_MYSQL_HOST:3306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=Local" diff --git a/services/gateway-service/configs/config.yaml b/services/gateway-service/configs/config.yaml index 70cb7877..0fdc6f4e 100644 --- a/services/gateway-service/configs/config.yaml +++ b/services/gateway-service/configs/config.yaml @@ -3,6 +3,7 @@ jwt_secret: "dev-shared-secret" room_service_addr: "127.0.0.1:13001" user_service_addr: "127.0.0.1:13005" wallet_service_addr: "127.0.0.1:13004" +activity_service_addr: "127.0.0.1:13006" app_config: # H5 地址由后台 APP配置/H5配置 写入 hyapp_admin.admin_app_configs,gateway 只读下发给 App。 mysql_dsn: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=Local" diff --git a/services/gateway-service/internal/app/app.go b/services/gateway-service/internal/app/app.go index a7dfef05..65ae34b3 100644 --- a/services/gateway-service/internal/app/app.go +++ b/services/gateway-service/internal/app/app.go @@ -24,15 +24,16 @@ import ( // App 装配 gateway 的 HTTP 入口。 type App struct { - server *http.Server - listener net.Listener - roomConn *grpc.ClientConn - userConn *grpc.ClientConn - walletConn *grpc.ClientConn - appConfig *appconfig.MySQLReader - redisClose func() error - health *healthcheck.State - closeOnce sync.Once + server *http.Server + listener net.Listener + roomConn *grpc.ClientConn + userConn *grpc.ClientConn + walletConn *grpc.ClientConn + activityConn *grpc.ClientConn + appConfig *appconfig.MySQLReader + redisClose func() error + health *healthcheck.State + closeOnce sync.Once } // New 初始化 gateway 应用。 @@ -58,6 +59,13 @@ func New(cfg config.Config) (*App, error) { _ = userConn.Close() return nil, err } + activityConn, err := grpc.Dial(cfg.ActivityServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + _ = roomConn.Close() + _ = userConn.Close() + _ = walletConn.Close() + return nil, err + } var roomClient client.RoomClient = client.NewGRPCRoomClient(roomConn) var roomGuardClient client.RoomGuardClient = client.NewGRPCRoomGuardClient(roomConn) @@ -65,15 +73,18 @@ func New(cfg config.Config) (*App, error) { var userClient client.UserAuthClient = client.NewGRPCUserAuthClient(userConn) var userIdentityClient client.UserIdentityClient = client.NewGRPCUserIdentityClient(userConn) var userProfileClient client.UserProfileClient = client.NewGRPCUserProfileClient(userConn) + var userDeviceClient client.UserDeviceClient = client.NewGRPCUserDeviceClient(userConn) var userCountryQueryClient client.UserCountryQueryClient = client.NewGRPCUserCountryQueryClient(userConn) var userHostClient client.UserHostClient = client.NewGRPCUserHostClient(userConn) var appRegistryClient client.AppRegistryClient = client.NewGRPCAppRegistryClient(userConn) var walletClient client.WalletClient = client.NewGRPCWalletClient(walletConn) + var messageClient client.MessageInboxClient = client.NewGRPCMessageInboxClient(activityConn) appConfigReader, err := openAppConfigReader(cfg.AppConfig) if err != nil { _ = roomConn.Close() _ = userConn.Close() _ = walletConn.Close() + _ = activityConn.Close() return nil, err } handler := httptransport.NewHandlerWithConfig(roomClient, roomGuardClient, userClient, userIdentityClient, httptransport.TencentIMConfig{ @@ -83,10 +94,12 @@ func New(cfg config.Config) (*App, error) { CallbackAuthToken: cfg.TencentIM.CallbackAuthToken, }, userProfileClient) handler.SetRoomQueryClient(roomQueryClient) + handler.SetUserDeviceClient(userDeviceClient) handler.SetUserCountryQueryClient(userCountryQueryClient) handler.SetUserHostClient(userHostClient) handler.SetAppRegistryClient(appRegistryClient) handler.SetWalletClient(walletClient) + handler.SetMessageInboxClient(messageClient) if appConfigReader != nil { handler.SetAppConfigReader(appConfigReader) } @@ -114,6 +127,7 @@ func New(cfg config.Config) (*App, error) { _ = roomConn.Close() _ = userConn.Close() _ = walletConn.Close() + _ = activityConn.Close() return nil, err } handler.SetObjectUploader(uploader) @@ -137,6 +151,7 @@ func New(cfg config.Config) (*App, error) { _ = roomConn.Close() _ = userConn.Close() _ = walletConn.Close() + _ = activityConn.Close() return nil, err } verifier := auth.NewVerifier(cfg.JWTSecret) @@ -159,6 +174,7 @@ func New(cfg config.Config) (*App, error) { _ = roomConn.Close() _ = userConn.Close() _ = walletConn.Close() + _ = activityConn.Close() return nil, err } @@ -167,14 +183,15 @@ func New(cfg config.Config) (*App, error) { } return &App{ - server: server, - listener: listener, - roomConn: roomConn, - userConn: userConn, - walletConn: walletConn, - appConfig: appConfigReader, - redisClose: redisClose, - health: healthState, + server: server, + listener: listener, + roomConn: roomConn, + userConn: userConn, + walletConn: walletConn, + activityConn: activityConn, + appConfig: appConfigReader, + redisClose: redisClose, + health: healthState, }, nil } @@ -236,6 +253,9 @@ func (a *App) Close() error { if a.walletConn != nil { err = errors.Join(err, a.walletConn.Close()) } + if a.activityConn != nil { + err = errors.Join(err, a.activityConn.Close()) + } if a.appConfig != nil { err = errors.Join(err, a.appConfig.Close()) } diff --git a/services/gateway-service/internal/client/message_client.go b/services/gateway-service/internal/client/message_client.go new file mode 100644 index 00000000..80729527 --- /dev/null +++ b/services/gateway-service/internal/client/message_client.go @@ -0,0 +1,46 @@ +package client + +import ( + "context" + + "google.golang.org/grpc" + activityv1 "hyapp.local/api/proto/activity/v1" +) + +// MessageInboxClient abstracts gateway access to the backend-owned system/activity inbox. +type MessageInboxClient interface { + ListMessageTabs(ctx context.Context, req *activityv1.ListMessageTabsRequest) (*activityv1.ListMessageTabsResponse, error) + ListInboxMessages(ctx context.Context, req *activityv1.ListInboxMessagesRequest) (*activityv1.ListInboxMessagesResponse, error) + MarkInboxMessageRead(ctx context.Context, req *activityv1.MarkInboxMessageReadRequest) (*activityv1.MarkInboxMessageReadResponse, error) + MarkInboxSectionRead(ctx context.Context, req *activityv1.MarkInboxSectionReadRequest) (*activityv1.MarkInboxSectionReadResponse, error) + DeleteInboxMessage(ctx context.Context, req *activityv1.DeleteInboxMessageRequest) (*activityv1.DeleteInboxMessageResponse, error) +} + +type grpcMessageInboxClient struct { + client activityv1.MessageInboxServiceClient +} + +// NewGRPCMessageInboxClient builds an inbox client backed by activity-service MessageInboxService. +func NewGRPCMessageInboxClient(conn *grpc.ClientConn) MessageInboxClient { + return &grpcMessageInboxClient{client: activityv1.NewMessageInboxServiceClient(conn)} +} + +func (c *grpcMessageInboxClient) ListMessageTabs(ctx context.Context, req *activityv1.ListMessageTabsRequest) (*activityv1.ListMessageTabsResponse, error) { + return c.client.ListMessageTabs(ctx, req) +} + +func (c *grpcMessageInboxClient) ListInboxMessages(ctx context.Context, req *activityv1.ListInboxMessagesRequest) (*activityv1.ListInboxMessagesResponse, error) { + return c.client.ListInboxMessages(ctx, req) +} + +func (c *grpcMessageInboxClient) MarkInboxMessageRead(ctx context.Context, req *activityv1.MarkInboxMessageReadRequest) (*activityv1.MarkInboxMessageReadResponse, error) { + return c.client.MarkInboxMessageRead(ctx, req) +} + +func (c *grpcMessageInboxClient) MarkInboxSectionRead(ctx context.Context, req *activityv1.MarkInboxSectionReadRequest) (*activityv1.MarkInboxSectionReadResponse, error) { + return c.client.MarkInboxSectionRead(ctx, req) +} + +func (c *grpcMessageInboxClient) DeleteInboxMessage(ctx context.Context, req *activityv1.DeleteInboxMessageRequest) (*activityv1.DeleteInboxMessageResponse, error) { + return c.client.DeleteInboxMessage(ctx, req) +} diff --git a/services/gateway-service/internal/client/room_client.go b/services/gateway-service/internal/client/room_client.go index 706d582d..976b539b 100644 --- a/services/gateway-service/internal/client/room_client.go +++ b/services/gateway-service/internal/client/room_client.go @@ -38,6 +38,8 @@ type RoomGuardClient interface { // RoomQueryClient 抽象 gateway 对 room-service 读模型查询的依赖。 type RoomQueryClient interface { ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (*roomv1.ListRoomsResponse, error) + GetCurrentRoom(ctx context.Context, req *roomv1.GetCurrentRoomRequest) (*roomv1.GetCurrentRoomResponse, error) + GetRoomSnapshot(ctx context.Context, req *roomv1.GetRoomSnapshotRequest) (*roomv1.GetRoomSnapshotResponse, error) } type grpcRoomClient struct { @@ -152,3 +154,11 @@ func (c *grpcRoomGuardClient) VerifyRoomPresence(ctx context.Context, req *roomv func (c *grpcRoomQueryClient) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (*roomv1.ListRoomsResponse, error) { return c.client.ListRooms(ctx, req) } + +func (c *grpcRoomQueryClient) GetCurrentRoom(ctx context.Context, req *roomv1.GetCurrentRoomRequest) (*roomv1.GetCurrentRoomResponse, error) { + return c.client.GetCurrentRoom(ctx, req) +} + +func (c *grpcRoomQueryClient) GetRoomSnapshot(ctx context.Context, req *roomv1.GetRoomSnapshotRequest) (*roomv1.GetRoomSnapshotResponse, error) { + return c.client.GetRoomSnapshot(ctx, req) +} diff --git a/services/gateway-service/internal/client/user_client.go b/services/gateway-service/internal/client/user_client.go index 3f72b390..4c157bbb 100644 --- a/services/gateway-service/internal/client/user_client.go +++ b/services/gateway-service/internal/client/user_client.go @@ -28,11 +28,18 @@ type UserIdentityClient interface { // UserProfileClient 抽象 gateway 对 user-service 用户资料能力的依赖。 type UserProfileClient interface { GetUser(ctx context.Context, req *userv1.GetUserRequest) (*userv1.GetUserResponse, error) + BatchGetUsers(ctx context.Context, req *userv1.BatchGetUsersRequest) (*userv1.BatchGetUsersResponse, error) CompleteOnboarding(ctx context.Context, req *userv1.CompleteOnboardingRequest) (*userv1.CompleteOnboardingResponse, error) UpdateUserProfile(ctx context.Context, req *userv1.UpdateUserProfileRequest) (*userv1.UpdateUserProfileResponse, error) ChangeUserCountry(ctx context.Context, req *userv1.ChangeUserCountryRequest) (*userv1.ChangeUserCountryResponse, error) } +// UserDeviceClient 抽象 gateway 对 user-service 设备 push token 的依赖。 +type UserDeviceClient interface { + BindPushToken(ctx context.Context, req *userv1.BindPushTokenRequest) (*userv1.BindPushTokenResponse, error) + DeletePushToken(ctx context.Context, req *userv1.DeletePushTokenRequest) (*userv1.DeletePushTokenResponse, error) +} + // UserCountryQueryClient 抽象 gateway 对 App 注册页国家列表的公开读依赖。 type UserCountryQueryClient interface { ListRegistrationCountries(ctx context.Context, req *userv1.ListRegistrationCountriesRequest) (*userv1.ListRegistrationCountriesResponse, error) @@ -62,6 +69,10 @@ type grpcUserProfileClient struct { client userv1.UserServiceClient } +type grpcUserDeviceClient struct { + client userv1.UserDeviceServiceClient +} + type grpcUserCountryQueryClient struct { client userv1.CountryQueryServiceClient } @@ -95,6 +106,13 @@ func NewGRPCUserProfileClient(conn *grpc.ClientConn) UserProfileClient { } } +// NewGRPCUserDeviceClient 用 gRPC 连接构造 user-service 设备推送 client。 +func NewGRPCUserDeviceClient(conn *grpc.ClientConn) UserDeviceClient { + return &grpcUserDeviceClient{ + client: userv1.NewUserDeviceServiceClient(conn), + } +} + // NewGRPCUserCountryQueryClient 用 gRPC 连接构造国家公开查询 client。 func NewGRPCUserCountryQueryClient(conn *grpc.ClientConn) UserCountryQueryClient { return &grpcUserCountryQueryClient{ @@ -156,6 +174,10 @@ func (c *grpcUserProfileClient) GetUser(ctx context.Context, req *userv1.GetUser return c.client.GetUser(ctx, req) } +func (c *grpcUserProfileClient) BatchGetUsers(ctx context.Context, req *userv1.BatchGetUsersRequest) (*userv1.BatchGetUsersResponse, error) { + return c.client.BatchGetUsers(ctx, req) +} + func (c *grpcUserProfileClient) CompleteOnboarding(ctx context.Context, req *userv1.CompleteOnboardingRequest) (*userv1.CompleteOnboardingResponse, error) { return c.client.CompleteOnboarding(ctx, req) } @@ -168,6 +190,14 @@ func (c *grpcUserProfileClient) ChangeUserCountry(ctx context.Context, req *user return c.client.ChangeUserCountry(ctx, req) } +func (c *grpcUserDeviceClient) BindPushToken(ctx context.Context, req *userv1.BindPushTokenRequest) (*userv1.BindPushTokenResponse, error) { + return c.client.BindPushToken(ctx, req) +} + +func (c *grpcUserDeviceClient) DeletePushToken(ctx context.Context, req *userv1.DeletePushTokenRequest) (*userv1.DeletePushTokenResponse, error) { + return c.client.DeletePushToken(ctx, req) +} + func (c *grpcUserCountryQueryClient) ListRegistrationCountries(ctx context.Context, req *userv1.ListRegistrationCountriesRequest) (*userv1.ListRegistrationCountriesResponse, error) { return c.client.ListRegistrationCountries(ctx, req) } diff --git a/services/gateway-service/internal/config/config.go b/services/gateway-service/internal/config/config.go index 45be78f1..c4fa16c6 100644 --- a/services/gateway-service/internal/config/config.go +++ b/services/gateway-service/internal/config/config.go @@ -11,16 +11,17 @@ import ( // Config 描述 gateway-service 启动所需的最小配置。 type Config struct { - HTTPAddr string `yaml:"http_addr"` - JWTSecret string `yaml:"jwt_secret"` - RoomServiceAddr string `yaml:"room_service_addr"` - UserServiceAddr string `yaml:"user_service_addr"` - WalletServiceAddr string `yaml:"wallet_service_addr"` - AuthRateLimit AuthRateLimitConfig `yaml:"auth_rate_limit"` - AppConfig AppConfigConfig `yaml:"app_config"` - TencentIM TencentIMConfig `yaml:"tencent_im"` - TencentRTC TencentRTCConfig `yaml:"tencent_rtc"` - TencentCOS TencentCOSConfig `yaml:"tencent-cos"` + HTTPAddr string `yaml:"http_addr"` + JWTSecret string `yaml:"jwt_secret"` + RoomServiceAddr string `yaml:"room_service_addr"` + UserServiceAddr string `yaml:"user_service_addr"` + WalletServiceAddr string `yaml:"wallet_service_addr"` + ActivityServiceAddr string `yaml:"activity_service_addr"` + AuthRateLimit AuthRateLimitConfig `yaml:"auth_rate_limit"` + AppConfig AppConfigConfig `yaml:"app_config"` + TencentIM TencentIMConfig `yaml:"tencent_im"` + TencentRTC TencentRTCConfig `yaml:"tencent_rtc"` + TencentCOS TencentCOSConfig `yaml:"tencent-cos"` } // AppConfigConfig 描述 gateway 读取后台 App 运行时配置的只读数据源。 @@ -109,11 +110,12 @@ type TencentCOSConfig struct { // Default 返回本地开发默认配置。 func Default() Config { return Config{ - HTTPAddr: ":13000", - JWTSecret: "gateway-dev-secret", - RoomServiceAddr: "127.0.0.1:13001", - UserServiceAddr: "127.0.0.1:13005", - WalletServiceAddr: "127.0.0.1:13004", + HTTPAddr: ":13000", + JWTSecret: "gateway-dev-secret", + RoomServiceAddr: "127.0.0.1:13001", + UserServiceAddr: "127.0.0.1:13005", + WalletServiceAddr: "127.0.0.1:13004", + ActivityServiceAddr: "127.0.0.1:13006", AppConfig: AppConfigConfig{ MySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=Local", }, @@ -167,9 +169,13 @@ func (cfg *Config) Normalize() error { cfg.RoomServiceAddr = strings.TrimSpace(cfg.RoomServiceAddr) cfg.UserServiceAddr = strings.TrimSpace(cfg.UserServiceAddr) cfg.WalletServiceAddr = strings.TrimSpace(cfg.WalletServiceAddr) + cfg.ActivityServiceAddr = strings.TrimSpace(cfg.ActivityServiceAddr) if cfg.WalletServiceAddr == "" { cfg.WalletServiceAddr = "127.0.0.1:13004" } + if cfg.ActivityServiceAddr == "" { + cfg.ActivityServiceAddr = "127.0.0.1:13006" + } cfg.AppConfig.MySQLDSN = strings.TrimSpace(cfg.AppConfig.MySQLDSN) cfg.TencentCOS.SecretID = strings.TrimSpace(cfg.TencentCOS.SecretID) cfg.TencentCOS.SecretKey = strings.TrimSpace(cfg.TencentCOS.SecretKey) 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 72f1641c..4af3ed12 100644 --- a/services/gateway-service/internal/transport/http/app_config_handler.go +++ b/services/gateway-service/internal/transport/http/app_config_handler.go @@ -5,6 +5,7 @@ import ( "net/http" "strconv" "strings" + "time" "hyapp/pkg/appcode" "hyapp/services/gateway-service/internal/appconfig" @@ -16,6 +17,57 @@ type appConfigReader interface { ListBanners(ctx context.Context, query appconfig.BannerQuery) ([]appconfig.Banner, error) } +type appBootstrapBottomTab struct { + Key string `json:"key"` + Title string `json:"title"` + Enabled bool `json:"enabled"` +} + +type appBootstrapResponse struct { + AppCode string `json:"app_code"` + ServerTimeMS int64 `json:"server_time_ms"` + ForceUpgrade bool `json:"force_upgrade"` + Maintenance bool `json:"maintenance"` + MinimumVersion string `json:"minimum_version"` + LatestVersion string `json:"latest_version"` + FeatureFlags map[string]bool `json:"feature_flags"` + BottomTabs []appBootstrapBottomTab `json:"bottom_tabs"` + ConfigVersions map[string]string `json:"config_versions"` +} + +// getAppBootstrap 返回 App 启动状态机需要的轻量配置摘要。 +// bootstrap 只下发版本、开关和配置版本号,不返回 banner、礼物或资源大列表。 +func (h *Handler) getAppBootstrap(writer http.ResponseWriter, request *http.Request) { + writeOK(writer, request, appBootstrapResponse{ + AppCode: appcode.FromContext(request.Context()), + ServerTimeMS: time.Now().UnixMilli(), + ForceUpgrade: false, + Maintenance: false, + MinimumVersion: "1.0.0", + LatestVersion: "1.0.0", + FeatureFlags: map[string]bool{ + "wallet_recharge": true, + "wallet_withdraw": true, + "diamond_exchange": true, + "message_tab": true, + "host_center": true, + "room_create": true, + }, + BottomTabs: []appBootstrapBottomTab{ + {Key: "rooms", Title: "房间", Enabled: true}, + {Key: "messages", Title: "消息", Enabled: true}, + {Key: "me", Title: "我的", Enabled: true}, + }, + ConfigVersions: map[string]string{ + "countries": "v1", + "banners": "v1", + "h5_links": "v1", + "resources": "v1", + "gifts": "v1", + }, + }) +} + // listH5Links 返回后台 APP配置/H5配置 中维护的 H5 入口地址。 func (h *Handler) listH5Links(writer http.ResponseWriter, request *http.Request) { if h.appConfigReader == nil { diff --git a/services/gateway-service/internal/transport/http/device_handler.go b/services/gateway-service/internal/transport/http/device_handler.go new file mode 100644 index 00000000..731f1b89 --- /dev/null +++ b/services/gateway-service/internal/transport/http/device_handler.go @@ -0,0 +1,130 @@ +package http + +import ( + "net/http" + "strings" + + userv1 "hyapp.local/api/proto/user/v1" + "hyapp/services/gateway-service/internal/auth" +) + +// handlePushToken 分发 push token 绑定和失效。 +// 设备 token 属于 user-service 主数据扩展,gateway 只做鉴权、字段透传和 HTTP method 约束。 +func (h *Handler) handlePushToken(writer http.ResponseWriter, request *http.Request) { + switch request.Method { + case http.MethodPost: + h.bindPushToken(writer, request) + case http.MethodDelete: + h.deletePushToken(writer, request) + default: + writeError(writer, request, http.StatusMethodNotAllowed, codeInvalidArgument, "invalid argument") + } +} + +func (h *Handler) bindPushToken(writer http.ResponseWriter, request *http.Request) { + if h.userDeviceClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + + var body struct { + DeviceID string `json:"device_id"` + PushToken string `json:"push_token"` + Provider string `json:"provider"` + Platform string `json:"platform"` + AppVersion string `json:"app_version"` + Language string `json:"language"` + Timezone string `json:"timezone"` + } + if !decode(writer, request, &body) { + return + } + body.DeviceID = pushDeviceID(request, body.DeviceID) + body.Platform = pushPlatform(request, body.Platform) + + resp, err := h.userDeviceClient.BindPushToken(request.Context(), &userv1.BindPushTokenRequest{ + Meta: authRequestMeta(request, body.DeviceID), + UserId: auth.UserIDFromContext(request.Context()), + DeviceId: body.DeviceID, + PushToken: strings.TrimSpace(body.PushToken), + Provider: body.Provider, + Platform: body.Platform, + AppVersion: body.AppVersion, + Language: body.Language, + Timezone: body.Timezone, + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + writeOK(writer, request, bindPushTokenDataFromProto(resp)) +} + +func (h *Handler) deletePushToken(writer http.ResponseWriter, request *http.Request) { + if h.userDeviceClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + + var body struct { + DeviceID string `json:"device_id"` + PushToken string `json:"push_token"` + } + if !decode(writer, request, &body) { + return + } + body.DeviceID = pushDeviceID(request, body.DeviceID) + + resp, err := h.userDeviceClient.DeletePushToken(request.Context(), &userv1.DeletePushTokenRequest{ + Meta: authRequestMeta(request, body.DeviceID), + UserId: auth.UserIDFromContext(request.Context()), + DeviceId: body.DeviceID, + PushToken: strings.TrimSpace(body.PushToken), + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + writeOK(writer, request, deletePushTokenDataFromProto(resp)) +} + +// bindPushTokenData/deletePushTokenData 固定外部 JSON 字段,避免 proto3 false 被省略。 +type bindPushTokenData struct { + Bound bool `json:"bound"` + UpdatedAtMS int64 `json:"updated_at_ms"` +} + +type deletePushTokenData struct { + Deleted bool `json:"deleted"` + UpdatedAtMS int64 `json:"updated_at_ms"` +} + +func bindPushTokenDataFromProto(resp *userv1.BindPushTokenResponse) bindPushTokenData { + if resp == nil { + return bindPushTokenData{} + } + + return bindPushTokenData{Bound: resp.GetBound(), UpdatedAtMS: resp.GetUpdatedAtMs()} +} + +func deletePushTokenDataFromProto(resp *userv1.DeletePushTokenResponse) deletePushTokenData { + if resp == nil { + return deletePushTokenData{} + } + + return deletePushTokenData{Deleted: resp.GetDeleted(), UpdatedAtMS: resp.GetUpdatedAtMs()} +} + +func pushDeviceID(request *http.Request, bodyValue string) string { + if value := strings.TrimSpace(bodyValue); value != "" { + return value + } + return firstHeader(request, "X-Device-ID", "X-HY-Device-ID") +} + +func pushPlatform(request *http.Request, bodyValue string) string { + if value := strings.TrimSpace(bodyValue); value != "" { + return value + } + return firstHeader(request, "X-App-Platform", "X-Platform") +} diff --git a/services/gateway-service/internal/transport/http/handler.go b/services/gateway-service/internal/transport/http/handler.go index d13907e3..2c97e2fb 100644 --- a/services/gateway-service/internal/transport/http/handler.go +++ b/services/gateway-service/internal/transport/http/handler.go @@ -24,10 +24,12 @@ type Handler struct { userClient client.UserAuthClient userIdentityClient client.UserIdentityClient userProfileClient client.UserProfileClient + userDeviceClient client.UserDeviceClient userCountryClient client.UserCountryQueryClient userHostClient client.UserHostClient appRegistryClient client.AppRegistryClient walletClient client.WalletClient + messageClient client.MessageInboxClient appConfigReader appConfigReader tencentIM TencentIMConfig tencentRTC TencentRTCConfig @@ -123,6 +125,11 @@ func (h *Handler) SetUserCountryQueryClient(userCountryClient client.UserCountry h.userCountryClient = userCountryClient } +// SetUserDeviceClient 注入 user-service 设备推送 token client。 +func (h *Handler) SetUserDeviceClient(userDeviceClient client.UserDeviceClient) { + h.userDeviceClient = userDeviceClient +} + // SetUserHostClient 注入 user-service host domain 身份查询 client。 func (h *Handler) SetUserHostClient(userHostClient client.UserHostClient) { h.userHostClient = userHostClient @@ -138,6 +145,11 @@ func (h *Handler) SetWalletClient(walletClient client.WalletClient) { h.walletClient = walletClient } +// SetMessageInboxClient 注入 activity-service message inbox client。 +func (h *Handler) SetMessageInboxClient(messageClient client.MessageInboxClient) { + h.messageClient = messageClient +} + // SetAppConfigReader 注入后台 App 配置读取依赖。 func (h *Handler) SetAppConfigReader(reader appConfigReader) { h.appConfigReader = reader diff --git a/services/gateway-service/internal/transport/http/message_handler.go b/services/gateway-service/internal/transport/http/message_handler.go new file mode 100644 index 00000000..d7b15f39 --- /dev/null +++ b/services/gateway-service/internal/transport/http/message_handler.go @@ -0,0 +1,289 @@ +package http + +import ( + "net/http" + "strconv" + "strings" + "time" + + activityv1 "hyapp.local/api/proto/activity/v1" + userv1 "hyapp.local/api/proto/user/v1" + "hyapp/pkg/appcode" + "hyapp/services/gateway-service/internal/auth" +) + +type messageTabSectionData struct { + Section string `json:"section"` + Title string `json:"title"` + UnreadCount int64 `json:"unread_count"` + Source string `json:"source"` +} + +type inboxMessageData struct { + MessageID string `json:"message_id"` + Title string `json:"title"` + Summary string `json:"summary"` + Body string `json:"body"` + IconURL string `json:"icon_url"` + ImageURL string `json:"image_url"` + ActionType string `json:"action_type"` + ActionParam string `json:"action_param"` + Read bool `json:"read"` + SentAtMS int64 `json:"sent_at_ms"` +} + +type userProfileBatchData struct { + UserID string `json:"user_id"` + DisplayUserID string `json:"display_user_id"` + Username string `json:"username"` + Avatar string `json:"avatar,omitempty"` + Gender string `json:"gender,omitempty"` + Country string `json:"country,omitempty"` + RegionID int64 `json:"region_id,omitempty"` + AppCode string `json:"app_code"` +} + +// listMessageTabs returns backend unread summary and declares user conversations as Tencent IM SDK owned. +func (h *Handler) listMessageTabs(writer http.ResponseWriter, request *http.Request) { + if h.messageClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + resp, err := h.messageClient.ListMessageTabs(request.Context(), &activityv1.ListMessageTabsRequest{ + Meta: activityMeta(request), + UserId: auth.UserIDFromContext(request.Context()), + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + sections := make([]messageTabSectionData, 0, len(resp.GetSections())) + for _, section := range resp.GetSections() { + sections = append(sections, messageTabSectionData{ + Section: section.GetSection(), + Title: section.GetTitle(), + UnreadCount: section.GetUnreadCount(), + Source: section.GetSource(), + }) + } + writeOK(writer, request, map[string]any{"sections": sections}) +} + +// listInboxMessages reads system/activity inbox list; private user conversations stay in Tencent IM SDK. +func (h *Handler) listInboxMessages(writer http.ResponseWriter, request *http.Request) { + if h.messageClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + pageSize, ok := parseMessagePageSize(request.URL.Query().Get("page_size")) + if !ok { + writeError(writer, request, http.StatusBadRequest, codeInvalidArgument, "invalid argument") + return + } + section := strings.TrimSpace(request.URL.Query().Get("section")) + resp, err := h.messageClient.ListInboxMessages(request.Context(), &activityv1.ListInboxMessagesRequest{ + Meta: activityMeta(request), + UserId: auth.UserIDFromContext(request.Context()), + Section: section, + PageSize: pageSize, + PageToken: strings.TrimSpace(request.URL.Query().Get("page_token")), + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + items := make([]inboxMessageData, 0, len(resp.GetItems())) + for _, item := range resp.GetItems() { + items = append(items, inboxMessageData{ + MessageID: item.GetMessageId(), + Title: item.GetTitle(), + Summary: item.GetSummary(), + Body: item.GetBody(), + IconURL: item.GetIconUrl(), + ImageURL: item.GetImageUrl(), + ActionType: item.GetActionType(), + ActionParam: item.GetActionParam(), + Read: item.GetRead(), + SentAtMS: item.GetSentAtMs(), + }) + } + writeOK(writer, request, map[string]any{"section": resp.GetSection(), "items": items, "next_page_token": resp.GetNextPageToken()}) +} + +// markInboxSectionRead marks all current visible unread messages in one backend-owned section. +func (h *Handler) markInboxSectionRead(writer http.ResponseWriter, request *http.Request) { + if h.messageClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + var body struct { + Section string `json:"section"` + } + if !decode(writer, request, &body) { + return + } + resp, err := h.messageClient.MarkInboxSectionRead(request.Context(), &activityv1.MarkInboxSectionReadRequest{ + Meta: activityMeta(request), + UserId: auth.UserIDFromContext(request.Context()), + Section: body.Section, + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + writeOK(writer, request, map[string]any{"section": resp.GetSection(), "read_count": resp.GetReadCount()}) +} + +// inboxMessageByID handles per-message read and delete routes under /api/v1/messages/{message_id}. +func (h *Handler) inboxMessageByID(writer http.ResponseWriter, request *http.Request) { + if h.messageClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + messageID, readRoute := parseInboxMessagePath(request.URL.Path) + if messageID == "" { + writeError(writer, request, http.StatusNotFound, codeNotFound, "not found") + return + } + if readRoute { + h.markInboxMessageRead(writer, request, messageID) + return + } + if request.Method == http.MethodDelete { + h.deleteInboxMessage(writer, request, messageID) + return + } + writeError(writer, request, http.StatusNotFound, codeNotFound, "not found") +} + +func (h *Handler) markInboxMessageRead(writer http.ResponseWriter, request *http.Request, messageID string) { + if request.Method != http.MethodPost { + writeError(writer, request, http.StatusNotFound, codeNotFound, "not found") + return + } + resp, err := h.messageClient.MarkInboxMessageRead(request.Context(), &activityv1.MarkInboxMessageReadRequest{ + Meta: activityMeta(request), + UserId: auth.UserIDFromContext(request.Context()), + MessageId: messageID, + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + writeOK(writer, request, map[string]any{"message_id": resp.GetMessageId(), "read": resp.GetRead(), "read_at_ms": resp.GetReadAtMs()}) +} + +func (h *Handler) deleteInboxMessage(writer http.ResponseWriter, request *http.Request, messageID string) { + resp, err := h.messageClient.DeleteInboxMessage(request.Context(), &activityv1.DeleteInboxMessageRequest{ + Meta: activityMeta(request), + UserId: auth.UserIDFromContext(request.Context()), + MessageId: messageID, + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + writeOK(writer, request, map[string]any{"message_id": resp.GetMessageId(), "deleted": resp.GetDeleted()}) +} + +// batchUserProfiles returns only safe profile fields needed to render Tencent IM conversation rows. +func (h *Handler) batchUserProfiles(writer http.ResponseWriter, request *http.Request) { + if h.userProfileClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + userIDs, ok := parseBatchUserIDs(request) + if !ok { + writeError(writer, request, http.StatusBadRequest, codeInvalidArgument, "invalid argument") + return + } + resp, err := h.userProfileClient.BatchGetUsers(request.Context(), &userv1.BatchGetUsersRequest{ + Meta: authRequestMeta(request, ""), + UserIds: userIDs, + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + items := make([]userProfileBatchData, 0, len(resp.GetUsers())) + for _, userID := range userIDs { + if user := resp.GetUsers()[userID]; user != nil { + items = append(items, userProfileBatchData{ + UserID: strconv.FormatInt(user.GetUserId(), 10), + DisplayUserID: user.GetDisplayUserId(), + Username: user.GetUsername(), + Avatar: user.GetAvatar(), + Gender: user.GetGender(), + Country: user.GetCountry(), + RegionID: user.GetRegionId(), + AppCode: user.GetAppCode(), + }) + } + } + writeOK(writer, request, map[string]any{"profiles": items}) +} + +func activityMeta(request *http.Request) *activityv1.RequestMeta { + return &activityv1.RequestMeta{ + RequestId: requestIDFromContext(request.Context()), + Caller: "gateway-service", + GatewayNodeId: "gateway-local", + SentAtMs: time.Now().UnixMilli(), + AppCode: appcode.FromContext(request.Context()), + } +} + +func parseMessagePageSize(raw string) (int32, bool) { + raw = strings.TrimSpace(raw) + if raw == "" { + return 0, true + } + value, err := strconv.Atoi(raw) + if err != nil || value < 0 || value > 1000 { + return 0, false + } + return int32(value), true +} + +func parseInboxMessagePath(path string) (string, bool) { + tail := strings.TrimPrefix(path, apiV1Prefix+"/messages/") + tail = strings.Trim(tail, "/") + if tail == "" || tail == "tabs" || tail == "read-all" { + return "", false + } + if strings.HasSuffix(tail, "/read") { + messageID := strings.TrimSuffix(tail, "/read") + return strings.Trim(messageID, "/"), true + } + if strings.Contains(tail, "/") { + return "", false + } + return tail, false +} + +func parseBatchUserIDs(request *http.Request) ([]int64, bool) { + rawValues := append([]string(nil), request.URL.Query()["user_ids"]...) + rawValues = append(rawValues, request.URL.Query()["user_id"]...) + seen := make(map[int64]bool) + result := make([]int64, 0, len(rawValues)) + for _, raw := range rawValues { + for _, piece := range strings.Split(raw, ",") { + piece = strings.TrimSpace(piece) + if piece == "" { + continue + } + userID, err := strconv.ParseInt(piece, 10, 64) + if err != nil || userID <= 0 { + return nil, false + } + if !seen[userID] { + seen[userID] = true + result = append(result, userID) + } + } + } + if len(result) == 0 || len(result) > 100 { + return nil, false + } + return result, true +} diff --git a/services/gateway-service/internal/transport/http/middleware.go b/services/gateway-service/internal/transport/http/middleware.go index 9d332712..49e1be80 100644 --- a/services/gateway-service/internal/transport/http/middleware.go +++ b/services/gateway-service/internal/transport/http/middleware.go @@ -12,24 +12,6 @@ import ( "hyapp/services/gateway-service/internal/auth" ) -// apiHandler 包装所有 gateway 业务 HTTP API 的公共入口能力。 -// 顺序必须是 request_id -> auth -> handler,保证鉴权失败也能返回可追踪 request_id。 -func apiHandler(jwtVerifier *auth.Verifier, next http.HandlerFunc) http.Handler { - return withRequestID(withAccessLog(withAuth(jwtVerifier, next))) -} - -// profileAPIHandler 包装必须完成注册资料才能访问的业务 API。 -// 三方登录后未完成资料的用户已经有合法 token,但不能进入房间、IM、RTC 或付费链路。 -func profileAPIHandler(jwtVerifier *auth.Verifier, next http.HandlerFunc) http.Handler { - return withRequestID(withAccessLog(withAuth(jwtVerifier, requireCompletedProfile(next)))) -} - -// publicAPIHandler 包装不需要 access token 的业务 API。 -// 登录注册链路仍然有 request_id,但不能要求用户已经有 access token。 -func publicAPIHandler(next http.HandlerFunc) http.Handler { - return withRequestID(withAccessLog(next)) -} - // apiHandler 包装需要 app 解析和 access token 的业务 API。 func (h *Handler) apiHandler(jwtVerifier *auth.Verifier, next http.HandlerFunc) http.Handler { return withRequestID(withAccessLog(h.withResolvedApp(withAuth(jwtVerifier, next)))) @@ -124,6 +106,18 @@ func firstHeader(request *http.Request, names ...string) string { return "" } +// requireMethod 在业务 handler 之前固定 HTTP method,避免 path-only mux 让错误 method 进入命令链路。 +func requireMethod(method string, next http.HandlerFunc) http.HandlerFunc { + return func(writer http.ResponseWriter, request *http.Request) { + if request.Method != method { + writeError(writer, request, http.StatusMethodNotAllowed, codeInvalidArgument, "invalid argument") + return + } + + next(writer, request) + } +} + // requireCompletedProfile 在 gateway 层执行外部准入门禁。 // 这里故意不访问 user-service,依赖 access token 快照,避免所有高频房间入口同步打用户服务。 func requireCompletedProfile(next http.HandlerFunc) http.HandlerFunc { diff --git a/services/gateway-service/internal/transport/http/my_page_overview_handler.go b/services/gateway-service/internal/transport/http/my_page_overview_handler.go new file mode 100644 index 00000000..f4a123de --- /dev/null +++ b/services/gateway-service/internal/transport/http/my_page_overview_handler.go @@ -0,0 +1,294 @@ +package http + +import ( + "context" + "net/http" + "sync" + "time" + + activityv1 "hyapp.local/api/proto/activity/v1" + userv1 "hyapp.local/api/proto/user/v1" + walletv1 "hyapp.local/api/proto/wallet/v1" + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + "hyapp/services/gateway-service/internal/auth" +) + +const overviewAggregationTimeout = 200 * time.Millisecond + +var overviewAssetTypes = []string{"COIN", "DIAMOND", "USD_BALANCE"} + +type myOverviewData struct { + Profile userProfileData `json:"profile"` + Wallet overviewWalletData `json:"wallet"` + Roles overviewRolesData `json:"roles"` + Badges overviewBadgesData `json:"badges"` + Entries []overviewEntryData `json:"entries"` + ServerTimeMS int64 `json:"server_time_ms"` +} + +type overviewWalletData struct { + Balances []assetBalanceData `json:"balances"` + RechargeEnabled bool `json:"recharge_enabled"` + DiamondExchangeEnabled bool `json:"diamond_exchange_enabled"` + WithdrawEnabled bool `json:"withdraw_enabled"` + Unavailable bool `json:"unavailable,omitempty"` +} + +type overviewRolesData struct { + IsHost bool `json:"is_host"` + IsAgent bool `json:"is_agent"` + IsBD bool `json:"is_bd"` + IsBDLeader bool `json:"is_bd_leader"` + IsCoinSeller bool `json:"is_coin_seller"` + Unavailable bool `json:"unavailable,omitempty"` +} + +type overviewBadgesData struct { + UnreadSystemMessages int64 `json:"unread_system_messages"` + UnreadActivityMessages int64 `json:"unread_activity_messages"` + PendingRoleInvitations int64 `json:"pending_role_invitations"` + Unavailable bool `json:"unavailable,omitempty"` +} + +type overviewEntryData struct { + Key string `json:"key"` + Title string `json:"title"` + Visible bool `json:"visible"` + BadgeCount int64 `json:"badge_count"` +} + +// getMyOverview 聚合 App 我的页首屏摘要;gateway 只做 RPC 编排和入口显隐规则,不查数据库。 +func (h *Handler) getMyOverview(writer http.ResponseWriter, request *http.Request) { + if h.userProfileClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + + ctx, cancel := context.WithTimeout(request.Context(), overviewAggregationTimeout) + defer cancel() + + userID := auth.UserIDFromContext(request.Context()) + var wg sync.WaitGroup + + var profileResp *userv1.GetUserResponse + var profileErr error + wg.Add(1) + go func() { + defer wg.Done() + profileResp, profileErr = h.userProfileClient.GetUser(ctx, &userv1.GetUserRequest{ + Meta: authRequestMeta(request.WithContext(ctx), ""), + UserId: userID, + }) + }() + + var walletResp *walletv1.GetBalancesResponse + var walletErr error + wg.Add(1) + go func() { + defer wg.Done() + if h.walletClient == nil { + walletErr = xerr.New(xerr.Unavailable, "wallet service is not configured") + return + } + walletResp, walletErr = h.walletClient.GetBalances(ctx, &walletv1.GetBalancesRequest{ + RequestId: requestIDFromContext(request.Context()), + UserId: userID, + AssetTypes: append([]string(nil), overviewAssetTypes...), + AppCode: appcode.FromContext(request.Context()), + }) + }() + + var roles overviewRolesData + var rolesErr error + wg.Add(1) + go func() { + defer wg.Done() + roles, rolesErr = h.getOverviewRoles(ctx, request, userID) + }() + + var tabsResp *activityv1.ListMessageTabsResponse + var tabsErr error + wg.Add(1) + go func() { + defer wg.Done() + if h.messageClient == nil { + tabsErr = xerr.New(xerr.Unavailable, "message service is not configured") + return + } + tabsResp, tabsErr = h.messageClient.ListMessageTabs(ctx, &activityv1.ListMessageTabsRequest{ + Meta: activityMeta(request.WithContext(ctx)), + UserId: userID, + }) + }() + + wg.Wait() + if profileErr != nil { + writeRPCError(writer, request, profileErr) + return + } + if profileResp.GetUser() == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + + if rolesErr != nil { + roles = overviewRolesData{Unavailable: true} + } + wallet := overviewWallet(walletResp, walletErr) + badges := overviewBadges(tabsResp, tabsErr) + + writeOK(writer, request, myOverviewData{ + Profile: profileData(profileResp.GetUser(), 0), + Wallet: wallet, + Roles: roles, + Badges: badges, + Entries: overviewEntries(roles), + ServerTimeMS: time.Now().UnixMilli(), + }) +} + +func (h *Handler) getOverviewRoles(ctx context.Context, request *http.Request, userID int64) (overviewRolesData, error) { + if h.userHostClient == nil { + return overviewRolesData{}, xerr.New(xerr.Unavailable, "user host service is not configured") + } + + var wg sync.WaitGroup + var hostProfile *userv1.HostProfile + var bdProfile *userv1.BDProfile + var coinSellerProfile *userv1.CoinSellerProfile + var roleErr error + var roleErrOnce sync.Once + + setRoleErr := func(err error) { + if err == nil || xerr.ReasonFromGRPC(err) == xerr.NotFound { + return + } + roleErrOnce.Do(func() { + roleErr = err + }) + } + + wg.Add(3) + go func() { + defer wg.Done() + resp, err := h.userHostClient.GetHostProfile(ctx, &userv1.GetHostProfileRequest{ + Meta: authRequestMeta(request.WithContext(ctx), ""), + UserId: userID, + }) + if err != nil { + setRoleErr(err) + return + } + hostProfile = resp.GetHostProfile() + }() + go func() { + defer wg.Done() + resp, err := h.userHostClient.GetBDProfile(ctx, &userv1.GetBDProfileRequest{ + Meta: authRequestMeta(request.WithContext(ctx), ""), + UserId: userID, + }) + if err != nil { + setRoleErr(err) + return + } + bdProfile = resp.GetBdProfile() + }() + go func() { + defer wg.Done() + resp, err := h.userHostClient.GetCoinSellerProfile(ctx, &userv1.GetCoinSellerProfileRequest{ + Meta: authRequestMeta(request.WithContext(ctx), ""), + UserId: userID, + }) + if err != nil { + setRoleErr(err) + return + } + coinSellerProfile = resp.GetCoinSellerProfile() + }() + wg.Wait() + if roleErr != nil { + return overviewRolesData{}, roleErr + } + + identity := userHostIdentityData{} + applyHostIdentity(&identity, hostProfile) + applyBDIdentity(&identity, bdProfile) + applyCoinSellerIdentity(&identity, coinSellerProfile) + + return overviewRolesData{ + IsHost: identity.IsHost, + IsAgent: identity.IsAgent, + IsBD: identity.IsBD, + IsBDLeader: identity.IsBDLeader, + IsCoinSeller: identity.IsCoinSeller, + }, nil +} + +func overviewWallet(resp *walletv1.GetBalancesResponse, err error) overviewWalletData { + if err != nil { + return overviewWalletData{ + Balances: []assetBalanceData{}, + Unavailable: true, + } + } + + byType := make(map[string]*walletv1.AssetBalance) + for _, balance := range resp.GetBalances() { + if balance == nil { + continue + } + byType[balance.GetAssetType()] = balance + } + + balances := make([]assetBalanceData, 0, len(overviewAssetTypes)) + for _, assetType := range overviewAssetTypes { + balance := byType[assetType] + item := assetBalanceData{AssetType: assetType} + if balance != nil { + item.AvailableAmount = balance.GetAvailableAmount() + item.FrozenAmount = balance.GetFrozenAmount() + item.Version = balance.GetVersion() + } + balances = append(balances, item) + } + + return overviewWalletData{ + Balances: balances, + RechargeEnabled: true, + DiamondExchangeEnabled: true, + WithdrawEnabled: true, + } +} + +func overviewBadges(resp *activityv1.ListMessageTabsResponse, err error) overviewBadgesData { + if err != nil { + return overviewBadgesData{Unavailable: true} + } + + var badges overviewBadgesData + for _, section := range resp.GetSections() { + switch section.GetSection() { + case "system": + badges.UnreadSystemMessages = section.GetUnreadCount() + case "activity": + badges.UnreadActivityMessages = section.GetUnreadCount() + } + } + return badges +} + +func overviewEntries(roles overviewRolesData) []overviewEntryData { + return []overviewEntryData{ + {Key: "wallet", Title: "Wallet", Visible: true}, + {Key: "host_center", Title: "Host Center", Visible: roles.IsHost}, + {Key: "apply_host", Title: "Apply Host", Visible: !roles.IsHost}, + {Key: "agency_center", Title: "Agency Center", Visible: roles.IsAgent}, + {Key: "bd_center", Title: "BD Center", Visible: roles.IsBD}, + {Key: "bd_leader_center", Title: "BD Leader Center", Visible: roles.IsBDLeader}, + {Key: "coin_seller_center", Title: "Coin Seller", Visible: roles.IsCoinSeller}, + {Key: "backpack", Title: "Backpack", Visible: true}, + {Key: "settings", Title: "Settings", Visible: true}, + {Key: "support", Title: "Support", Visible: true}, + } +} diff --git a/services/gateway-service/internal/transport/http/my_page_overview_handler_test.go b/services/gateway-service/internal/transport/http/my_page_overview_handler_test.go new file mode 100644 index 00000000..397e5425 --- /dev/null +++ b/services/gateway-service/internal/transport/http/my_page_overview_handler_test.go @@ -0,0 +1,218 @@ +package http + +import ( + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "testing" + + activityv1 "hyapp.local/api/proto/activity/v1" + userv1 "hyapp.local/api/proto/user/v1" + walletv1 "hyapp.local/api/proto/wallet/v1" + "hyapp/pkg/xerr" + "hyapp/services/gateway-service/internal/auth" +) + +func TestGetMyOverviewComposesProfileWalletRolesBadgesAndEntries(t *testing.T) { + profileClient := &fakeUserProfileClient{regionID: 10} + walletClient := &fakeWalletClient{resp: &walletv1.GetBalancesResponse{Balances: []*walletv1.AssetBalance{ + {AssetType: "COIN", AvailableAmount: 12000, Version: 8}, + {AssetType: "GIFT_POINT", AvailableAmount: 999}, + {AssetType: "DIAMOND", AvailableAmount: 300, Version: 3}, + {AssetType: "USD_BALANCE", AvailableAmount: 2500, FrozenAmount: 500, Version: 2}, + }}} + hostClient := &fakeUserHostClient{ + hostProfile: &userv1.HostProfile{UserId: 42, Status: "active", Source: "admin_create_agency"}, + bdProfile: &userv1.BDProfile{UserId: 42, Status: "active", Role: "bd_leader"}, + profile: &userv1.CoinSellerProfile{UserId: 42, Status: "active", MerchantAssetType: "COIN_SELLER_COIN"}, + } + messageClient := &fakeMessageInboxClient{tabsResp: &activityv1.ListMessageTabsResponse{Sections: []*activityv1.MessageTabSection{ + {Section: "user", Title: "用户", UnreadCount: 99, Source: "tencent_im_sdk"}, + {Section: "system", Title: "系统", UnreadCount: 2, Source: "backend"}, + {Section: "activity", Title: "活动", UnreadCount: 1, Source: "backend"}, + }}} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, profileClient) + handler.SetWalletClient(walletClient) + handler.SetUserHostClient(hostClient) + handler.SetMessageInboxClient(messageClient) + + data := performOverviewRequest(t, handler, "req-overview") + + if profileClient.lastGet == nil || profileClient.lastGet.GetUserId() != 42 || profileClient.lastGet.GetMeta().GetAppCode() != "lalu" { + t.Fatalf("profile request mismatch: %+v", profileClient.lastGet) + } + if walletClient.last == nil || walletClient.last.GetUserId() != 42 || walletClient.last.GetAppCode() != "lalu" { + t.Fatalf("wallet request mismatch: %+v", walletClient.last) + } + if got := walletClient.last.GetAssetTypes(); len(got) != 3 || got[0] != "COIN" || got[1] != "DIAMOND" || got[2] != "USD_BALANCE" { + t.Fatalf("overview wallet asset types mismatch: %+v", got) + } + if hostClient.lastHost == nil || hostClient.lastHost.GetUserId() != 42 || hostClient.lastBD == nil || hostClient.lastBD.GetUserId() != 42 || hostClient.last == nil || hostClient.last.GetUserId() != 42 { + t.Fatalf("role requests mismatch: host=%+v bd=%+v coin=%+v", hostClient.lastHost, hostClient.lastBD, hostClient.last) + } + if messageClient.lastTabs == nil || messageClient.lastTabs.GetUserId() != 42 || messageClient.lastTabs.GetMeta().GetRequestId() != "req-overview" { + t.Fatalf("message tabs request mismatch: %+v", messageClient.lastTabs) + } + + profile := data["profile"].(map[string]any) + if profile["user_id"] != "42" || profile["username"] != "hy" || profile["region_id"] != float64(10) { + t.Fatalf("profile data mismatch: %+v", profile) + } + roles := data["roles"].(map[string]any) + if roles["is_host"] != true || roles["is_agent"] != true || roles["is_bd"] != true || roles["is_bd_leader"] != true || roles["is_coin_seller"] != true { + t.Fatalf("roles data mismatch: %+v", roles) + } + badges := data["badges"].(map[string]any) + if badges["unread_system_messages"] != float64(2) || badges["unread_activity_messages"] != float64(1) || badges["pending_role_invitations"] != float64(0) { + t.Fatalf("badges data mismatch: %+v", badges) + } + wallet := data["wallet"].(map[string]any) + if wallet["recharge_enabled"] != true || wallet["diamond_exchange_enabled"] != true || wallet["withdraw_enabled"] != true { + t.Fatalf("wallet feature flags mismatch: %+v", wallet) + } + balances := wallet["balances"].([]any) + if len(balances) != 3 { + t.Fatalf("overview must return three fixed balances, got %+v", balances) + } + if balanceAssetType(balances[0]) != "COIN" || balanceAvailable(balances[0]) != 12000 || + balanceAssetType(balances[1]) != "DIAMOND" || balanceAvailable(balances[1]) != 300 || + balanceAssetType(balances[2]) != "USD_BALANCE" || balanceAvailable(balances[2]) != 2500 { + t.Fatalf("balance projection mismatch: %+v", balances) + } + + entries := data["entries"].([]any) + if !overviewEntryVisible(entries, "wallet") || + !overviewEntryVisible(entries, "host_center") || + !overviewEntryVisible(entries, "agency_center") || + !overviewEntryVisible(entries, "bd_center") || + !overviewEntryVisible(entries, "bd_leader_center") || + !overviewEntryVisible(entries, "coin_seller_center") || + overviewEntryVisible(entries, "apply_host") { + t.Fatalf("entry visibility mismatch: %+v", entries) + } + if data["server_time_ms"].(float64) <= 0 { + t.Fatalf("missing server_time_ms: %+v", data) + } +} + +func TestGetMyOverviewFillsMissingWalletBalancesForOrdinaryUser(t *testing.T) { + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetWalletClient(&fakeWalletClient{resp: &walletv1.GetBalancesResponse{}}) + handler.SetUserHostClient(&fakeUserHostClient{}) + handler.SetMessageInboxClient(&fakeMessageInboxClient{}) + + data := performOverviewRequest(t, handler, "req-overview-empty-wallet") + + wallet := data["wallet"].(map[string]any) + balances := wallet["balances"].([]any) + if len(balances) != 3 { + t.Fatalf("missing wallet rows must still project three balances: %+v", balances) + } + for _, balance := range balances { + item := balance.(map[string]any) + if item["available_amount"] != float64(0) || item["frozen_amount"] != float64(0) || item["version"] != float64(0) { + t.Fatalf("missing balance should be zero projection: %+v", item) + } + } + roles := data["roles"].(map[string]any) + if roles["is_host"] != false || roles["is_bd"] != false || roles["is_coin_seller"] != false { + t.Fatalf("ordinary roles mismatch: %+v", roles) + } + entries := data["entries"].([]any) + if !overviewEntryVisible(entries, "apply_host") || overviewEntryVisible(entries, "host_center") { + t.Fatalf("ordinary entries mismatch: %+v", entries) + } +} + +func TestGetMyOverviewDegradesOptionalUpstreamFailures(t *testing.T) { + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetWalletClient(&fakeWalletClient{err: errors.New("wallet down")}) + handler.SetUserHostClient(&fakeUserHostClient{hostErr: xerr.ToGRPCError(xerr.New(xerr.Internal, "role service down"))}) + handler.SetMessageInboxClient(&fakeMessageInboxClient{err: errors.New("message down")}) + + data := performOverviewRequest(t, handler, "req-overview-degraded") + + wallet := data["wallet"].(map[string]any) + if wallet["unavailable"] != true || len(wallet["balances"].([]any)) != 0 { + t.Fatalf("wallet degradation mismatch: %+v", wallet) + } + roles := data["roles"].(map[string]any) + if roles["unavailable"] != true || roles["is_host"] != false || roles["is_bd"] != false || roles["is_coin_seller"] != false { + t.Fatalf("roles degradation mismatch: %+v", roles) + } + badges := data["badges"].(map[string]any) + if badges["unavailable"] != true || badges["unread_system_messages"] != float64(0) || badges["unread_activity_messages"] != float64(0) { + t.Fatalf("badges degradation mismatch: %+v", badges) + } + entries := data["entries"].([]any) + if overviewEntryVisible(entries, "host_center") || overviewEntryVisible(entries, "bd_center") || overviewEntryVisible(entries, "coin_seller_center") { + t.Fatalf("degraded roles must not expose privileged entries: %+v", entries) + } +} + +func TestGetMyOverviewFailsWhenProfileFails(t *testing.T) { + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{ + getErr: xerr.ToGRPCError(xerr.New(xerr.NotFound, "user not found")), + }) + handler.SetWalletClient(&fakeWalletClient{}) + handler.SetUserHostClient(&fakeUserHostClient{}) + handler.SetMessageInboxClient(&fakeMessageInboxClient{}) + router := handler.Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/users/me/overview", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-overview-profile-fail") + recorder := httptest.NewRecorder() + + router.ServeHTTP(recorder, request) + + assertEnvelope(t, recorder, http.StatusNotFound, string(xerr.NotFound), "req-overview-profile-fail") +} + +func performOverviewRequest(t *testing.T, handler *Handler, requestID string) map[string]any { + t.Helper() + + router := handler.Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/users/me/overview", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", requestID) + 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 responseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode overview response failed: %v", err) + } + data, ok := response.Data.(map[string]any) + if response.Code != codeOK || !ok || response.RequestID != requestID { + t.Fatalf("overview envelope mismatch: %+v", response) + } + return data +} + +func overviewEntryVisible(entries []any, key string) bool { + for _, entry := range entries { + item, ok := entry.(map[string]any) + if ok && item["key"] == key { + visible, _ := item["visible"].(bool) + return visible + } + } + return false +} + +func balanceAssetType(balance any) string { + item, _ := balance.(map[string]any) + value, _ := item["asset_type"].(string) + return value +} + +func balanceAvailable(balance any) int64 { + item, _ := balance.(map[string]any) + value, _ := item["available_amount"].(float64) + return int64(value) +} diff --git a/services/gateway-service/internal/transport/http/response.go b/services/gateway-service/internal/transport/http/response.go index 1b475384..81af1b6d 100644 --- a/services/gateway-service/internal/transport/http/response.go +++ b/services/gateway-service/internal/transport/http/response.go @@ -105,13 +105,13 @@ func writeRPCError(writer http.ResponseWriter, request *http.Request, err error) func mapReasonToHTTP(reason xerr.Code) (int, string, string) { switch reason { - case xerr.InvalidArgument, xerr.DisplayUserIDInvalid: + case xerr.InvalidArgument, xerr.DisplayUserIDInvalid, xerr.InvalidSection, xerr.PageTokenInvalid: return http.StatusBadRequest, string(reason), "invalid argument" case xerr.AuthFailed: return http.StatusUnauthorized, string(reason), "authentication failed" case xerr.Unauthorized, xerr.SessionExpired, xerr.SessionRevoked: return http.StatusUnauthorized, string(reason), "unauthorized" - case xerr.Conflict, xerr.PasswordAlreadySet, xerr.DisplayUserIDExists: + case xerr.Conflict, xerr.PasswordAlreadySet, xerr.DisplayUserIDExists, xerr.RequestConflict, xerr.ProducerEventConflict: return http.StatusConflict, string(reason), "conflict" case xerr.RoomClosed: return http.StatusConflict, string(reason), "room closed" @@ -123,7 +123,7 @@ func mapReasonToHTTP(reason xerr.Code) (int, string, string) { return http.StatusForbidden, codeProfileRequired, "profile required" case xerr.UserDisabled, xerr.PermissionDenied: return http.StatusForbidden, string(reason), "permission denied" - case xerr.NotFound, xerr.DisplayUserIDNotFound, xerr.CountryNotFound, xerr.RegionNotFound: + case xerr.NotFound, xerr.DisplayUserIDNotFound, xerr.CountryNotFound, xerr.RegionNotFound, xerr.MessageNotFound, xerr.MessageRecalled: return http.StatusNotFound, string(reason), "not found" case xerr.Unavailable: return http.StatusBadGateway, codeUpstreamError, "upstream service error" diff --git a/services/gateway-service/internal/transport/http/response_test.go b/services/gateway-service/internal/transport/http/response_test.go index 4be7dfc4..77d9fd22 100644 --- a/services/gateway-service/internal/transport/http/response_test.go +++ b/services/gateway-service/internal/transport/http/response_test.go @@ -19,6 +19,7 @@ import ( "time" jwt "github.com/golang-jwt/jwt/v5" + activityv1 "hyapp.local/api/proto/activity/v1" roomv1 "hyapp.local/api/proto/room/v1" userv1 "hyapp.local/api/proto/user/v1" walletv1 "hyapp.local/api/proto/wallet/v1" @@ -160,6 +161,7 @@ type fakeUserAuthClient struct { type fakeUserProfileClient struct { lastGet *userv1.GetUserRequest + lastBatch *userv1.BatchGetUsersRequest getRequests []*userv1.GetUserRequest lastComplete *userv1.CompleteOnboardingRequest lastUpdate *userv1.UpdateUserProfileRequest @@ -178,9 +180,22 @@ type fakeUserIdentityClient struct { } type fakeRoomQueryClient struct { - lastList *roomv1.ListRoomsRequest - resp *roomv1.ListRoomsResponse - err error + lastList *roomv1.ListRoomsRequest + lastCurrent *roomv1.GetCurrentRoomRequest + lastSnapshot *roomv1.GetRoomSnapshotRequest + resp *roomv1.ListRoomsResponse + currentResp *roomv1.GetCurrentRoomResponse + snapshotResp *roomv1.GetRoomSnapshotResponse + err error + currentErr error + snapshotErr error +} + +type fakeUserDeviceClient struct { + lastBind *userv1.BindPushTokenRequest + lastDelete *userv1.DeletePushTokenRequest + bindErr error + deleteErr error } type fakeUserCountryQueryClient struct { @@ -210,6 +225,20 @@ type fakeWalletClient struct { transferErr error } +type fakeMessageInboxClient struct { + lastTabs *activityv1.ListMessageTabsRequest + lastList *activityv1.ListInboxMessagesRequest + lastRead *activityv1.MarkInboxMessageReadRequest + lastReadAll *activityv1.MarkInboxSectionReadRequest + lastDelete *activityv1.DeleteInboxMessageRequest + tabsResp *activityv1.ListMessageTabsResponse + listResp *activityv1.ListInboxMessagesResponse + readResp *activityv1.MarkInboxMessageReadResponse + readAllResp *activityv1.MarkInboxSectionReadResponse + deleteResp *activityv1.DeleteInboxMessageResponse + err error +} + func (f *fakeUserAuthClient) LoginPassword(_ context.Context, req *userv1.LoginPasswordRequest) (*userv1.AuthResponse, error) { f.lastLoginPassword = req f.loginPasswordCount++ @@ -287,6 +316,24 @@ func (f *fakeUserProfileClient) GetUser(_ context.Context, req *userv1.GetUserRe }}, nil } +func (f *fakeUserProfileClient) BatchGetUsers(_ context.Context, req *userv1.BatchGetUsersRequest) (*userv1.BatchGetUsersResponse, error) { + f.lastBatch = req + users := make(map[int64]*userv1.User, len(req.GetUserIds())) + for _, userID := range req.GetUserIds() { + users[userID] = &userv1.User{ + UserId: userID, + DisplayUserId: strconv.FormatInt(100000+userID, 10), + Username: "user-" + strconv.FormatInt(userID, 10), + Gender: "female", + Country: "US", + Avatar: "https://cdn.example/avatar.png", + RegionId: 1001, + AppCode: req.GetMeta().GetAppCode(), + } + } + return &userv1.BatchGetUsersResponse{Users: users}, nil +} + func (f *fakeUserProfileClient) CompleteOnboarding(_ context.Context, req *userv1.CompleteOnboardingRequest) (*userv1.CompleteOnboardingResponse, error) { f.lastComplete = req if f.completeErr != nil { @@ -396,6 +443,44 @@ func (f *fakeRoomQueryClient) ListRooms(_ context.Context, req *roomv1.ListRooms return &roomv1.ListRoomsResponse{}, nil } +func (f *fakeRoomQueryClient) GetCurrentRoom(_ context.Context, req *roomv1.GetCurrentRoomRequest) (*roomv1.GetCurrentRoomResponse, error) { + f.lastCurrent = req + if f.currentErr != nil { + return nil, f.currentErr + } + if f.currentResp != nil { + return f.currentResp, nil + } + return &roomv1.GetCurrentRoomResponse{}, nil +} + +func (f *fakeRoomQueryClient) GetRoomSnapshot(_ context.Context, req *roomv1.GetRoomSnapshotRequest) (*roomv1.GetRoomSnapshotResponse, error) { + f.lastSnapshot = req + if f.snapshotErr != nil { + return nil, f.snapshotErr + } + if f.snapshotResp != nil { + return f.snapshotResp, nil + } + return &roomv1.GetRoomSnapshotResponse{}, nil +} + +func (f *fakeUserDeviceClient) BindPushToken(_ context.Context, req *userv1.BindPushTokenRequest) (*userv1.BindPushTokenResponse, error) { + f.lastBind = req + if f.bindErr != nil { + return nil, f.bindErr + } + return &userv1.BindPushTokenResponse{Bound: true, UpdatedAtMs: 1234}, nil +} + +func (f *fakeUserDeviceClient) DeletePushToken(_ context.Context, req *userv1.DeletePushTokenRequest) (*userv1.DeletePushTokenResponse, error) { + f.lastDelete = req + if f.deleteErr != nil { + return nil, f.deleteErr + } + return &userv1.DeletePushTokenResponse{Deleted: true, UpdatedAtMs: 1235}, nil +} + func (f *fakeUserCountryQueryClient) ListRegistrationCountries(_ context.Context, req *userv1.ListRegistrationCountriesRequest) (*userv1.ListRegistrationCountriesResponse, error) { f.last = req if f.err != nil { @@ -408,6 +493,61 @@ func (f *fakeUserCountryQueryClient) ListRegistrationCountries(_ context.Context return &userv1.ListRegistrationCountriesResponse{}, nil } +func (f *fakeMessageInboxClient) ListMessageTabs(_ context.Context, req *activityv1.ListMessageTabsRequest) (*activityv1.ListMessageTabsResponse, error) { + f.lastTabs = req + if f.err != nil { + return nil, f.err + } + if f.tabsResp != nil { + return f.tabsResp, nil + } + return &activityv1.ListMessageTabsResponse{}, nil +} + +func (f *fakeMessageInboxClient) ListInboxMessages(_ context.Context, req *activityv1.ListInboxMessagesRequest) (*activityv1.ListInboxMessagesResponse, error) { + f.lastList = req + if f.err != nil { + return nil, f.err + } + if f.listResp != nil { + return f.listResp, nil + } + return &activityv1.ListInboxMessagesResponse{Section: req.GetSection()}, nil +} + +func (f *fakeMessageInboxClient) MarkInboxMessageRead(_ context.Context, req *activityv1.MarkInboxMessageReadRequest) (*activityv1.MarkInboxMessageReadResponse, error) { + f.lastRead = req + if f.err != nil { + return nil, f.err + } + if f.readResp != nil { + return f.readResp, nil + } + return &activityv1.MarkInboxMessageReadResponse{MessageId: req.GetMessageId(), Read: true, ReadAtMs: 1234}, nil +} + +func (f *fakeMessageInboxClient) MarkInboxSectionRead(_ context.Context, req *activityv1.MarkInboxSectionReadRequest) (*activityv1.MarkInboxSectionReadResponse, error) { + f.lastReadAll = req + if f.err != nil { + return nil, f.err + } + if f.readAllResp != nil { + return f.readAllResp, nil + } + return &activityv1.MarkInboxSectionReadResponse{Section: req.GetSection(), ReadCount: 2}, nil +} + +func (f *fakeMessageInboxClient) DeleteInboxMessage(_ context.Context, req *activityv1.DeleteInboxMessageRequest) (*activityv1.DeleteInboxMessageResponse, error) { + f.lastDelete = req + if f.err != nil { + return nil, f.err + } + if f.deleteResp != nil { + return f.deleteResp, nil + } + return &activityv1.DeleteInboxMessageResponse{MessageId: req.GetMessageId(), Deleted: true}, nil +} + func (f *fakeUserHostClient) GetHostProfile(_ context.Context, req *userv1.GetHostProfileRequest) (*userv1.GetHostProfileResponse, error) { f.lastHost = req if f.hostErr != nil { @@ -841,6 +981,154 @@ func TestListRoomsRejectsInvalidLimitBeforeGRPC(t *testing.T) { } } +func TestBindPushTokenUsesAuthenticatedUserAndDeviceMeta(t *testing.T) { + deviceClient := &fakeUserDeviceClient{} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetUserDeviceClient(deviceClient) + router := handler.Routes(auth.NewVerifier("secret")) + body := []byte(`{"device_id":"dev-1","push_token":"push-1","provider":"fcm","platform":"android","app_version":"1.2.3","language":"en-US","timezone":"America/Los_Angeles"}`) + request := httptest.NewRequest(http.MethodPost, "/api/v1/devices/push-token", bytes.NewReader(body)) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-bind-push") + 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 deviceClient.lastBind == nil || deviceClient.lastBind.GetUserId() != 42 || deviceClient.lastBind.GetMeta().GetDeviceId() != "dev-1" { + t.Fatalf("push token bind must use authenticated user and device meta: %+v", deviceClient.lastBind) + } + if deviceClient.lastBind.GetPushToken() != "push-1" || deviceClient.lastBind.GetPlatform() != "android" || deviceClient.lastBind.GetProvider() != "fcm" { + t.Fatalf("push token bind fields mismatch: %+v", deviceClient.lastBind) + } + var response responseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode bind response failed: %v", err) + } + data, ok := response.Data.(map[string]any) + if !ok || data["bound"] != true || data["updated_at_ms"].(float64) != 1234 { + t.Fatalf("push token response must keep explicit fields: %+v", response.Data) + } +} + +func TestDeletePushTokenUsesAuthenticatedUser(t *testing.T) { + deviceClient := &fakeUserDeviceClient{} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetUserDeviceClient(deviceClient) + router := handler.Routes(auth.NewVerifier("secret")) + body := []byte(`{"device_id":"dev-1","push_token":"push-1"}`) + request := httptest.NewRequest(http.MethodDelete, "/api/v1/devices/push-token", bytes.NewReader(body)) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-delete-push") + 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 deviceClient.lastDelete == nil || deviceClient.lastDelete.GetUserId() != 42 || deviceClient.lastDelete.GetDeviceId() != "dev-1" || deviceClient.lastDelete.GetPushToken() != "push-1" { + t.Fatalf("push token delete fields mismatch: %+v", deviceClient.lastDelete) + } + var response responseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode delete response failed: %v", err) + } + data, ok := response.Data.(map[string]any) + if !ok || data["deleted"] != true || data["updated_at_ms"].(float64) != 1235 { + t.Fatalf("push token delete response must keep explicit fields: %+v", response.Data) + } +} + +func TestGetCurrentRoomUsesAuthenticatedUser(t *testing.T) { + queryClient := &fakeRoomQueryClient{currentResp: &roomv1.GetCurrentRoomResponse{ + HasCurrentRoom: true, + RoomId: "room-current", + RoomVersion: 9, + Role: "audience", + NeedJoinImGroup: true, + ServerTimeMs: 123456, + }} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetRoomQueryClient(queryClient) + router := handler.Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/rooms/current?user_id=999", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-current-room") + 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 queryClient.lastCurrent == nil { + t.Fatal("current room query was not sent") + } + if queryClient.lastCurrent.GetUserId() != 42 || queryClient.lastCurrent.GetMeta().GetRequestId() != "req-current-room" { + t.Fatalf("current room must use authenticated user and request meta: %+v", queryClient.lastCurrent) + } + var response responseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode current room response failed: %v", err) + } + data, ok := response.Data.(map[string]any) + if !ok || data["has_current_room"] != true || data["need_rtc_token"] != false || data["room_id"] != "room-current" { + t.Fatalf("current room response must keep explicit booleans: %+v", response.Data) + } +} + +func TestGetRoomSnapshotUsesAuthenticatedUser(t *testing.T) { + queryClient := &fakeRoomQueryClient{snapshotResp: &roomv1.GetRoomSnapshotResponse{ + Room: &roomv1.RoomSnapshot{ + RoomId: "room-snapshot", + OwnerUserId: 42, + Status: "active", + Version: 7, + }, + ServerTimeMs: 123456, + }} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetRoomQueryClient(queryClient) + router := handler.Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/rooms/snapshot?room_id=room-snapshot&viewer_user_id=999", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-room-snapshot") + 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 queryClient.lastSnapshot == nil { + t.Fatal("room snapshot query was not sent") + } + if queryClient.lastSnapshot.GetViewerUserId() != 42 || queryClient.lastSnapshot.GetRoomId() != "room-snapshot" || queryClient.lastSnapshot.GetMeta().GetRequestId() != "req-room-snapshot" { + t.Fatalf("snapshot query must use authenticated user and request meta: %+v", queryClient.lastSnapshot) + } +} + +func TestGetRoomSnapshotRejectsInvalidRoomIDBeforeGRPC(t *testing.T) { + queryClient := &fakeRoomQueryClient{} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetRoomQueryClient(queryClient) + router := handler.Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/rooms/snapshot?room_id=room:bad", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-room-snapshot-invalid") + recorder := httptest.NewRecorder() + + router.ServeHTTP(recorder, request) + + assertEnvelope(t, recorder, http.StatusBadRequest, codeInvalidArgument, "req-room-snapshot-invalid") + if queryClient.lastSnapshot != nil { + t.Fatalf("invalid room_id must not reach room-service: %+v", queryClient.lastSnapshot) + } +} + func TestListRegistrationCountriesIsPublicAndReturnsCountryMetadata(t *testing.T) { countryClient := &fakeUserCountryQueryClient{resp: &userv1.ListRegistrationCountriesResponse{ Countries: []*userv1.Country{ @@ -942,6 +1230,34 @@ func TestListH5LinksRequiresConfigReader(t *testing.T) { assertEnvelope(t, recorder, http.StatusBadGateway, codeUpstreamError, "req-h5-links-missing") } +func TestAppBootstrapIsPublicAndLightweight(t *testing.T) { + router := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}).Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/app/bootstrap", nil) + request.Header.Set("X-Request-ID", "req-bootstrap") + request.Header.Set("X-App-Code", "lalu") + 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 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 != codeOK || !ok { + t.Fatalf("unexpected envelope: %+v", response) + } + if data["app_code"] != "lalu" || data["server_time_ms"].(float64) <= 0 || data["force_upgrade"] != false || data["maintenance"] != false { + t.Fatalf("bootstrap base fields mismatch: %+v", data) + } + if _, exists := data["banners"]; exists { + t.Fatalf("bootstrap must not return large config payloads: %+v", data) + } +} + func TestListAppBannersReturnsAdminAppConfig(t *testing.T) { handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) handler.SetAppConfigReader(appconfig.StaticReader{Banners: []appconfig.Banner{ @@ -1356,6 +1672,128 @@ func TestGetMyProfileUsesAuthenticatedUserID(t *testing.T) { } } +func TestMessageTabsAndInboxRoutesUseAuthenticatedUser(t *testing.T) { + messageClient := &fakeMessageInboxClient{tabsResp: &activityv1.ListMessageTabsResponse{Sections: []*activityv1.MessageTabSection{ + {Section: "user", Title: "用户", UnreadCount: 0, Source: "tencent_im_sdk"}, + {Section: "system", Title: "系统", UnreadCount: 2, Source: "backend"}, + {Section: "activity", Title: "活动", UnreadCount: 1, Source: "backend"}, + }}, listResp: &activityv1.ListInboxMessagesResponse{ + Section: "system", + Items: []*activityv1.InboxMessage{{ + MessageId: "msg-1", + Title: "提现审核通过", + Summary: "你的提现申请已通过。", + ActionType: "wallet_withdraw_detail", + ActionParam: "withdrawal_id=wd_01", + SentAtMs: 1777996800000, + }}, + NextPageToken: "cursor-2", + }} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetMessageInboxClient(messageClient) + router := handler.Routes(auth.NewVerifier("secret")) + + request := httptest.NewRequest(http.MethodGet, "/api/v1/messages/tabs", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-message-tabs") + recorder := httptest.NewRecorder() + router.ServeHTTP(recorder, request) + if recorder.Code != http.StatusOK { + t.Fatalf("tabs status mismatch: got %d body=%s", recorder.Code, recorder.Body.String()) + } + if messageClient.lastTabs == nil || messageClient.lastTabs.GetUserId() != 42 || messageClient.lastTabs.GetMeta().GetAppCode() != "lalu" || messageClient.lastTabs.GetMeta().GetRequestId() != "req-message-tabs" { + t.Fatalf("message tabs request mismatch: %+v", messageClient.lastTabs) + } + + request = httptest.NewRequest(http.MethodGet, "/api/v1/messages?section=system&page_size=20&page_token=cursor-1", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-message-list") + recorder = httptest.NewRecorder() + router.ServeHTTP(recorder, request) + if recorder.Code != http.StatusOK { + t.Fatalf("list status mismatch: got %d body=%s", recorder.Code, recorder.Body.String()) + } + if messageClient.lastList == nil || messageClient.lastList.GetUserId() != 42 || messageClient.lastList.GetSection() != "system" || messageClient.lastList.GetPageSize() != 20 || messageClient.lastList.GetPageToken() != "cursor-1" { + t.Fatalf("message list request mismatch: %+v", messageClient.lastList) + } + var response responseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode list response failed: %v", err) + } + data, ok := response.Data.(map[string]any) + if response.Code != codeOK || !ok || data["section"] != "system" || data["next_page_token"] != "cursor-2" { + t.Fatalf("message list envelope mismatch: %+v", response) + } +} + +func TestMessageReadAllReadAndDeleteRoutes(t *testing.T) { + messageClient := &fakeMessageInboxClient{} + handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{}) + handler.SetMessageInboxClient(messageClient) + router := handler.Routes(auth.NewVerifier("secret")) + + request := httptest.NewRequest(http.MethodPost, "/api/v1/messages/read-all", bytes.NewReader([]byte(`{"section":"activity"}`))) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-message-read-all") + recorder := httptest.NewRecorder() + router.ServeHTTP(recorder, request) + if recorder.Code != http.StatusOK || messageClient.lastReadAll == nil || messageClient.lastReadAll.GetUserId() != 42 || messageClient.lastReadAll.GetSection() != "activity" { + t.Fatalf("read-all mismatch: status=%d body=%s req=%+v", recorder.Code, recorder.Body.String(), messageClient.lastReadAll) + } + + request = httptest.NewRequest(http.MethodPost, "/api/v1/messages/msg-1/read", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-message-read") + recorder = httptest.NewRecorder() + router.ServeHTTP(recorder, request) + if recorder.Code != http.StatusOK || messageClient.lastRead == nil || messageClient.lastRead.GetUserId() != 42 || messageClient.lastRead.GetMessageId() != "msg-1" { + t.Fatalf("read mismatch: status=%d body=%s req=%+v", recorder.Code, recorder.Body.String(), messageClient.lastRead) + } + + request = httptest.NewRequest(http.MethodDelete, "/api/v1/messages/msg-1", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-message-delete") + recorder = httptest.NewRecorder() + router.ServeHTTP(recorder, request) + if recorder.Code != http.StatusOK || messageClient.lastDelete == nil || messageClient.lastDelete.GetUserId() != 42 || messageClient.lastDelete.GetMessageId() != "msg-1" { + t.Fatalf("delete mismatch: status=%d body=%s req=%+v", recorder.Code, recorder.Body.String(), messageClient.lastDelete) + } +} + +func TestBatchUserProfilesReturnsOnlySafeDisplayFields(t *testing.T) { + profileClient := &fakeUserProfileClient{} + router := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, profileClient).Routes(auth.NewVerifier("secret")) + request := httptest.NewRequest(http.MethodGet, "/api/v1/users/profiles:batch?user_ids=42,43", nil) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 7)) + request.Header.Set("X-Request-ID", "req-profile-batch") + 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.lastBatch == nil || profileClient.lastBatch.GetMeta().GetRequestId() != "req-profile-batch" || len(profileClient.lastBatch.GetUserIds()) != 2 { + t.Fatalf("batch user request mismatch: %+v", profileClient.lastBatch) + } + var response responseEnvelope + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode profile batch failed: %v", err) + } + data, ok := response.Data.(map[string]any) + profiles, profilesOK := data["profiles"].([]any) + if response.Code != codeOK || !ok || !profilesOK || len(profiles) != 2 { + t.Fatalf("profile batch response mismatch: %+v", response) + } + first, ok := profiles[0].(map[string]any) + if !ok || first["user_id"] != "42" || first["display_user_id"] == "" || first["username"] == "" || first["app_code"] != "lalu" { + t.Fatalf("profile batch item mismatch: %+v", first) + } + if _, exists := first["birth"]; exists { + t.Fatalf("profile batch must not expose birth or other non-conversation fields: %+v", first) + } +} + func TestGetMyBalancesUsesAuthenticatedUserIDAndDefaultsCoin(t *testing.T) { walletClient := &fakeWalletClient{resp: &walletv1.GetBalancesResponse{ Balances: []*walletv1.AssetBalance{{AssetType: "COIN", AvailableAmount: 120, FrozenAmount: 3, Version: 2}}, @@ -1600,6 +2038,12 @@ func TestProfileGateRejectsIncompleteUsersForRoomIMRTCPaidCapabilities(t *testin {name: "im_usersig", method: http.MethodGet, path: "/api/v1/im/usersig"}, {name: "rtc_token", method: http.MethodPost, path: "/api/v1/rtc/token", body: `{"room_id":"room-1"}`}, {name: "send_gift", method: http.MethodPost, path: "/api/v1/rooms/gift/send", body: `{"room_id":"room-1","gift_id":"rose"}`}, + {name: "message_tabs", method: http.MethodGet, path: "/api/v1/messages/tabs"}, + {name: "message_list", method: http.MethodGet, path: "/api/v1/messages?section=system"}, + {name: "message_read", method: http.MethodPost, path: "/api/v1/messages/msg-1/read"}, + {name: "message_read_all", method: http.MethodPost, path: "/api/v1/messages/read-all", body: `{"section":"system"}`}, + {name: "message_delete", method: http.MethodDelete, path: "/api/v1/messages/msg-1"}, + {name: "profiles_batch", method: http.MethodGet, path: "/api/v1/users/profiles:batch?user_ids=42"}, } for _, test := range tests { @@ -1627,6 +2071,51 @@ func TestProfileGateRejectsIncompleteUsersForRoomIMRTCPaidCapabilities(t *testin } } +func TestVoiceRoomRoutesRejectWrongHTTPMethod(t *testing.T) { + roomClient := &fakeRoomClient{} + queryClient := &fakeRoomQueryClient{} + guardClient := &fakeRoomGuardClient{presenceResp: &roomv1.VerifyRoomPresenceResponse{Present: true, RoomVersion: 1}} + handler := NewHandlerWithConfig(roomClient, guardClient, nil, nil, TencentIMConfig{ + SDKAppID: 1400000000, + SecretKey: "secret", + UserSigTTL: time.Hour, + }) + handler.SetTencentRTC(TencentRTCConfig{Enabled: true, SDKAppID: 1400000000, SecretKey: "secret", UserSigTTL: time.Hour}) + handler.SetRoomQueryClient(queryClient) + router := handler.Routes(auth.NewVerifier("secret")) + + tests := []struct { + name string + method string + path string + body string + }{ + {name: "rooms_list", method: http.MethodPost, path: "/api/v1/rooms"}, + {name: "current_room", method: http.MethodPost, path: "/api/v1/rooms/current"}, + {name: "join_room", method: http.MethodGet, path: "/api/v1/rooms/join", body: `{"room_id":"room-1"}`}, + {name: "heartbeat", method: http.MethodGet, path: "/api/v1/rooms/heartbeat", body: `{"room_id":"room-1"}`}, + {name: "im_usersig", method: http.MethodPost, path: "/api/v1/im/usersig"}, + {name: "rtc_token", method: http.MethodGet, path: "/api/v1/rtc/token"}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + request := httptest.NewRequest(test.method, test.path, bytes.NewReader([]byte(test.body))) + request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42)) + request.Header.Set("X-Request-ID", "req-method-guard") + recorder := httptest.NewRecorder() + + router.ServeHTTP(recorder, request) + + assertEnvelope(t, recorder, http.StatusMethodNotAllowed, codeInvalidArgument, "req-method-guard") + }) + } + + if roomClient.lastJoin != nil || roomClient.lastHeartbeat != nil || queryClient.lastList != nil || queryClient.lastCurrent != nil || guardClient.lastPresence != nil { + t.Fatalf("method guard must stop voice-room calls before downstream clients: room=%+v query=%+v guard=%+v", roomClient, queryClient, guardClient) + } +} + func TestUploadAvatarAllowsIncompleteProfileAndWritesObject(t *testing.T) { uploader := &fakeObjectUploader{} handler := NewHandler(&fakeRoomClient{}) diff --git a/services/gateway-service/internal/transport/http/room_handler.go b/services/gateway-service/internal/transport/http/room_handler.go index eca41c48..9b4ee339 100644 --- a/services/gateway-service/internal/transport/http/room_handler.go +++ b/services/gateway-service/internal/transport/http/room_handler.go @@ -8,6 +8,7 @@ import ( roomv1 "hyapp.local/api/proto/room/v1" userv1 "hyapp.local/api/proto/user/v1" "hyapp/pkg/appcode" + "hyapp/pkg/roomid" "hyapp/services/gateway-service/internal/auth" ) @@ -72,6 +73,78 @@ func parseRoomListLimit(raw string) (int32, bool) { return int32(value), true } +// getCurrentRoom 查询当前登录用户是否仍有可恢复房间。 +// gateway 只传鉴权 user_id;presence 和麦位状态由 room-service 用读模型和 Room Cell 快照判断。 +func (h *Handler) getCurrentRoom(writer http.ResponseWriter, request *http.Request) { + if h.roomQueryClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + + resp, err := h.roomQueryClient.GetCurrentRoom(request.Context(), &roomv1.GetCurrentRoomRequest{ + Meta: meta(request, "", ""), + UserId: auth.UserIDFromContext(request.Context()), + }) + if err != nil { + writeRPCError(writer, request, err) + return + } + writeOK(writer, request, currentRoomDataFromProto(resp)) +} + +// currentRoomData 是 gateway 的外部 JSON 契约,显式保留 false/0 字段。 +// 不能直接把 protobuf response 写出去,否则 proto3 的 omitempty 会让 has_current_room=false 消失。 +type currentRoomData struct { + HasCurrentRoom bool `json:"has_current_room"` + RoomID string `json:"room_id"` + RoomVersion int64 `json:"room_version"` + Role string `json:"role"` + MicSessionID string `json:"mic_session_id"` + PublishState string `json:"publish_state"` + NeedJoinIMGroup bool `json:"need_join_im_group"` + NeedRTCToken bool `json:"need_rtc_token"` + ServerTimeMS int64 `json:"server_time_ms"` +} + +func currentRoomDataFromProto(resp *roomv1.GetCurrentRoomResponse) currentRoomData { + if resp == nil { + return currentRoomData{} + } + + return currentRoomData{ + HasCurrentRoom: resp.GetHasCurrentRoom(), + RoomID: resp.GetRoomId(), + RoomVersion: resp.GetRoomVersion(), + Role: resp.GetRole(), + MicSessionID: resp.GetMicSessionId(), + PublishState: resp.GetPublishState(), + NeedJoinIMGroup: resp.GetNeedJoinImGroup(), + NeedRTCToken: resp.GetNeedRtcToken(), + ServerTimeMS: resp.GetServerTimeMs(), + } +} + +// getRoomSnapshot 主动拉取房间页完整快照。 +// 该接口只读 Room Cell/snapshot,不刷新 heartbeat,也不隐式 JoinRoom。 +func (h *Handler) getRoomSnapshot(writer http.ResponseWriter, request *http.Request) { + if h.roomQueryClient == nil { + writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") + return + } + roomID := strings.TrimSpace(request.URL.Query().Get("room_id")) + if !roomid.ValidStringID(roomID) { + writeError(writer, request, http.StatusBadRequest, codeInvalidArgument, "invalid argument") + return + } + + resp, err := h.roomQueryClient.GetRoomSnapshot(request.Context(), &roomv1.GetRoomSnapshotRequest{ + Meta: meta(request, roomID, ""), + RoomId: roomID, + ViewerUserId: auth.UserIDFromContext(request.Context()), + }) + write(writer, request, resp, err) +} + // createRoom 把创建房间 HTTP JSON 请求转换为 room-service CreateRoom 命令。 func (h *Handler) createRoom(writer http.ResponseWriter, request *http.Request) { var body struct { diff --git a/services/gateway-service/internal/transport/http/router.go b/services/gateway-service/internal/transport/http/router.go index e0639abd..3f455ed9 100644 --- a/services/gateway-service/internal/transport/http/router.go +++ b/services/gateway-service/internal/transport/http/router.go @@ -20,18 +20,22 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { mux.Handle(apiV1Prefix+"/auth/logout", h.publicAPIHandler(h.logout)) mux.Handle(apiV1Prefix+"/countries", h.publicAPIHandler(h.listRegistrationCountries)) + mux.Handle(apiV1Prefix+"/app/bootstrap", h.publicAPIHandler(h.getAppBootstrap)) mux.Handle(apiV1Prefix+"/app/h5-links", h.publicAPIHandler(h.listH5Links)) mux.Handle(apiV1Prefix+"/app/banners", h.publicAPIHandler(h.listAppBanners)) mux.Handle(apiV1Prefix+"/resources", h.publicAPIHandler(h.listResources)) mux.Handle(apiV1Prefix+"/resource-groups/", h.publicAPIHandler(h.getResourceGroup)) mux.Handle(apiV1Prefix+"/gifts", h.publicAPIHandler(h.listGifts)) - mux.Handle(apiV1Prefix+"/im/usersig", h.profileAPIHandler(jwtVerifier, h.issueTencentIMUserSig)) - mux.Handle(apiV1Prefix+"/rtc/token", h.profileAPIHandler(jwtVerifier, h.issueTencentRTCToken)) + mux.Handle(apiV1Prefix+"/im/usersig", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodGet, h.issueTencentIMUserSig))) + mux.Handle(apiV1Prefix+"/rtc/token", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.issueTencentRTCToken))) mux.Handle(apiV1Prefix+"/tencent-im/callback", h.publicAPIHandler(h.handleTencentIMCallback)) mux.Handle(apiV1Prefix+"/files/upload", h.apiHandler(jwtVerifier, h.uploadFile)) mux.Handle(apiV1Prefix+"/files/avatar/upload", h.apiHandler(jwtVerifier, h.uploadAvatar)) + mux.Handle(apiV1Prefix+"/devices/push-token", h.profileAPIHandler(jwtVerifier, h.handlePushToken)) mux.Handle(apiV1Prefix+"/users/by-display-user-id/", h.publicAPIHandler(h.resolveDisplayUserID)) + mux.Handle(apiV1Prefix+"/users/profiles:batch", h.profileAPIHandler(jwtVerifier, h.batchUserProfiles)) + mux.Handle(apiV1Prefix+"/users/me/overview", h.profileAPIHandler(jwtVerifier, h.getMyOverview)) mux.Handle(apiV1Prefix+"/users/me", h.profileAPIHandler(jwtVerifier, h.getMyProfile)) mux.Handle(apiV1Prefix+"/users/me/identity", h.apiHandler(jwtVerifier, h.getMyIdentity)) mux.Handle(apiV1Prefix+"/users/me/host-identity", h.profileAPIHandler(jwtVerifier, h.getMyHostIdentity)) @@ -43,24 +47,30 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { mux.Handle(apiV1Prefix+"/users/me/resources", h.profileAPIHandler(jwtVerifier, h.listMyResources)) mux.Handle(apiV1Prefix+"/users/me/resources/", h.profileAPIHandler(jwtVerifier, h.equipMyResource)) - mux.Handle(apiV1Prefix+"/rooms", h.profileAPIHandler(jwtVerifier, h.listRooms)) - mux.Handle(apiV1Prefix+"/rooms/create", h.profileAPIHandler(jwtVerifier, h.createRoom)) - mux.Handle(apiV1Prefix+"/rooms/join", h.profileAPIHandler(jwtVerifier, h.joinRoom)) - mux.Handle(apiV1Prefix+"/rooms/heartbeat", h.profileAPIHandler(jwtVerifier, h.roomHeartbeat)) - mux.Handle(apiV1Prefix+"/rooms/leave", h.profileAPIHandler(jwtVerifier, h.leaveRoom)) - mux.Handle(apiV1Prefix+"/rooms/mic/up", h.profileAPIHandler(jwtVerifier, h.micUp)) - mux.Handle(apiV1Prefix+"/rooms/mic/down", h.profileAPIHandler(jwtVerifier, h.micDown)) - mux.Handle(apiV1Prefix+"/rooms/mic/change", h.profileAPIHandler(jwtVerifier, h.changeMicSeat)) - mux.Handle(apiV1Prefix+"/rooms/mic/publishing/confirm", h.profileAPIHandler(jwtVerifier, h.confirmMicPublishing)) - mux.Handle(apiV1Prefix+"/rooms/mic/lock", h.profileAPIHandler(jwtVerifier, h.setMicSeatLock)) - mux.Handle(apiV1Prefix+"/rooms/chat/enabled", h.profileAPIHandler(jwtVerifier, h.setChatEnabled)) - mux.Handle(apiV1Prefix+"/rooms/admin/set", h.profileAPIHandler(jwtVerifier, h.setRoomAdmin)) - mux.Handle(apiV1Prefix+"/rooms/host/transfer", h.profileAPIHandler(jwtVerifier, h.transferRoomHost)) - mux.Handle(apiV1Prefix+"/rooms/user/mute", h.profileAPIHandler(jwtVerifier, h.muteUser)) - mux.Handle(apiV1Prefix+"/rooms/user/kick", h.profileAPIHandler(jwtVerifier, h.kickUser)) - mux.Handle(apiV1Prefix+"/rooms/user/unban", h.profileAPIHandler(jwtVerifier, h.unbanUser)) - mux.Handle(apiV1Prefix+"/rooms/gift/send", h.profileAPIHandler(jwtVerifier, h.sendGift)) + mux.Handle(apiV1Prefix+"/rooms", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodGet, h.listRooms))) + mux.Handle(apiV1Prefix+"/rooms/current", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodGet, h.getCurrentRoom))) + mux.Handle(apiV1Prefix+"/rooms/snapshot", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodGet, h.getRoomSnapshot))) + mux.Handle(apiV1Prefix+"/rooms/create", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.createRoom))) + mux.Handle(apiV1Prefix+"/rooms/join", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.joinRoom))) + mux.Handle(apiV1Prefix+"/rooms/heartbeat", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.roomHeartbeat))) + mux.Handle(apiV1Prefix+"/rooms/leave", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.leaveRoom))) + mux.Handle(apiV1Prefix+"/rooms/mic/up", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.micUp))) + mux.Handle(apiV1Prefix+"/rooms/mic/down", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.micDown))) + mux.Handle(apiV1Prefix+"/rooms/mic/change", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.changeMicSeat))) + mux.Handle(apiV1Prefix+"/rooms/mic/publishing/confirm", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.confirmMicPublishing))) + mux.Handle(apiV1Prefix+"/rooms/mic/lock", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.setMicSeatLock))) + mux.Handle(apiV1Prefix+"/rooms/chat/enabled", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.setChatEnabled))) + mux.Handle(apiV1Prefix+"/rooms/admin/set", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.setRoomAdmin))) + mux.Handle(apiV1Prefix+"/rooms/host/transfer", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.transferRoomHost))) + mux.Handle(apiV1Prefix+"/rooms/user/mute", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.muteUser))) + mux.Handle(apiV1Prefix+"/rooms/user/kick", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.kickUser))) + mux.Handle(apiV1Prefix+"/rooms/user/unban", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.unbanUser))) + mux.Handle(apiV1Prefix+"/rooms/gift/send", h.profileAPIHandler(jwtVerifier, requireMethod(http.MethodPost, h.sendGift))) mux.Handle(apiV1Prefix+"/tencent-rtc/callback", h.publicAPIHandler(h.handleTencentRTCCallback)) + mux.Handle(apiV1Prefix+"/messages/tabs", h.profileAPIHandler(jwtVerifier, h.listMessageTabs)) + mux.Handle(apiV1Prefix+"/messages/read-all", h.profileAPIHandler(jwtVerifier, h.markInboxSectionRead)) + mux.Handle(apiV1Prefix+"/messages/", h.profileAPIHandler(jwtVerifier, h.inboxMessageByID)) + mux.Handle(apiV1Prefix+"/messages", h.profileAPIHandler(jwtVerifier, h.listInboxMessages)) mux.Handle(apiV1Prefix+"/wallet/me/balances", h.profileAPIHandler(jwtVerifier, h.getMyBalances)) mux.Handle(apiV1Prefix+"/wallet/coin-seller/transfer", h.profileAPIHandler(jwtVerifier, h.transferCoinFromSeller)) 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 c965f5cd..c6e379bf 100644 --- a/services/room-service/deploy/mysql/initdb/001_room_service.sql +++ b/services/room-service/deploy/mysql/initdb/001_room_service.sql @@ -49,6 +49,22 @@ CREATE TABLE IF NOT EXISTS room_list_entries ( KEY idx_room_list_owner (app_code, owner_user_id, updated_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE IF NOT EXISTS room_user_presence ( + app_code VARCHAR(32) NOT NULL, + user_id BIGINT NOT NULL, + room_id VARCHAR(64) NOT NULL, + role VARCHAR(32) NOT NULL, + publish_state VARCHAR(32) NOT NULL DEFAULT '', + mic_session_id VARCHAR(128) NOT NULL DEFAULT '', + room_version BIGINT NOT NULL, + status VARCHAR(32) NOT NULL, + last_seen_at_ms BIGINT NOT NULL DEFAULT 0, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, user_id), + KEY idx_room_user_presence_room (app_code, room_id, status), + KEY idx_room_user_presence_updated (app_code, status, updated_at_ms) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CREATE TABLE IF NOT EXISTS room_snapshots ( app_code VARCHAR(32) NOT NULL, room_id VARCHAR(64) NOT NULL, diff --git a/services/room-service/internal/room/service/create_room.go b/services/room-service/internal/room/service/create_room.go index aadeaccc..f7a424e1 100644 --- a/services/room-service/internal/room/service/create_room.go +++ b/services/room-service/internal/room/service/create_room.go @@ -103,6 +103,8 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) if err != nil { return nil, err } + // CreateRoom 不经过 mutateRoom 管线,幂等重试也要补齐恢复读模型,避免旧请求成功但投影缺失。 + s.projectRoomPresenceBestEffort(ctx, snapshot) return &roomv1.CreateRoomResponse{ Result: commandResult(false, snapshot.GetVersion(), s.clock.Now()), @@ -211,6 +213,8 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) return nil, err } s.projectRoomListBestEffort(ctx, snapshot) + // owner 创建房间后已经是在线成员,必须立即投影到用户当前房间读模型。 + s.projectRoomPresenceBestEffort(ctx, snapshot) // 持久化成功后再安装内存 Cell,避免内存有房间但恢复来源不完整。 s.installCell(ctx, cmd.RoomID(), cell.New(roomState.Clone(), rank.FromState(roomState.GiftRank, s.rankLimit))) diff --git a/services/room-service/internal/room/service/current_room.go b/services/room-service/internal/room/service/current_room.go new file mode 100644 index 00000000..ff6b36d5 --- /dev/null +++ b/services/room-service/internal/room/service/current_room.go @@ -0,0 +1,152 @@ +package service + +import ( + "context" + "log" + + roomv1 "hyapp.local/api/proto/room/v1" + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + "hyapp/services/room-service/internal/room/state" +) + +const ( + roomPresenceStatusActive = "active" + roomPresenceStatusLeft = "left" +) + +// GetCurrentRoom 返回当前用户可恢复房间的只读探测结果。 +// 该方法先查用户级 presence 读模型,再用 Room Cell 快照二次校验,避免读模型滞后导致恢复已关闭或已踢出的房间。 +func (s *Service) GetCurrentRoom(ctx context.Context, req *roomv1.GetCurrentRoomRequest) (*roomv1.GetCurrentRoomResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + userID := req.GetUserId() + if userID <= 0 { + return nil, xerr.New(xerr.InvalidArgument, "user_id is required") + } + + serverTimeMS := s.clock.Now().UnixMilli() + presence, exists, err := s.repository.GetCurrentRoomPresence(ctx, userID) + if err != nil { + return nil, err + } + if !exists { + return emptyCurrentRoomResponse(serverTimeMS), nil + } + + snapshot, err := s.currentSnapshot(ctx, presence.RoomID) + if err != nil { + return nil, err + } + if !currentRoomSnapshotRestorable(snapshot, userID) { + // 查询语义必须保持只读;读模型滞后由后续命令投影或专项补偿修复。 + return emptyCurrentRoomResponse(serverTimeMS), nil + } + + roomUser := findProtoUser(snapshot, userID) + seat := protoSeatByUser(snapshot, userID) + role := presence.Role + if roomUser != nil { + role = roomUser.GetRole() + } + publishState := "" + micSessionID := "" + needRTCToken := false + if seat != nil { + publishState = seat.GetPublishState() + micSessionID = seat.GetMicSessionId() + needRTCToken = publishState == state.MicPublishPending || publishState == state.MicPublishPublishing + } + + return &roomv1.GetCurrentRoomResponse{ + HasCurrentRoom: true, + RoomId: snapshot.GetRoomId(), + RoomVersion: snapshot.GetVersion(), + Role: role, + MicSessionId: micSessionID, + PublishState: publishState, + NeedJoinImGroup: true, + NeedRtcToken: needRTCToken, + ServerTimeMs: serverTimeMS, + }, nil +} + +func emptyCurrentRoomResponse(serverTimeMS int64) *roomv1.GetCurrentRoomResponse { + return &roomv1.GetCurrentRoomResponse{ServerTimeMs: serverTimeMS} +} + +func currentRoomSnapshotRestorable(snapshot *roomv1.RoomSnapshot, userID int64) bool { + if snapshot == nil || snapshot.GetRoomId() == "" || snapshot.GetStatus() != state.RoomStatusActive { + return false + } + if containsUserID(snapshot.GetBanUserIds(), userID) { + return false + } + return findProtoUser(snapshot, userID) != nil +} + +// projectRoomPresenceBestEffort 用最新快照刷新“用户当前房间”读模型。 +// 读模型失败不能影响命令成功语义,但必须记录日志,避免恢复入口长期缺失无人感知。 +func (s *Service) projectRoomPresenceBestEffort(ctx context.Context, snapshot *roomv1.RoomSnapshot) { + projection := roomPresenceProjectionFromSnapshot(snapshot, s.clock.Now().UnixMilli()) + if projection.RoomID == "" { + return + } + if err := s.repository.ProjectRoomPresence(ctx, projection); err != nil { + log.Printf("component=room_presence_projector room_id=%s version=%d status=project_failed error=%q", projection.RoomID, projection.RoomVersion, err.Error()) + } +} + +func roomPresenceProjectionFromSnapshot(snapshot *roomv1.RoomSnapshot, updatedAtMS int64) RoomPresenceSnapshot { + if snapshot == nil || snapshot.GetRoomId() == "" { + return RoomPresenceSnapshot{} + } + + seatsByUser := make(map[int64]*roomv1.SeatState, len(snapshot.GetMicSeats())) + for _, seat := range snapshot.GetMicSeats() { + if seat.GetUserId() > 0 { + seatsByUser[seat.GetUserId()] = seat + } + } + + users := make([]RoomPresence, 0, len(snapshot.GetOnlineUsers())) + if snapshot.GetStatus() == state.RoomStatusActive { + for _, user := range snapshot.GetOnlineUsers() { + if user.GetUserId() <= 0 { + continue + } + entry := RoomPresence{ + AppCode: snapshot.GetAppCode(), + UserID: user.GetUserId(), + RoomID: snapshot.GetRoomId(), + Role: user.GetRole(), + RoomVersion: snapshot.GetVersion(), + Status: roomPresenceStatusActive, + LastSeenAtMS: user.GetLastSeenAtMs(), + UpdatedAtMS: updatedAtMS, + } + if seat := seatsByUser[user.GetUserId()]; seat != nil { + entry.PublishState = seat.GetPublishState() + entry.MicSessionID = seat.GetMicSessionId() + } + users = append(users, entry) + } + } + + return RoomPresenceSnapshot{ + AppCode: snapshot.GetAppCode(), + RoomID: snapshot.GetRoomId(), + RoomVersion: snapshot.GetVersion(), + RoomStatus: snapshot.GetStatus(), + Users: users, + UpdatedAtMS: updatedAtMS, + } +} + +func containsUserID(values []int64, target int64) bool { + for _, value := range values { + if value == target { + return true + } + } + return false +} diff --git a/services/room-service/internal/room/service/helpers.go b/services/room-service/internal/room/service/helpers.go index 4abfb4e0..7a9434c3 100644 --- a/services/room-service/internal/room/service/helpers.go +++ b/services/room-service/internal/room/service/helpers.go @@ -57,11 +57,13 @@ func runtimeRoomKeyFromContext(ctx context.Context, roomID string) string { } func (s *Service) loadedRoomLease(ctx context.Context, roomRef loadedRoomRef, now time.Time) (router.Lease, bool, error) { - lease, exists, err := s.directory.Lookup(ctx, runtimeRoomKey(roomRef.AppCode, roomRef.RoomID)) - if err != nil || !exists { + lease, err := s.directory.EnsureOwner(ctx, runtimeRoomKey(roomRef.AppCode, roomRef.RoomID), s.nodeID, now, s.leaseTTL) + if err != nil { return router.Lease{}, false, err } if lease.NodeID != s.nodeID || !lease.ValidAt(now) { + // 后台 worker 只处理自己仍然拥有或可安全续租的 Cell。 + // 如果其他节点已经接管并持有有效 lease,当前节点必须跳过,避免旧内存态覆盖新 owner。 return router.Lease{}, false, nil } diff --git a/services/room-service/internal/room/service/pipeline.go b/services/room-service/internal/room/service/pipeline.go index 008b72c0..b3f95949 100644 --- a/services/room-service/internal/room/service/pipeline.go +++ b/services/room-service/internal/room/service/pipeline.go @@ -133,6 +133,8 @@ func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayabl if result.applied { // 列表读模型最终一致,失败只记录日志,不回滚已经提交的 Room Cell 命令。 s.projectRoomListBestEffort(ctx, result.snapshot) + // 当前房间恢复读模型同样最终一致;权威校验仍以 Room Cell 快照为准。 + s.projectRoomPresenceBestEffort(ctx, result.snapshot) } if result.applied && result.syncEvent != nil { diff --git a/services/room-service/internal/room/service/repository.go b/services/room-service/internal/room/service/repository.go index 5ccaa9fe..2cfadce1 100644 --- a/services/room-service/internal/room/service/repository.go +++ b/services/room-service/internal/room/service/repository.go @@ -116,6 +116,31 @@ type RoomListEntry struct { UpdatedAtMS int64 } +// RoomPresence 是当前用户可恢复房间的轻量读模型。 +// 它从 RoomSnapshot 投影而来,只用于 App 启动/回前台探测,不替代 Room Cell 权威状态。 +type RoomPresence struct { + // AppCode 是 presence 所属 App,和 user_id 一起限定用户当前房间。 + AppCode string + // UserID 是业务 presence 所属用户。 + UserID int64 + // RoomID 是用户当前仍在的房间;status=left 时只保留排障参考。 + RoomID string + // Role 是房间内轻量角色,来自 RoomUser.role。 + Role string + // PublishState 是用户当前麦位发流状态,非上麦用户为空。 + PublishState string + // MicSessionID 是当前麦位发流会话,非上麦用户为空。 + MicSessionID string + // RoomVersion 是投影来自的房间版本。 + RoomVersion int64 + // Status 表示该用户 presence 是否仍 active。 + Status string + // LastSeenAtMS 是用户在 Room Cell 内的最后业务心跳时间。 + LastSeenAtMS int64 + // UpdatedAtMS 是投影写入时间。 + UpdatedAtMS int64 +} + // RoomListQuery 是 room-service 房间列表读模型查询条件。 type RoomListQuery struct { // AppCode 是列表查询所属 App,通常来自 gateway RequestMeta。 @@ -172,4 +197,18 @@ type Repository interface { UpsertRoomListEntry(ctx context.Context, entry RoomListEntry) error // ListRoomListEntries 按区域和 tab 查询房间列表,不访问 Room Cell 内存。 ListRoomListEntries(ctx context.Context, query RoomListQuery) ([]RoomListEntry, error) + // ProjectRoomPresence 用最新快照刷新用户当前房间读模型;失败不应破坏 Room Cell 已提交状态。 + ProjectRoomPresence(ctx context.Context, snapshot RoomPresenceSnapshot) error + // GetCurrentRoomPresence 查询用户当前 active 房间 presence,不扫描房间列表或快照。 + GetCurrentRoomPresence(ctx context.Context, userID int64) (RoomPresence, bool, error) +} + +// RoomPresenceSnapshot 是 repository 投影接口的稳定入参,避免存储层反向依赖 protobuf。 +type RoomPresenceSnapshot struct { + AppCode string + RoomID string + RoomVersion int64 + RoomStatus string + Users []RoomPresence + UpdatedAtMS int64 } diff --git a/services/room-service/internal/room/service/rtc_event.go b/services/room-service/internal/room/service/rtc_event.go index 897d6996..59f159f4 100644 --- a/services/room-service/internal/room/service/rtc_event.go +++ b/services/room-service/internal/room/service/rtc_event.go @@ -189,50 +189,18 @@ func (s *Service) applyRTCAudioStopped(now time.Time, current *state.RoomState, func (s *Service) applyRTCRoomExited(now time.Time, current *state.RoomState, cmd command.ApplyRTCEvent) (mutationResult, []outbox.Record, error) { if user, exists := current.OnlineUsers[cmd.TargetUserID]; exists && user.LastSeenAtMS > cmd.EventTimeMS { - // 腾讯可能重试或延迟投递旧退房事件;如果业务 presence 已被更新到事件之后,保留当前重连状态。 + // 腾讯可能重试或延迟投递旧退房事件;如果业务 presence 已被更新到事件之后,保留当前重连和麦位状态。 return mutationResult{snapshot: current.ToProto()}, nil, nil } - _, inRoom := current.OnlineUsers[cmd.TargetUserID] - seat, onSeat := current.SeatByUser(cmd.TargetUserID) - if onSeat && !rtcStopEventMatchesCurrentMicSession(seat, cmd.EventTimeMS, s.micPublishTimeout) { - return mutationResult{snapshot: current.ToProto(), seatNo: seat.SeatNo}, nil, nil - } - if !inRoom && !onSeat { + _, onSeat := current.SeatByUser(cmd.TargetUserID) + if !onSeat { + // RTC 退房只代表媒体频道状态,不拥有 room-service 业务 presence。 return mutationResult{snapshot: current.ToProto()}, nil, nil } - delete(current.OnlineUsers, cmd.TargetUserID) - if onSeat { - index := current.SeatIndex(seat.SeatNo) - current.ClearMicSession(index) - } - current.Version++ - - leftEvent, err := outbox.Build(current.RoomID, "RoomUserLeft", current.Version, now, &roomeventsv1.RoomUserLeft{ - UserId: cmd.TargetUserID, - }) - if err != nil { - return mutationResult{}, nil, err - } - - return mutationResult{ - snapshot: current.ToProto(), - seatNo: seat.SeatNo, - syncEvent: &tencentim.RoomEvent{ - EventID: leftEvent.EventID, - RoomID: current.RoomID, - EventType: "room_user_left", - ActorUserID: cmd.ActorUserID(), - TargetUserID: cmd.TargetUserID, - RoomVersion: current.Version, - Attributes: map[string]string{ - "reason": cmd.Reason, - "source": cmd.Source, - "external_event_id": cmd.ExternalEventID, - }, - }, - }, []outbox.Record{leftEvent}, nil + // 用户仍可能停留在房间页继续重连;这里只释放当前 mic_session,业务离房只能由 LeaveRoom、kick、close 或 stale worker 触发。 + return s.applyRTCAudioStopped(now, current, cmd) } func rtcEventMatchesCurrentMicSession(seat state.MicSeat, eventTimeMS int64, timeout time.Duration) bool { diff --git a/services/room-service/internal/room/service/service_test.go b/services/room-service/internal/room/service/service_test.go index 98ae9d4c..a986b371 100644 --- a/services/room-service/internal/room/service/service_test.go +++ b/services/room-service/internal/room/service/service_test.go @@ -332,6 +332,144 @@ func TestRoomListUsesRegionReadModelAndProjectionUpdates(t *testing.T) { } } +func TestGetCurrentRoomReturnsRecoverablePresence(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + svc := newRoomService("node-a", 1, router.NewMemoryDirectory(), repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}) + roomID := "room-current-presence" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ + Meta: roomservice.NewRequestMeta(roomID, 1), + SeatCount: 4, + Mode: "voice", + RoomName: "Current Room", + }); err != nil { + t.Fatalf("CreateRoom failed: %v", err) + } + if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("JoinRoom failed: %v", err) + } + micResp, err := svc.MicUp(ctx, &roomv1.MicUpRequest{Meta: roomservice.NewRequestMeta(roomID, 2), SeatNo: 1}) + if err != nil { + t.Fatalf("MicUp failed: %v", err) + } + + current, err := svc.GetCurrentRoom(ctx, &roomv1.GetCurrentRoomRequest{ + Meta: &roomv1.RequestMeta{AppCode: appcode.Default}, + UserId: 2, + }) + if err != nil { + t.Fatalf("GetCurrentRoom failed: %v", err) + } + if !current.GetHasCurrentRoom() || current.GetRoomId() != roomID || current.GetRole() != "audience" { + t.Fatalf("current room response mismatch: %+v", current) + } + if current.GetPublishState() != "pending_publish" || current.GetMicSessionId() != micResp.GetMicSessionId() || !current.GetNeedRtcToken() || !current.GetNeedJoinImGroup() { + t.Fatalf("current mic restore fields mismatch: %+v", current) + } +} + +func TestGetCurrentRoomReturnsOwnerAfterCreate(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + svc := newRoomService("node-a", 1, router.NewMemoryDirectory(), repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}) + roomID := "room-current-owner-after-create" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ + Meta: roomservice.NewRequestMeta(roomID, 1), + SeatCount: 4, + Mode: "voice", + RoomName: "Current Room", + }); err != nil { + t.Fatalf("CreateRoom failed: %v", err) + } + + current, err := svc.GetCurrentRoom(ctx, &roomv1.GetCurrentRoomRequest{ + Meta: &roomv1.RequestMeta{AppCode: appcode.Default}, + UserId: 1, + }) + if err != nil { + t.Fatalf("GetCurrentRoom failed: %v", err) + } + if !current.GetHasCurrentRoom() || current.GetRoomId() != roomID || current.GetRole() != "owner" || !current.GetNeedJoinImGroup() { + t.Fatalf("owner should recover room immediately after CreateRoom: %+v", current) + } + if current.GetNeedRtcToken() || current.GetPublishState() != "" || current.GetMicSessionId() != "" { + t.Fatalf("owner not on mic should not require RTC restore: %+v", current) + } +} + +func TestGetCurrentRoomReturnsEmptyAfterLeave(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + svc := newRoomService("node-a", 1, router.NewMemoryDirectory(), repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}) + roomID := "room-current-left" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ + Meta: roomservice.NewRequestMeta(roomID, 1), + SeatCount: 4, + Mode: "voice", + RoomName: "Current Room", + }); err != nil { + t.Fatalf("CreateRoom failed: %v", err) + } + if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("JoinRoom failed: %v", err) + } + if _, err := svc.LeaveRoom(ctx, &roomv1.LeaveRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("LeaveRoom failed: %v", err) + } + + current, err := svc.GetCurrentRoom(ctx, &roomv1.GetCurrentRoomRequest{ + Meta: &roomv1.RequestMeta{AppCode: appcode.Default}, + UserId: 2, + }) + if err != nil { + t.Fatalf("GetCurrentRoom failed: %v", err) + } + if current.GetHasCurrentRoom() || current.GetRoomId() != "" { + t.Fatalf("left user should not have current room: %+v", current) + } +} + +func TestGetRoomSnapshotRequiresViewerPresence(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + svc := newRoomService("node-a", 1, router.NewMemoryDirectory(), repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}) + roomID := "room-snapshot-read" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ + Meta: roomservice.NewRequestMeta(roomID, 1), + SeatCount: 4, + Mode: "voice", + RoomName: "Snapshot Room", + }); err != nil { + t.Fatalf("CreateRoom failed: %v", err) + } + if _, err := svc.GetRoomSnapshot(ctx, &roomv1.GetRoomSnapshotRequest{ + Meta: &roomv1.RequestMeta{AppCode: appcode.Default}, + RoomId: roomID, + ViewerUserId: 2, + }); !xerr.IsCode(err, xerr.PermissionDenied) { + t.Fatalf("non-presence viewer should not read full snapshot, got %v", err) + } + if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("JoinRoom failed: %v", err) + } + + resp, err := svc.GetRoomSnapshot(ctx, &roomv1.GetRoomSnapshotRequest{ + Meta: &roomv1.RequestMeta{AppCode: appcode.Default}, + RoomId: roomID, + ViewerUserId: 2, + }) + if err != nil { + t.Fatalf("GetRoomSnapshot failed: %v", err) + } + if resp.GetRoom().GetRoomId() != roomID || resp.GetRoom().GetVersion() == 0 || findRoomUser(resp.GetRoom(), 2) == nil { + t.Fatalf("snapshot response mismatch: %+v", resp.GetRoom()) + } +} + func TestCreateRoomRejectsInvalidRoomID(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) @@ -648,7 +786,7 @@ func TestAudienceCanChangeOwnMicSeat(t *testing.T) { } } -func TestApplyRTCEventConfirmsAudioAndClearsOnStopOrExit(t *testing.T) { +func TestApplyRTCEventConfirmsAudioAndClearsMicOnStopOrExit(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) usedClock := &mutableClock{now: time.UnixMilli(1_700_000_000_000)} @@ -716,14 +854,14 @@ func TestApplyRTCEventConfirmsAudioAndClearsOnStopOrExit(t *testing.T) { if err != nil { t.Fatalf("ApplyRTCEvent room_exited failed: %v", err) } - if user := findRoomUser(exitResp.GetRoom(), 3); user != nil { - t.Fatalf("RTC room_exited should remove business presence: user=%+v", user) + if user := findRoomUser(exitResp.GetRoom(), 3); user == nil { + t.Fatalf("RTC room_exited must not remove business presence") } if seat := findSeat(exitResp.GetRoom(), 2); seat == nil || seat.GetUserId() != 0 { t.Fatalf("RTC room_exited should release occupied mic: seat=%+v", seat) } - if len(syncPublisher.events) == 0 || syncPublisher.events[len(syncPublisher.events)-1].EventType != "room_user_left" { - t.Fatalf("RTC room_exited should publish room_user_left: %+v", syncPublisher.events) + if len(syncPublisher.events) == 0 || syncPublisher.events[len(syncPublisher.events)-1].EventType != "room_mic_down" { + t.Fatalf("RTC room_exited should publish room_mic_down: %+v", syncPublisher.events) } } @@ -790,8 +928,9 @@ func TestMicPublishTimeoutMicDownsPendingSession(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) usedClock := &mutableClock{now: time.UnixMilli(1_700_000_000_000)} + directory := router.NewMemoryDirectory() syncPublisher := &fakeSyncPublisher{} - svc := newRoomServiceWithClock("node-a", 1, router.NewMemoryDirectory(), repository, syncPublisher, &fakeOutboxPublisher{}, usedClock, time.Minute) + svc := newRoomServiceWithClock("node-a", 1, directory, repository, syncPublisher, &fakeOutboxPublisher{}, usedClock, time.Minute) roomID := "room-mic-publish-timeout" if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 1), SeatCount: 4, Mode: "voice", RoomName: "Test Room"}); err != nil { @@ -805,9 +944,8 @@ func TestMicPublishTimeoutMicDownsPendingSession(t *testing.T) { t.Fatalf("MicUp failed: %v", err) } usedClock.now = time.UnixMilli(micResp.GetPublishDeadlineMs()) - if _, err := svc.RoomHeartbeat(ctx, &roomv1.RoomHeartbeatRequest{Meta: roomservice.NewRequestMeta(roomID, 1)}); err != nil { - t.Fatalf("RoomHeartbeat owner before mic timeout sweep failed: %v", err) - } + // 真实配置里 lease_ttl 可能短于 publish timeout;worker 必须能在无其他 owner 时续租并执行超时下麦。 + directory.ForceExpire(roomRouteKeyForTest(roomID)) if err := svc.SweepMicPublishTimeouts(ctx); err != nil { t.Fatalf("SweepMicPublishTimeouts failed: %v", err) } diff --git a/services/room-service/internal/room/service/snapshot_query.go b/services/room-service/internal/room/service/snapshot_query.go new file mode 100644 index 00000000..a098b040 --- /dev/null +++ b/services/room-service/internal/room/service/snapshot_query.go @@ -0,0 +1,55 @@ +package service + +import ( + "context" + + roomv1 "hyapp.local/api/proto/room/v1" + "hyapp/pkg/appcode" + "hyapp/pkg/roomid" + "hyapp/pkg/xerr" + "hyapp/services/room-service/internal/room/state" +) + +// GetRoomSnapshot 返回房间页主动同步所需的完整 Room Cell 快照。 +// 该查询只读,不刷新 presence、不写 command log,也不隐式 JoinRoom。 +func (s *Service) GetRoomSnapshot(ctx context.Context, req *roomv1.GetRoomSnapshotRequest) (*roomv1.GetRoomSnapshotResponse, error) { + ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) + roomID := req.GetRoomId() + viewerUserID := req.GetViewerUserId() + if !roomid.ValidStringID(roomID) { + // 快照查询同样受腾讯 IM GroupID 和 RTC strRoomId 格式约束,避免脏 room_id 进入恢复路径。 + return nil, xerr.New(xerr.InvalidArgument, "room_id is invalid") + } + if viewerUserID <= 0 { + // viewer_user_id 必须来自 gateway 鉴权,room-service 不接受匿名读取完整 presence。 + return nil, xerr.New(xerr.InvalidArgument, "viewer_user_id is required") + } + + closed, err := s.isRoomClosed(ctx, roomID) + if err != nil { + return nil, err + } + if closed { + return nil, xerr.New(xerr.RoomClosed, "room closed") + } + + snapshot, err := s.currentSnapshot(ctx, roomID) + if err != nil { + return nil, err + } + if snapshot == nil || snapshot.GetRoomId() == "" { + return nil, xerr.New(xerr.NotFound, "room not found") + } + if snapshot.GetStatus() != state.RoomStatusActive { + return nil, xerr.New(xerr.RoomClosed, "room closed") + } + if containsUserID(snapshot.GetBanUserIds(), viewerUserID) || findProtoUser(snapshot, viewerUserID) == nil { + // 完整快照包含在线用户、麦位和房管集合,必须要求 viewer 仍在业务 presence 内。 + return nil, xerr.New(xerr.PermissionDenied, "viewer is not in room") + } + + return &roomv1.GetRoomSnapshotResponse{ + Room: snapshot, + ServerTimeMs: s.clock.Now().UnixMilli(), + }, nil +} diff --git a/services/room-service/internal/storage/mysql/repository.go b/services/room-service/internal/storage/mysql/repository.go index 36c31230..e24d1c26 100644 --- a/services/room-service/internal/storage/mysql/repository.go +++ b/services/room-service/internal/storage/mysql/repository.go @@ -110,6 +110,21 @@ func (r *Repository) Migrate(ctx context.Context) error { KEY idx_room_list_region_new (app_code, visible_region_id, status, created_at_ms DESC, room_id), KEY idx_room_list_owner (app_code, owner_user_id, updated_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`, + `CREATE TABLE IF NOT EXISTS room_user_presence ( + app_code VARCHAR(32) NOT NULL, + user_id BIGINT NOT NULL, + room_id VARCHAR(64) NOT NULL, + role VARCHAR(32) NOT NULL, + publish_state VARCHAR(32) NOT NULL DEFAULT '', + mic_session_id VARCHAR(128) NOT NULL DEFAULT '', + room_version BIGINT NOT NULL, + status VARCHAR(32) NOT NULL, + last_seen_at_ms BIGINT NOT NULL DEFAULT 0, + updated_at_ms BIGINT NOT NULL, + PRIMARY KEY (app_code, user_id), + KEY idx_room_user_presence_room (app_code, room_id, status), + KEY idx_room_user_presence_updated (app_code, status, updated_at_ms) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`, `CREATE TABLE IF NOT EXISTS room_snapshots ( app_code VARCHAR(32) NOT NULL, room_id VARCHAR(64) NOT NULL, @@ -154,6 +169,7 @@ func (r *Repository) Migrate(ctx context.Context) error { ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`, `ALTER TABLE rooms MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, `ALTER TABLE room_list_entries MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, + `ALTER TABLE room_user_presence MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, `ALTER TABLE room_snapshots MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, `ALTER TABLE room_command_log MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, `ALTER TABLE room_outbox MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, @@ -819,6 +835,110 @@ func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) { return roomListSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY sort_score DESC, room_id ASC\n\tLIMIT ?", args } +// ProjectRoomPresence 用最新 RoomSnapshot 投影用户当前房间读模型。 +func (r *Repository) ProjectRoomPresence(ctx context.Context, snapshot roomservice.RoomPresenceSnapshot) error { + appCode := normalizedRecordAppCode(ctx, snapshot.AppCode) + if strings.TrimSpace(snapshot.RoomID) == "" { + return nil + } + + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return err + } + + // 先把该房间上一版 active presence 全部置为 left,再把本次快照里的在线用户 upsert 回 active。 + // 这样 Join/Leave/Kick/Close 的投影逻辑统一,避免按命令类型维护多份分支。 + if _, err := tx.ExecContext(ctx, + `UPDATE room_user_presence + SET status = ?, publish_state = '', mic_session_id = '', room_version = ?, updated_at_ms = ? + WHERE app_code = ? AND room_id = ? AND status = ?`, + roomPresenceStatusLeftSQL, + snapshot.RoomVersion, + snapshot.UpdatedAtMS, + appCode, + snapshot.RoomID, + roomPresenceStatusActiveSQL, + ); err != nil { + _ = tx.Rollback() + return err + } + + for _, user := range snapshot.Users { + if user.UserID <= 0 { + continue + } + if _, err := tx.ExecContext(ctx, + `INSERT INTO room_user_presence ( + app_code, user_id, room_id, role, publish_state, mic_session_id, room_version, status, last_seen_at_ms, updated_at_ms + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + room_id = VALUES(room_id), + role = VALUES(role), + publish_state = VALUES(publish_state), + mic_session_id = VALUES(mic_session_id), + room_version = VALUES(room_version), + status = VALUES(status), + last_seen_at_ms = VALUES(last_seen_at_ms), + updated_at_ms = VALUES(updated_at_ms)`, + appCode, + user.UserID, + snapshot.RoomID, + user.Role, + user.PublishState, + user.MicSessionID, + snapshot.RoomVersion, + roomPresenceStatusActiveSQL, + user.LastSeenAtMS, + snapshot.UpdatedAtMS, + ); err != nil { + _ = tx.Rollback() + return err + } + } + + return tx.Commit() +} + +// GetCurrentRoomPresence 查询用户当前 active 房间,不扫描发现页列表。 +func (r *Repository) GetCurrentRoomPresence(ctx context.Context, userID int64) (roomservice.RoomPresence, bool, error) { + row := r.db.QueryRowContext(ctx, + `SELECT app_code, user_id, room_id, role, publish_state, mic_session_id, room_version, status, last_seen_at_ms, updated_at_ms + FROM room_user_presence + WHERE app_code = ? AND user_id = ? AND status = ? + LIMIT 1`, + appcode.FromContext(ctx), + userID, + roomPresenceStatusActiveSQL, + ) + + var presence roomservice.RoomPresence + if err := row.Scan( + &presence.AppCode, + &presence.UserID, + &presence.RoomID, + &presence.Role, + &presence.PublishState, + &presence.MicSessionID, + &presence.RoomVersion, + &presence.Status, + &presence.LastSeenAtMS, + &presence.UpdatedAtMS, + ); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return roomservice.RoomPresence{}, false, nil + } + return roomservice.RoomPresence{}, false, err + } + + return presence, true, nil +} + +const ( + roomPresenceStatusActiveSQL = "active" + roomPresenceStatusLeftSQL = "left" +) + func escapeRoomListLike(value string) string { var builder strings.Builder for _, r := range value { diff --git a/services/room-service/internal/transport/grpc/server.go b/services/room-service/internal/transport/grpc/server.go index 998ceba1..50170640 100644 --- a/services/room-service/internal/transport/grpc/server.go +++ b/services/room-service/internal/transport/grpc/server.go @@ -187,6 +187,20 @@ func (s *Server) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (* return mapServiceResult(s.svc.ListRooms(ctx, req)) } +// GetCurrentRoom 代理到用户当前房间恢复探测读模型。 +func (s *Server) GetCurrentRoom(ctx context.Context, req *roomv1.GetCurrentRoomRequest) (*roomv1.GetCurrentRoomResponse, error) { + // 恢复探测不修改 Room Cell,只在读模型命中后用快照做二次校验。 + ctx = contextWithMetaApp(ctx, req.GetMeta()) + return mapServiceResult(s.svc.GetCurrentRoom(ctx, req)) +} + +// GetRoomSnapshot 代理到房间页完整快照只读查询。 +func (s *Server) GetRoomSnapshot(ctx context.Context, req *roomv1.GetRoomSnapshotRequest) (*roomv1.GetRoomSnapshotResponse, error) { + // 快照查询不刷新 presence,不替代 heartbeat,也不能让未进房用户读取完整房间态。 + ctx = contextWithMetaApp(ctx, req.GetMeta()) + return mapServiceResult(s.svc.GetRoomSnapshot(ctx, req)) +} + func contextWithMetaApp(ctx context.Context, meta *roomv1.RequestMeta) context.Context { if meta == nil { return appcode.WithContext(ctx, "") 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 151283f9..f870a01b 100644 --- a/services/user-service/deploy/mysql/initdb/001_user_service.sql +++ b/services/user-service/deploy/mysql/initdb/001_user_service.sql @@ -170,6 +170,26 @@ CREATE TABLE IF NOT EXISTS user_region_rebuild_tasks ( KEY idx_user_region_rebuild_tasks_lock (app_code, status, locked_until_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE IF NOT EXISTS user_push_tokens ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + user_id BIGINT NOT NULL, + device_id VARCHAR(128) NOT NULL, + push_token VARCHAR(512) NOT NULL, + provider VARCHAR(32) NOT NULL, + platform VARCHAR(16) NOT NULL, + app_version VARCHAR(64) NOT NULL DEFAULT '', + language VARCHAR(32) NOT NULL DEFAULT '', + timezone VARCHAR(64) NOT NULL DEFAULT '', + status VARCHAR(32) NOT NULL, + bound_at_ms BIGINT NOT NULL, + updated_at_ms BIGINT NOT NULL, + last_request_id VARCHAR(96) NOT NULL DEFAULT '', + PRIMARY KEY (app_code, user_id, device_id), + UNIQUE KEY uk_user_push_tokens_token (app_code, provider, push_token), + KEY idx_user_push_tokens_user_status (app_code, user_id, status), + KEY idx_user_push_tokens_updated (app_code, status, updated_at_ms) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CREATE TABLE IF NOT EXISTS host_profiles ( app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', user_id BIGINT NOT NULL PRIMARY KEY, diff --git a/services/user-service/internal/app/app.go b/services/user-service/internal/app/app.go index 17966081..f9310275 100644 --- a/services/user-service/internal/app/app.go +++ b/services/user-service/internal/app/app.go @@ -81,6 +81,7 @@ func New(cfg config.Config) (*App, error) { userRepo := mysqlRepo.UserRepository() identityRepo := mysqlRepo.IdentityRepository() regionRepo := mysqlRepo.RegionRepository() + deviceRepo := mysqlRepo.DeviceRepository() hostRepo := mysqlRepo.HostRepository() // auth service 负责登录、session 和 token;用户主数据和短号事务仍通过各自领域存储完成。 @@ -107,6 +108,7 @@ func New(cfg config.Config) (*App, error) { userservice.WithCountryAdminRepository(regionRepo), userservice.WithRegionAdminRepository(regionRepo), userservice.WithRegionRebuildRepository(regionRepo), + userservice.WithDeviceRepository(deviceRepo), userservice.WithIDGenerator(idgen.NewInt64Generator(cfg.IDGenerator.NodeID)), userservice.WithDisplayUserIDPolicy(cfg.DisplayUserID.AllocateMaxAttempts, time.Duration(cfg.DisplayUserID.ChangeCooldownSec)*time.Second), ) @@ -117,6 +119,7 @@ func New(cfg config.Config) (*App, error) { // 多个 protobuf service 共用一个 Server 适配器,领域逻辑仍拆在 auth/user/host service。 userv1.RegisterAuthServiceServer(server, userServer) userv1.RegisterUserServiceServer(server, userServer) + userv1.RegisterUserDeviceServiceServer(server, userServer) userv1.RegisterAppRegistryServiceServer(server, userServer) userv1.RegisterUserIdentityServiceServer(server, userServer) userv1.RegisterCountryAdminServiceServer(server, userServer) diff --git a/services/user-service/internal/domain/user/target_query.go b/services/user-service/internal/domain/user/target_query.go new file mode 100644 index 00000000..142b34f2 --- /dev/null +++ b/services/user-service/internal/domain/user/target_query.go @@ -0,0 +1,19 @@ +package user + +const ( + // UserIDTargetAllActive supports low-frequency full-App jobs without exposing profile fields. + UserIDTargetAllActiveUsers = "all_active_users" + // UserIDTargetRegion selects active users by their materialized region_id snapshot. + UserIDTargetRegion = "region" + // UserIDTargetCountry selects active users by their current country code snapshot. + UserIDTargetCountry = "country" +) + +// UserIDPageFilter is the minimal user-service target query used by async fanout jobs. +type UserIDPageFilter struct { + TargetScope string + CursorUserID int64 + PageSize int + RegionID int64 + Country string +} diff --git a/services/user-service/internal/domain/user/user.go b/services/user-service/internal/domain/user/user.go index ccd0a416..f8a9a8aa 100644 --- a/services/user-service/internal/domain/user/user.go +++ b/services/user-service/internal/domain/user/user.go @@ -267,6 +267,52 @@ type CountryChangeLog struct { ChangedAtMs int64 } +// PushTokenStatus 表达用户设备推送 token 是否仍可用于离线触达。 +type PushTokenStatus string + +const ( + // PushTokenStatusActive 表示该 token 当前可用于系统/活动消息离线推送。 + PushTokenStatusActive PushTokenStatus = "active" + // PushTokenStatusInactive 表示该 token 已被用户登出、关闭通知或重新绑定替换。 + PushTokenStatusInactive PushTokenStatus = "inactive" +) + +// PushTokenCommand 描述一次设备 push token 绑定。 +type PushTokenCommand struct { + // AppCode 是 token 所属 App,避免不同包之间串推送。 + AppCode string + // UserID 是当前登录用户,必须由 gateway 鉴权后传入。 + UserID int64 + // DeviceID 是 App 安装级稳定 ID。 + DeviceID string + // PushToken 是系统推送服务返回的 token。 + PushToken string + // Provider 是推送提供方,例如 fcm 或 apns。 + Provider string + // Platform 是客户端平台,当前只接受 android/ios。 + Platform string + // AppVersion 是上报 token 时的 App 版本快照。 + AppVersion string + // Language 是用户当前客户端语言偏好。 + Language string + // Timezone 是用户当前 IANA 时区。 + Timezone string + // RequestID 是入口请求 ID,便于排查重复绑定。 + RequestID string + // UpdatedAtMs 是绑定事务时间。 + UpdatedAtMs int64 +} + +// DeletePushTokenCommand 描述一次设备 push token 失效。 +type DeletePushTokenCommand struct { + AppCode string + UserID int64 + DeviceID string + PushToken string + RequestID string + UpdatedAtMs int64 +} + // PrettyDisplayUserIDLease 是临时靓号覆盖关系的事实记录。 type PrettyDisplayUserIDLease struct { // AppCode 是租约所属 App。 diff --git a/services/user-service/internal/service/auth/service_test.go b/services/user-service/internal/service/auth/service_test.go index 7631a3be..b7d538a1 100644 --- a/services/user-service/internal/service/auth/service_test.go +++ b/services/user-service/internal/service/auth/service_test.go @@ -53,6 +53,7 @@ func newUserService(repository *mysqltest.Repository, options ...userservice.Opt userservice.WithCountryAdminRepository(repository), userservice.WithRegionAdminRepository(repository), userservice.WithRegionRebuildRepository(repository), + userservice.WithDeviceRepository(repository), } return userservice.New(repository, append(base, options...)...) } diff --git a/services/user-service/internal/service/user/device.go b/services/user-service/internal/service/user/device.go new file mode 100644 index 00000000..3e3d9123 --- /dev/null +++ b/services/user-service/internal/service/user/device.go @@ -0,0 +1,147 @@ +package user + +import ( + "context" + "strings" + + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + userdomain "hyapp/services/user-service/internal/domain/user" +) + +const ( + maxPushDeviceIDLen = 128 + maxPushTokenLen = 512 + maxPushProviderLen = 32 + maxPushPlatformLen = 16 + maxPushAppVersionLen = 64 + maxPushLanguageLen = 32 + maxPushTimezoneLen = 64 +) + +// BindPushToken 绑定当前登录用户的系统推送 token。 +// 该能力不影响 App 进入主界面;失败只影响离线消息触达。 +func (s *Service) BindPushToken(ctx context.Context, userID int64, deviceID string, pushToken string, provider string, platform string, appVersion string, language string, timezone string, requestID string) (int64, error) { + if s.deviceRepository == nil { + return 0, xerr.New(xerr.Unavailable, "device repository is not configured") + } + if err := s.requireActiveCompletedUser(ctx, userID); err != nil { + return 0, err + } + + command, err := normalizePushTokenCommand(ctx, userID, deviceID, pushToken, provider, platform, appVersion, language, timezone, requestID, s.now().UnixMilli()) + if err != nil { + return 0, err + } + if err := s.deviceRepository.BindPushToken(ctx, command); err != nil { + return 0, err + } + + return command.UpdatedAtMs, nil +} + +// DeletePushToken 失效当前登录用户某个设备的推送 token。 +func (s *Service) DeletePushToken(ctx context.Context, userID int64, deviceID string, pushToken string, requestID string) (bool, int64, error) { + if s.deviceRepository == nil { + return false, 0, xerr.New(xerr.Unavailable, "device repository is not configured") + } + if userID <= 0 { + return false, 0, xerr.New(xerr.InvalidArgument, "user_id is required") + } + + deviceID = strings.TrimSpace(deviceID) + pushToken = strings.TrimSpace(pushToken) + if deviceID == "" || len(deviceID) > maxPushDeviceIDLen { + return false, 0, xerr.New(xerr.InvalidArgument, "device_id is invalid") + } + if len(pushToken) > maxPushTokenLen { + return false, 0, xerr.New(xerr.InvalidArgument, "push_token is invalid") + } + + nowMs := s.now().UnixMilli() + deleted, err := s.deviceRepository.DeletePushToken(ctx, userdomain.DeletePushTokenCommand{ + AppCode: appcode.FromContext(ctx), + UserID: userID, + DeviceID: deviceID, + PushToken: pushToken, + RequestID: strings.TrimSpace(requestID), + UpdatedAtMs: nowMs, + }) + if err != nil { + return false, 0, err + } + + return deleted, nowMs, nil +} + +func (s *Service) requireActiveCompletedUser(ctx context.Context, userID int64) error { + if userID <= 0 { + return xerr.New(xerr.InvalidArgument, "user_id is required") + } + user, err := s.GetUser(ctx, userID) + if err != nil { + return err + } + if !user.ProfileCompleted { + return xerr.New(xerr.ProfileRequired, "profile required") + } + if user.Status != userdomain.StatusActive { + return xerr.New(xerr.UserDisabled, "user disabled") + } + return nil +} + +func normalizePushTokenCommand(ctx context.Context, userID int64, deviceID string, pushToken string, provider string, platform string, appVersion string, language string, timezone string, requestID string, nowMs int64) (userdomain.PushTokenCommand, error) { + deviceID = strings.TrimSpace(deviceID) + pushToken = strings.TrimSpace(pushToken) + platform = strings.ToLower(strings.TrimSpace(platform)) + provider = strings.ToLower(strings.TrimSpace(provider)) + if provider == "" { + provider = defaultPushProvider(platform) + } + + if deviceID == "" || len(deviceID) > maxPushDeviceIDLen { + return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "device_id is invalid") + } + if pushToken == "" || len(pushToken) > maxPushTokenLen { + return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "push_token is invalid") + } + if provider == "" || len(provider) > maxPushProviderLen { + return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "provider is invalid") + } + if platform != "android" && platform != "ios" { + return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "platform is invalid") + } + + appVersion = strings.TrimSpace(appVersion) + language = strings.TrimSpace(language) + timezone = strings.TrimSpace(timezone) + if len(appVersion) > maxPushAppVersionLen || len(language) > maxPushLanguageLen || len(timezone) > maxPushTimezoneLen { + return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "push token metadata is invalid") + } + + return userdomain.PushTokenCommand{ + AppCode: appcode.FromContext(ctx), + UserID: userID, + DeviceID: deviceID, + PushToken: pushToken, + Provider: provider, + Platform: platform, + AppVersion: appVersion, + Language: language, + Timezone: timezone, + RequestID: strings.TrimSpace(requestID), + UpdatedAtMs: nowMs, + }, nil +} + +func defaultPushProvider(platform string) string { + switch platform { + case "android": + return "fcm" + case "ios": + return "apns" + default: + return "" + } +} diff --git a/services/user-service/internal/service/user/service.go b/services/user-service/internal/service/user/service.go index fe5add47..3edc83bf 100644 --- a/services/user-service/internal/service/user/service.go +++ b/services/user-service/internal/service/user/service.go @@ -16,6 +16,8 @@ type UserRepository interface { GetUser(ctx context.Context, userID int64) (userdomain.User, error) // BatchGetUsers 批量查询用户主状态,缺失用户不应返回占位对象。 BatchGetUsers(ctx context.Context, userIDs []int64) (map[int64]userdomain.User, error) + // ListUserIDs 按稳定 user_id 游标读取低频后台任务目标用户。 + ListUserIDs(ctx context.Context, filter userdomain.UserIDPageFilter) ([]int64, error) // CreateUserWithIdentity 原子创建用户和默认短号。 CreateUserWithIdentity(ctx context.Context, createdUser userdomain.User, identity userdomain.Identity) error // UpdateUserProfile 原子修改用户基础资料。 @@ -79,6 +81,15 @@ type IdentityRepository interface { ExpirePrettyDisplayUserID(ctx context.Context, command userdomain.ExpirePrettyDisplayUserIDCommand) (userdomain.Identity, error) } +// DeviceRepository 隔离设备 push token 的持久化。 +// 推送 token 只服务离线触达,不进入认证、房间或钱包主链路。 +type DeviceRepository interface { + // BindPushToken 原子绑定或替换当前用户设备 token。 + BindPushToken(ctx context.Context, command userdomain.PushTokenCommand) error + // DeletePushToken 失效当前用户设备 token。 + DeletePushToken(ctx context.Context, command userdomain.DeletePushTokenCommand) (bool, error) +} + // IDGenerator 生成系统内部不可变 user_id。 type IDGenerator interface { // NewInt64 返回全局唯一 user_id。 @@ -111,6 +122,8 @@ type Service struct { regionAdminRepository RegionAdminRepository // regionRebuildRepository 持有历史用户区域快照重算能力。 regionRebuildRepository RegionRebuildRepository + // deviceRepository 持有设备 push token 绑定能力。 + deviceRepository DeviceRepository // idGenerator 生成系统内部不可变 user_id。 idGenerator IDGenerator // displayUserIDAllocator 生成默认短号候选,唯一性由 repository 保证。 @@ -194,6 +207,15 @@ func WithRegionRebuildRepository(repository RegionRebuildRepository) Option { } } +// WithDeviceRepository 注入设备 push token repository。 +func WithDeviceRepository(repository DeviceRepository) Option { + return func(s *Service) { + if repository != nil { + s.deviceRepository = repository + } + } +} + // WithCountryChangeCooldown 配置用户国家修改冷却窗口。 func WithCountryChangeCooldown(cooldown time.Duration) Option { return func(s *Service) { diff --git a/services/user-service/internal/service/user/service_test.go b/services/user-service/internal/service/user/service_test.go index 934f948b..848778ba 100644 --- a/services/user-service/internal/service/user/service_test.go +++ b/services/user-service/internal/service/user/service_test.go @@ -88,6 +88,7 @@ func newUserService(repository *mysqltest.Repository, options ...userservice.Opt userservice.WithCountryAdminRepository(repository), userservice.WithRegionAdminRepository(repository), userservice.WithRegionRebuildRepository(repository), + userservice.WithDeviceRepository(repository), } return userservice.New(repository, append(base, options...)...) } @@ -136,6 +137,35 @@ func TestGetUserUsesRepository(t *testing.T) { } } +func TestListUserIDsUsesCursorAndTargetFilters(t *testing.T) { + repository := mysqltest.NewRepository(t) + for _, user := range []userdomain.User{ + {UserID: 10001, CurrentDisplayUserID: "100001", Status: userdomain.StatusActive, Country: "US", RegionID: 7}, + {UserID: 10002, CurrentDisplayUserID: "100002", Status: userdomain.StatusActive, Country: "SG", RegionID: 8}, + {UserID: 10003, CurrentDisplayUserID: "100003", Status: userdomain.StatusActive, Country: "US", RegionID: 7}, + {UserID: 10004, CurrentDisplayUserID: "100004", Status: userdomain.StatusDisabled, Country: "US", RegionID: 7}, + } { + repository.PutUser(completedUser(user)) + } + svc := newUserService(repository) + + userIDs, next, done, err := svc.ListUserIDs(context.Background(), userdomain.UserIDPageFilter{TargetScope: userdomain.UserIDTargetAllActiveUsers, PageSize: 2}) + if err != nil || done || next != 10002 || len(userIDs) != 2 || userIDs[0] != 10001 || userIDs[1] != 10002 { + t.Fatalf("all active first page mismatch: ids=%v next=%d done=%v err=%v", userIDs, next, done, err) + } + userIDs, next, done, err = svc.ListUserIDs(context.Background(), userdomain.UserIDPageFilter{TargetScope: userdomain.UserIDTargetRegion, RegionID: 7, CursorUserID: next, PageSize: 10}) + if err != nil || !done || next != 10003 || len(userIDs) != 1 || userIDs[0] != 10003 { + t.Fatalf("region page mismatch: ids=%v next=%d done=%v err=%v", userIDs, next, done, err) + } + userIDs, next, done, err = svc.ListUserIDs(context.Background(), userdomain.UserIDPageFilter{TargetScope: userdomain.UserIDTargetCountry, Country: " us ", PageSize: 10}) + if err != nil || !done || next != 10003 || len(userIDs) != 2 || userIDs[0] != 10001 || userIDs[1] != 10003 { + t.Fatalf("country page mismatch: ids=%v next=%d done=%v err=%v", userIDs, next, done, err) + } + if _, _, _, err := svc.ListUserIDs(context.Background(), userdomain.UserIDPageFilter{TargetScope: userdomain.UserIDTargetCountry, Country: "1"}); !xerr.IsCode(err, xerr.InvalidArgument) { + t.Fatalf("invalid country should fail, got %v", err) + } +} + func TestUpdateUserProfile(t *testing.T) { repository := mysqltest.NewRepository(t) repository.PutUser(completedUser(userdomain.User{ @@ -213,6 +243,67 @@ func TestUpdateUserProfile(t *testing.T) { } } +func TestBindAndDeletePushToken(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + current := time.UnixMilli(1700000000000) + svc := newUserService(repository, userservice.WithClock(func() time.Time { return current })) + repository.PutUser(completedUser(userdomain.User{ + UserID: 10001, + DefaultDisplayUserID: "100001", + CurrentDisplayUserID: "100001", + Status: userdomain.StatusActive, + })) + + updatedAt, err := svc.BindPushToken(ctx, 10001, " dev-1 ", " push-token-1 ", "", " android ", "1.2.3", "en-US", "America/Los_Angeles", "req-push-bind") + if err != nil { + t.Fatalf("BindPushToken failed: %v", err) + } + if updatedAt != 1700000000000 { + t.Fatalf("updated_at mismatch: got %d", updatedAt) + } + + deleted, deletedAt, err := svc.DeletePushToken(ctx, 10001, "dev-1", "push-token-1", "req-push-delete") + if err != nil { + t.Fatalf("DeletePushToken failed: %v", err) + } + if !deleted || deletedAt != 1700000000000 { + t.Fatalf("delete response mismatch: deleted=%v deletedAt=%d", deleted, deletedAt) + } +} + +func TestBindPushTokenValidation(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + svc := newUserService(repository) + repository.PutUser(completedUser(userdomain.User{ + UserID: 10001, + DefaultDisplayUserID: "100001", + CurrentDisplayUserID: "100001", + Status: userdomain.StatusActive, + })) + + tests := []struct { + name string + deviceID string + token string + platform string + wantCode xerr.Code + }{ + {name: "device", deviceID: "", token: "push-1", platform: "android", wantCode: xerr.InvalidArgument}, + {name: "token", deviceID: "dev-1", token: "", platform: "android", wantCode: xerr.InvalidArgument}, + {name: "platform", deviceID: "dev-1", token: "push-1", platform: "web", wantCode: xerr.InvalidArgument}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + _, err := svc.BindPushToken(ctx, 10001, test.deviceID, test.token, "", test.platform, "", "", "", "req-"+test.name) + if !xerr.IsCode(err, test.wantCode) { + t.Fatalf("error code mismatch: got %v want %s", err, test.wantCode) + } + }) + } +} + func TestCompleteOnboardingWritesProfileRegionAndSkipsCountryCooldown(t *testing.T) { // CompleteOnboarding 是注册页原子提交点,首次国家写入不能污染后续国家修改冷却日志。 ctx := context.Background() diff --git a/services/user-service/internal/service/user/user.go b/services/user-service/internal/service/user/user.go index 663714d5..a6d6f38a 100644 --- a/services/user-service/internal/service/user/user.go +++ b/services/user-service/internal/service/user/user.go @@ -2,12 +2,18 @@ package user import ( "context" + "strings" "hyapp/pkg/appcode" "hyapp/pkg/xerr" userdomain "hyapp/services/user-service/internal/domain/user" ) +const ( + defaultUserIDPageSize = 500 + maxUserIDPageSize = 5000 +) + // GetUser 查询单个用户主状态。 func (s *Service) GetUser(ctx context.Context, userID int64) (userdomain.User, error) { if userID <= 0 { @@ -65,6 +71,52 @@ func (s *Service) BatchGetUsers(ctx context.Context, userIDs []int64) (map[int64 return users, nil } +// ListUserIDs returns active user IDs for low-frequency backend fanout tasks. +func (s *Service) ListUserIDs(ctx context.Context, filter userdomain.UserIDPageFilter) ([]int64, int64, bool, error) { + if s.userRepository == nil { + return nil, 0, false, xerr.New(xerr.Unavailable, "user repository is not configured") + } + filter.TargetScope = strings.TrimSpace(filter.TargetScope) + filter.Country = userdomain.NormalizeCountryCode(filter.Country) + filter.PageSize = normalizeUserIDPageSize(filter.PageSize) + if filter.CursorUserID < 0 { + return nil, 0, false, xerr.New(xerr.InvalidArgument, "cursor_user_id is invalid") + } + switch filter.TargetScope { + case userdomain.UserIDTargetAllActiveUsers: + case userdomain.UserIDTargetRegion: + if filter.RegionID <= 0 { + return nil, 0, false, xerr.New(xerr.InvalidArgument, "region_id is required") + } + case userdomain.UserIDTargetCountry: + if !userdomain.ValidCountryCode(filter.Country) { + return nil, 0, false, xerr.New(xerr.InvalidArgument, "country is invalid") + } + default: + return nil, 0, false, xerr.New(xerr.InvalidArgument, "target_scope is invalid") + } + + userIDs, err := s.userRepository.ListUserIDs(ctx, filter) + if err != nil { + return nil, 0, false, err + } + nextCursor := filter.CursorUserID + if len(userIDs) > 0 { + nextCursor = userIDs[len(userIDs)-1] + } + return userIDs, nextCursor, len(userIDs) < filter.PageSize, nil +} + +func normalizeUserIDPageSize(value int) int { + if value <= 0 { + return defaultUserIDPageSize + } + if value > maxUserIDPageSize { + return maxUserIDPageSize + } + return value +} + // CreateUser 创建用户主记录,并同时分配 active display_user_id。 // 该方法供注册和三方首次登录后续接入,避免出现没有短号的用户。 func (s *Service) CreateUser(ctx context.Context) (userdomain.User, userdomain.Identity, error) { diff --git a/services/user-service/internal/storage/mysql/device/repository.go b/services/user-service/internal/storage/mysql/device/repository.go new file mode 100644 index 00000000..67b0cbe3 --- /dev/null +++ b/services/user-service/internal/storage/mysql/device/repository.go @@ -0,0 +1,119 @@ +// Package device implements user-service push token persistence. +package device + +import ( + "context" + "database/sql" + "strings" + + "hyapp/pkg/appcode" + userdomain "hyapp/services/user-service/internal/domain/user" +) + +// Repository stores App push tokens in MySQL. +type Repository struct { + db *sql.DB +} + +// New creates a device repository over the shared user-service connection pool. +func New(db *sql.DB) *Repository { + return &Repository{db: db} +} + +// BindPushToken binds a push token to the current user/device and removes stale ownership of the same token. +func (r *Repository) BindPushToken(ctx context.Context, command userdomain.PushTokenCommand) error { + appCode := normalizedAppCode(ctx, command.AppCode) + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return err + } + + // 同一个系统 push token 只能投递一次;重新登录其他账号时删除旧归属,避免离线消息双发。 + if _, err := tx.ExecContext(ctx, + `DELETE FROM user_push_tokens + WHERE app_code = ? AND provider = ? AND push_token = ? + AND NOT (user_id = ? AND device_id = ?)`, + appCode, + command.Provider, + command.PushToken, + command.UserID, + command.DeviceID, + ); err != nil { + _ = tx.Rollback() + return err + } + + if _, err := tx.ExecContext(ctx, + `INSERT INTO user_push_tokens ( + app_code, user_id, device_id, push_token, provider, platform, app_version, language, timezone, + status, bound_at_ms, updated_at_ms, last_request_id + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + push_token = VALUES(push_token), + provider = VALUES(provider), + platform = VALUES(platform), + app_version = VALUES(app_version), + language = VALUES(language), + timezone = VALUES(timezone), + status = VALUES(status), + updated_at_ms = VALUES(updated_at_ms), + last_request_id = VALUES(last_request_id)`, + appCode, + command.UserID, + command.DeviceID, + command.PushToken, + command.Provider, + command.Platform, + command.AppVersion, + command.Language, + command.Timezone, + userdomain.PushTokenStatusActive, + command.UpdatedAtMs, + command.UpdatedAtMs, + command.RequestID, + ); err != nil { + _ = tx.Rollback() + return err + } + + return tx.Commit() +} + +// DeletePushToken marks one user's device token inactive. +func (r *Repository) DeletePushToken(ctx context.Context, command userdomain.DeletePushTokenCommand) (bool, error) { + appCode := normalizedAppCode(ctx, command.AppCode) + query := `UPDATE user_push_tokens + SET status = ?, updated_at_ms = ?, last_request_id = ? + WHERE app_code = ? AND user_id = ? AND device_id = ? AND status = ?` + args := []any{ + userdomain.PushTokenStatusInactive, + command.UpdatedAtMs, + command.RequestID, + appCode, + command.UserID, + command.DeviceID, + userdomain.PushTokenStatusActive, + } + if strings.TrimSpace(command.PushToken) != "" { + query += ` AND push_token = ?` + args = append(args, command.PushToken) + } + + result, err := r.db.ExecContext(ctx, query, args...) + if err != nil { + return false, err + } + affected, err := result.RowsAffected() + if err != nil { + return false, err + } + return affected > 0, nil +} + +func normalizedAppCode(ctx context.Context, value string) string { + value = strings.TrimSpace(value) + if value == "" { + return appcode.FromContext(ctx) + } + return appcode.Normalize(value) +} diff --git a/services/user-service/internal/storage/mysql/repositories.go b/services/user-service/internal/storage/mysql/repositories.go index b5e39028..0472802e 100644 --- a/services/user-service/internal/storage/mysql/repositories.go +++ b/services/user-service/internal/storage/mysql/repositories.go @@ -3,6 +3,7 @@ package mysql import ( appstorage "hyapp/services/user-service/internal/storage/mysql/app" authstorage "hyapp/services/user-service/internal/storage/mysql/auth" + devicestorage "hyapp/services/user-service/internal/storage/mysql/device" hoststorage "hyapp/services/user-service/internal/storage/mysql/host" identitystorage "hyapp/services/user-service/internal/storage/mysql/identity" regionstorage "hyapp/services/user-service/internal/storage/mysql/region" @@ -49,6 +50,14 @@ func (r *Repository) RegionRepository() *regionstorage.Repository { return regionstorage.New(r.db) } +// 基于 user-service 共享 MySQL 连接池返回设备推送 token 存储对象。 +func (r *Repository) DeviceRepository() *devicestorage.Repository { + if r == nil { + return nil + } + return devicestorage.New(r.db) +} + // 基于 user-service 共享 MySQL 连接池返回 Host 领域存储对象。 func (r *Repository) HostRepository() *hoststorage.Repository { if r == nil { diff --git a/services/user-service/internal/storage/mysql/user/repository.go b/services/user-service/internal/storage/mysql/user/repository.go index c42057e1..b88b1d29 100644 --- a/services/user-service/internal/storage/mysql/user/repository.go +++ b/services/user-service/internal/storage/mysql/user/repository.go @@ -61,6 +61,42 @@ func (r *Repository) BatchGetUsers(ctx context.Context, userIDs []int64) (map[in return result, rows.Err() } +// ListUserIDs returns active user IDs in ascending order for cursor-based backend fanout. +func (r *Repository) ListUserIDs(ctx context.Context, filter userdomain.UserIDPageFilter) ([]int64, error) { + conditions := []string{"app_code = ?", "status = ?", "user_id > ?"} + args := []any{appcode.FromContext(ctx), string(userdomain.StatusActive), filter.CursorUserID} + switch filter.TargetScope { + case userdomain.UserIDTargetRegion: + conditions = append(conditions, "region_id = ?") + args = append(args, filter.RegionID) + case userdomain.UserIDTargetCountry: + conditions = append(conditions, "country = ?") + args = append(args, filter.Country) + } + args = append(args, filter.PageSize) + + rows, err := r.db.QueryContext(ctx, ` + SELECT user_id + FROM users + WHERE `+strings.Join(conditions, " AND ")+` + ORDER BY user_id ASC + LIMIT ?`, args...) + if err != nil { + return nil, err + } + defer rows.Close() + + userIDs := make([]int64, 0, filter.PageSize) + for rows.Next() { + var userID int64 + if err := rows.Scan(&userID); err != nil { + return nil, err + } + userIDs = append(userIDs, userID) + } + return userIDs, rows.Err() +} + // CreateUserWithIdentity 是用户创建的事务入口。 // 它同时写 users 和默认短号 active 记录,避免出现没有默认门牌号的用户。 diff --git a/services/user-service/internal/testutil/mysqltest/mysqltest.go b/services/user-service/internal/testutil/mysqltest/mysqltest.go index 6ee15425..f97c8bb2 100644 --- a/services/user-service/internal/testutil/mysqltest/mysqltest.go +++ b/services/user-service/internal/testutil/mysqltest/mysqltest.go @@ -61,6 +61,11 @@ func (r *Repository) BatchGetUsers(ctx context.Context, userIDs []int64) (map[in return r.Repository.UserRepository().BatchGetUsers(ctx, userIDs) } +// ListUserIDs 让测试 wrapper 继续满足后台 fanout 目标用户查询接口。 +func (r *Repository) ListUserIDs(ctx context.Context, filter userdomain.UserIDPageFilter) ([]int64, error) { + return r.Repository.UserRepository().ListUserIDs(ctx, filter) +} + // CreateUserWithIdentity 让测试 wrapper 继续满足业务层用户创建接口。 func (r *Repository) CreateUserWithIdentity(ctx context.Context, user userdomain.User, identity userdomain.Identity) error { return r.Repository.UserRepository().CreateUserWithIdentity(ctx, user, identity) @@ -81,6 +86,16 @@ func (r *Repository) ChangeUserCountry(ctx context.Context, command userdomain.C return r.Repository.UserRepository().ChangeUserCountry(ctx, command) } +// BindPushToken 让测试 wrapper 继续满足设备 push token repository。 +func (r *Repository) BindPushToken(ctx context.Context, command userdomain.PushTokenCommand) error { + return r.Repository.DeviceRepository().BindPushToken(ctx, command) +} + +// DeletePushToken 让测试 wrapper 继续满足设备 push token repository。 +func (r *Repository) DeletePushToken(ctx context.Context, command userdomain.DeletePushTokenCommand) (bool, error) { + return r.Repository.DeviceRepository().DeletePushToken(ctx, command) +} + // AllocateDisplayUserID 让测试 wrapper 继续满足认证注册接口。 func (r *Repository) AllocateDisplayUserID(ctx context.Context, appCode string) (string, error) { return r.Repository.AuthRepository().AllocateDisplayUserID(ctx, appCode) diff --git a/services/user-service/internal/transport/grpc/server.go b/services/user-service/internal/transport/grpc/server.go index 594dc3bb..75d11acd 100644 --- a/services/user-service/internal/transport/grpc/server.go +++ b/services/user-service/internal/transport/grpc/server.go @@ -20,6 +20,8 @@ type Server struct { userv1.UnimplementedAuthServiceServer // UnimplementedUserServiceServer 提供未实现 RPC 的默认返回。 userv1.UnimplementedUserServiceServer + // UnimplementedUserDeviceServiceServer 提供设备推送 token RPC 的默认返回。 + userv1.UnimplementedUserDeviceServiceServer // UnimplementedAppRegistryServiceServer 提供 App 注册表 RPC 的默认返回。 userv1.UnimplementedAppRegistryServiceServer // UnimplementedUserIdentityServiceServer 提供未实现 RPC 的默认返回。 @@ -175,6 +177,22 @@ func (s *Server) BatchGetUsers(ctx context.Context, req *userv1.BatchGetUsersReq return &userv1.BatchGetUsersResponse{Users: result}, nil } +// ListUserIDs 为后台 fanout 任务返回稳定递增的用户 ID 游标页。 +func (s *Server) ListUserIDs(ctx context.Context, req *userv1.ListUserIDsRequest) (*userv1.ListUserIDsResponse, error) { + ctx = contextWithApp(ctx, req.GetMeta()) + userIDs, nextCursor, done, err := s.userSvc.ListUserIDs(ctx, userdomain.UserIDPageFilter{ + TargetScope: req.GetTargetScope(), + CursorUserID: req.GetCursorUserId(), + PageSize: int(req.GetPageSize()), + RegionID: req.GetRegionId(), + Country: req.GetCountry(), + }) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &userv1.ListUserIDsResponse{UserIds: userIDs, NextCursorUserId: nextCursor, Done: done}, nil +} + // UpdateUserProfile 修改当前用户基础资料。 func (s *Server) UpdateUserProfile(ctx context.Context, req *userv1.UpdateUserProfileRequest) (*userv1.UpdateUserProfileResponse, error) { ctx = contextWithApp(ctx, req.GetMeta()) @@ -230,6 +248,26 @@ func (s *Server) CompleteOnboarding(ctx context.Context, req *userv1.CompleteOnb }, nil } +// BindPushToken 绑定当前用户设备推送 token。 +func (s *Server) BindPushToken(ctx context.Context, req *userv1.BindPushTokenRequest) (*userv1.BindPushTokenResponse, error) { + ctx = contextWithApp(ctx, req.GetMeta()) + updatedAtMS, err := s.userSvc.BindPushToken(ctx, req.GetUserId(), req.GetDeviceId(), req.GetPushToken(), req.GetProvider(), req.GetPlatform(), req.GetAppVersion(), req.GetLanguage(), req.GetTimezone(), req.GetMeta().GetRequestId()) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &userv1.BindPushTokenResponse{Bound: true, UpdatedAtMs: updatedAtMS}, nil +} + +// DeletePushToken 失效当前用户设备推送 token。 +func (s *Server) DeletePushToken(ctx context.Context, req *userv1.DeletePushTokenRequest) (*userv1.DeletePushTokenResponse, error) { + ctx = contextWithApp(ctx, req.GetMeta()) + deleted, updatedAtMS, err := s.userSvc.DeletePushToken(ctx, req.GetUserId(), req.GetDeviceId(), req.GetPushToken(), req.GetMeta().GetRequestId()) + if err != nil { + return nil, xerr.ToGRPCError(err) + } + return &userv1.DeletePushTokenResponse{Deleted: deleted, UpdatedAtMs: updatedAtMS}, nil +} + // ListCountries 返回国家主数据列表。 func (s *Server) ListCountries(ctx context.Context, req *userv1.ListCountriesRequest) (*userv1.ListCountriesResponse, error) { ctx = contextWithApp(ctx, req.GetMeta()) diff --git a/services/user-service/internal/transport/grpc/server_test.go b/services/user-service/internal/transport/grpc/server_test.go index 2ec0edb8..97007834 100644 --- a/services/user-service/internal/transport/grpc/server_test.go +++ b/services/user-service/internal/transport/grpc/server_test.go @@ -22,6 +22,7 @@ func newUserService(repository *mysqltest.Repository, options ...userservice.Opt userservice.WithCountryAdminRepository(repository), userservice.WithRegionAdminRepository(repository), userservice.WithRegionRebuildRepository(repository), + userservice.WithDeviceRepository(repository), } return userservice.New(repository, append(base, options...)...) }