diff --git a/api/proto/room/v1/room.pb.go b/api/proto/room/v1/room.pb.go index b59c2402..21165f6b 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 v5.29.2 +// protoc v7.34.1 // source: proto/room/v1/room.proto package roomv1 @@ -909,6 +909,119 @@ func (x *JoinRoomResponse) GetRoom() *RoomSnapshot { return nil } +// RoomHeartbeatRequest 显式刷新已经存在的房间业务 presence。 +// 它不能替代 JoinRoom;用户不在房间时必须拒绝,避免心跳把已离开的用户重新加入房间。 +type RoomHeartbeatRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` +} + +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) + } +} + +func (x *RoomHeartbeatRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoomHeartbeatRequest) ProtoMessage() {} + +func (x *RoomHeartbeatRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RoomHeartbeatRequest.ProtoReflect.Descriptor instead. +func (*RoomHeartbeatRequest) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{10} +} + +func (x *RoomHeartbeatRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +// RoomHeartbeatResponse 返回刷新后的用户 presence 和房间快照。 +type RoomHeartbeatResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result *CommandResult `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + User *RoomUser `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"` + Room *RoomSnapshot `protobuf:"bytes,3,opt,name=room,proto3" json:"room,omitempty"` +} + +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) + } +} + +func (x *RoomHeartbeatResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoomHeartbeatResponse) ProtoMessage() {} + +func (x *RoomHeartbeatResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RoomHeartbeatResponse.ProtoReflect.Descriptor instead. +func (*RoomHeartbeatResponse) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{11} +} + +func (x *RoomHeartbeatResponse) GetResult() *CommandResult { + if x != nil { + return x.Result + } + return nil +} + +func (x *RoomHeartbeatResponse) GetUser() *RoomUser { + if x != nil { + return x.User + } + return nil +} + +func (x *RoomHeartbeatResponse) GetRoom() *RoomSnapshot { + if x != nil { + return x.Room + } + return nil +} + // LeaveRoomRequest 把用户从房间 presence 移出。 type LeaveRoomRequest struct { state protoimpl.MessageState @@ -921,7 +1034,7 @@ type LeaveRoomRequest struct { func (x *LeaveRoomRequest) Reset() { *x = LeaveRoomRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[10] + mi := &file_proto_room_v1_room_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -934,7 +1047,7 @@ func (x *LeaveRoomRequest) String() string { func (*LeaveRoomRequest) ProtoMessage() {} func (x *LeaveRoomRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[10] + mi := &file_proto_room_v1_room_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -947,7 +1060,7 @@ func (x *LeaveRoomRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LeaveRoomRequest.ProtoReflect.Descriptor instead. func (*LeaveRoomRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{10} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{12} } func (x *LeaveRoomRequest) GetMeta() *RequestMeta { @@ -970,7 +1083,7 @@ type LeaveRoomResponse struct { func (x *LeaveRoomResponse) Reset() { *x = LeaveRoomResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[11] + mi := &file_proto_room_v1_room_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -983,7 +1096,7 @@ func (x *LeaveRoomResponse) String() string { func (*LeaveRoomResponse) ProtoMessage() {} func (x *LeaveRoomResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[11] + mi := &file_proto_room_v1_room_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -996,7 +1109,7 @@ func (x *LeaveRoomResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LeaveRoomResponse.ProtoReflect.Descriptor instead. func (*LeaveRoomResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{11} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{13} } func (x *LeaveRoomResponse) GetResult() *CommandResult { @@ -1026,7 +1139,7 @@ type MicUpRequest struct { func (x *MicUpRequest) Reset() { *x = MicUpRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[12] + mi := &file_proto_room_v1_room_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1039,7 +1152,7 @@ func (x *MicUpRequest) String() string { func (*MicUpRequest) ProtoMessage() {} func (x *MicUpRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[12] + mi := &file_proto_room_v1_room_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1052,7 +1165,7 @@ func (x *MicUpRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MicUpRequest.ProtoReflect.Descriptor instead. func (*MicUpRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{12} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{14} } func (x *MicUpRequest) GetMeta() *RequestMeta { @@ -1085,7 +1198,7 @@ type MicUpResponse struct { func (x *MicUpResponse) Reset() { *x = MicUpResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[13] + mi := &file_proto_room_v1_room_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1098,7 +1211,7 @@ func (x *MicUpResponse) String() string { func (*MicUpResponse) ProtoMessage() {} func (x *MicUpResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[13] + mi := &file_proto_room_v1_room_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1111,7 +1224,7 @@ func (x *MicUpResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MicUpResponse.ProtoReflect.Descriptor instead. func (*MicUpResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{13} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{15} } func (x *MicUpResponse) GetResult() *CommandResult { @@ -1164,7 +1277,7 @@ type MicDownRequest struct { func (x *MicDownRequest) Reset() { *x = MicDownRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[14] + mi := &file_proto_room_v1_room_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1177,7 +1290,7 @@ func (x *MicDownRequest) String() string { func (*MicDownRequest) ProtoMessage() {} func (x *MicDownRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[14] + mi := &file_proto_room_v1_room_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1190,7 +1303,7 @@ func (x *MicDownRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MicDownRequest.ProtoReflect.Descriptor instead. func (*MicDownRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{14} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{16} } func (x *MicDownRequest) GetMeta() *RequestMeta { @@ -1228,7 +1341,7 @@ type MicDownResponse struct { func (x *MicDownResponse) Reset() { *x = MicDownResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[15] + mi := &file_proto_room_v1_room_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1241,7 +1354,7 @@ func (x *MicDownResponse) String() string { func (*MicDownResponse) ProtoMessage() {} func (x *MicDownResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[15] + mi := &file_proto_room_v1_room_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1254,7 +1367,7 @@ func (x *MicDownResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MicDownResponse.ProtoReflect.Descriptor instead. func (*MicDownResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{15} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{17} } func (x *MicDownResponse) GetResult() *CommandResult { @@ -1292,7 +1405,7 @@ type ChangeMicSeatRequest struct { func (x *ChangeMicSeatRequest) Reset() { *x = ChangeMicSeatRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[16] + mi := &file_proto_room_v1_room_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1305,7 +1418,7 @@ func (x *ChangeMicSeatRequest) String() string { func (*ChangeMicSeatRequest) ProtoMessage() {} func (x *ChangeMicSeatRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[16] + mi := &file_proto_room_v1_room_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1318,7 +1431,7 @@ func (x *ChangeMicSeatRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeMicSeatRequest.ProtoReflect.Descriptor instead. func (*ChangeMicSeatRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{16} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{18} } func (x *ChangeMicSeatRequest) GetMeta() *RequestMeta { @@ -1355,7 +1468,7 @@ type ChangeMicSeatResponse struct { func (x *ChangeMicSeatResponse) Reset() { *x = ChangeMicSeatResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[17] + mi := &file_proto_room_v1_room_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1368,7 +1481,7 @@ func (x *ChangeMicSeatResponse) String() string { func (*ChangeMicSeatResponse) ProtoMessage() {} func (x *ChangeMicSeatResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[17] + mi := &file_proto_room_v1_room_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1381,7 +1494,7 @@ func (x *ChangeMicSeatResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeMicSeatResponse.ProtoReflect.Descriptor instead. func (*ChangeMicSeatResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{17} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{19} } func (x *ChangeMicSeatResponse) GetResult() *CommandResult { @@ -1417,7 +1530,7 @@ type ConfirmMicPublishingRequest struct { func (x *ConfirmMicPublishingRequest) Reset() { *x = ConfirmMicPublishingRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[18] + mi := &file_proto_room_v1_room_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1430,7 +1543,7 @@ func (x *ConfirmMicPublishingRequest) String() string { func (*ConfirmMicPublishingRequest) ProtoMessage() {} func (x *ConfirmMicPublishingRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[18] + mi := &file_proto_room_v1_room_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1443,7 +1556,7 @@ func (x *ConfirmMicPublishingRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfirmMicPublishingRequest.ProtoReflect.Descriptor instead. func (*ConfirmMicPublishingRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{18} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{20} } func (x *ConfirmMicPublishingRequest) GetMeta() *RequestMeta { @@ -1502,7 +1615,7 @@ type ConfirmMicPublishingResponse struct { func (x *ConfirmMicPublishingResponse) Reset() { *x = ConfirmMicPublishingResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[19] + mi := &file_proto_room_v1_room_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1515,7 +1628,7 @@ func (x *ConfirmMicPublishingResponse) String() string { func (*ConfirmMicPublishingResponse) ProtoMessage() {} func (x *ConfirmMicPublishingResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[19] + mi := &file_proto_room_v1_room_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1528,7 +1641,7 @@ func (x *ConfirmMicPublishingResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfirmMicPublishingResponse.ProtoReflect.Descriptor instead. func (*ConfirmMicPublishingResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{19} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{21} } func (x *ConfirmMicPublishingResponse) GetResult() *CommandResult { @@ -1552,6 +1665,167 @@ func (x *ConfirmMicPublishingResponse) GetRoom() *RoomSnapshot { return nil } +// ApplyRTCEventRequest 把可信 RTC 服务端回调转换成 Room Cell 命令。 +// event_type 当前只接受 audio_started、audio_stopped、room_exited。 +type ApplyRTCEventRequest 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"` + EventType string `protobuf:"bytes,3,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"` + EventTimeMs int64 `protobuf:"varint,4,opt,name=event_time_ms,json=eventTimeMs,proto3" json:"event_time_ms,omitempty"` + Reason string `protobuf:"bytes,5,opt,name=reason,proto3" json:"reason,omitempty"` + Source string `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` + ExternalEventId string `protobuf:"bytes,7,opt,name=external_event_id,json=externalEventId,proto3" json:"external_event_id,omitempty"` +} + +func (x *ApplyRTCEventRequest) Reset() { + *x = ApplyRTCEventRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_room_v1_room_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyRTCEventRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyRTCEventRequest) ProtoMessage() {} + +func (x *ApplyRTCEventRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyRTCEventRequest.ProtoReflect.Descriptor instead. +func (*ApplyRTCEventRequest) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{22} +} + +func (x *ApplyRTCEventRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *ApplyRTCEventRequest) GetTargetUserId() int64 { + if x != nil { + return x.TargetUserId + } + return 0 +} + +func (x *ApplyRTCEventRequest) GetEventType() string { + if x != nil { + return x.EventType + } + return "" +} + +func (x *ApplyRTCEventRequest) GetEventTimeMs() int64 { + if x != nil { + return x.EventTimeMs + } + return 0 +} + +func (x *ApplyRTCEventRequest) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *ApplyRTCEventRequest) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *ApplyRTCEventRequest) GetExternalEventId() string { + if x != nil { + return x.ExternalEventId + } + return "" +} + +// ApplyRTCEventResponse 返回 RTC 事件落房间状态后的快照。 +type ApplyRTCEventResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result *CommandResult `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + SeatNo int32 `protobuf:"varint,2,opt,name=seat_no,json=seatNo,proto3" json:"seat_no,omitempty"` + Room *RoomSnapshot `protobuf:"bytes,3,opt,name=room,proto3" json:"room,omitempty"` +} + +func (x *ApplyRTCEventResponse) Reset() { + *x = ApplyRTCEventResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_room_v1_room_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyRTCEventResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyRTCEventResponse) ProtoMessage() {} + +func (x *ApplyRTCEventResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_room_v1_room_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyRTCEventResponse.ProtoReflect.Descriptor instead. +func (*ApplyRTCEventResponse) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{23} +} + +func (x *ApplyRTCEventResponse) GetResult() *CommandResult { + if x != nil { + return x.Result + } + return nil +} + +func (x *ApplyRTCEventResponse) GetSeatNo() int32 { + if x != nil { + return x.SeatNo + } + return 0 +} + +func (x *ApplyRTCEventResponse) GetRoom() *RoomSnapshot { + if x != nil { + return x.Room + } + return nil +} + // SetMicSeatLockRequest 锁定或解锁指定麦位。 type SetMicSeatLockRequest struct { state protoimpl.MessageState @@ -1566,7 +1840,7 @@ type SetMicSeatLockRequest struct { func (x *SetMicSeatLockRequest) Reset() { *x = SetMicSeatLockRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[20] + mi := &file_proto_room_v1_room_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1579,7 +1853,7 @@ func (x *SetMicSeatLockRequest) String() string { func (*SetMicSeatLockRequest) ProtoMessage() {} func (x *SetMicSeatLockRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[20] + mi := &file_proto_room_v1_room_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1592,7 +1866,7 @@ func (x *SetMicSeatLockRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetMicSeatLockRequest.ProtoReflect.Descriptor instead. func (*SetMicSeatLockRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{20} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{24} } func (x *SetMicSeatLockRequest) GetMeta() *RequestMeta { @@ -1629,7 +1903,7 @@ type SetMicSeatLockResponse struct { func (x *SetMicSeatLockResponse) Reset() { *x = SetMicSeatLockResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[21] + mi := &file_proto_room_v1_room_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1642,7 +1916,7 @@ func (x *SetMicSeatLockResponse) String() string { func (*SetMicSeatLockResponse) ProtoMessage() {} func (x *SetMicSeatLockResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[21] + mi := &file_proto_room_v1_room_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1655,7 +1929,7 @@ func (x *SetMicSeatLockResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SetMicSeatLockResponse.ProtoReflect.Descriptor instead. func (*SetMicSeatLockResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{21} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{25} } func (x *SetMicSeatLockResponse) GetResult() *CommandResult { @@ -1685,7 +1959,7 @@ type SetChatEnabledRequest struct { func (x *SetChatEnabledRequest) Reset() { *x = SetChatEnabledRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[22] + mi := &file_proto_room_v1_room_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1698,7 +1972,7 @@ func (x *SetChatEnabledRequest) String() string { func (*SetChatEnabledRequest) ProtoMessage() {} func (x *SetChatEnabledRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[22] + mi := &file_proto_room_v1_room_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1711,7 +1985,7 @@ func (x *SetChatEnabledRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetChatEnabledRequest.ProtoReflect.Descriptor instead. func (*SetChatEnabledRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{22} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{26} } func (x *SetChatEnabledRequest) GetMeta() *RequestMeta { @@ -1741,7 +2015,7 @@ type SetChatEnabledResponse struct { func (x *SetChatEnabledResponse) Reset() { *x = SetChatEnabledResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[23] + mi := &file_proto_room_v1_room_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1754,7 +2028,7 @@ func (x *SetChatEnabledResponse) String() string { func (*SetChatEnabledResponse) ProtoMessage() {} func (x *SetChatEnabledResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[23] + mi := &file_proto_room_v1_room_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1767,7 +2041,7 @@ func (x *SetChatEnabledResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SetChatEnabledResponse.ProtoReflect.Descriptor instead. func (*SetChatEnabledResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{23} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{27} } func (x *SetChatEnabledResponse) GetResult() *CommandResult { @@ -1798,7 +2072,7 @@ type SetRoomAdminRequest struct { func (x *SetRoomAdminRequest) Reset() { *x = SetRoomAdminRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[24] + mi := &file_proto_room_v1_room_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1811,7 +2085,7 @@ func (x *SetRoomAdminRequest) String() string { func (*SetRoomAdminRequest) ProtoMessage() {} func (x *SetRoomAdminRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[24] + mi := &file_proto_room_v1_room_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1824,7 +2098,7 @@ func (x *SetRoomAdminRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetRoomAdminRequest.ProtoReflect.Descriptor instead. func (*SetRoomAdminRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{24} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{28} } func (x *SetRoomAdminRequest) GetMeta() *RequestMeta { @@ -1861,7 +2135,7 @@ type SetRoomAdminResponse struct { func (x *SetRoomAdminResponse) Reset() { *x = SetRoomAdminResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[25] + mi := &file_proto_room_v1_room_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1874,7 +2148,7 @@ func (x *SetRoomAdminResponse) String() string { func (*SetRoomAdminResponse) ProtoMessage() {} func (x *SetRoomAdminResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[25] + mi := &file_proto_room_v1_room_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1887,7 +2161,7 @@ func (x *SetRoomAdminResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SetRoomAdminResponse.ProtoReflect.Descriptor instead. func (*SetRoomAdminResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{25} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{29} } func (x *SetRoomAdminResponse) GetResult() *CommandResult { @@ -1917,7 +2191,7 @@ type TransferRoomHostRequest struct { func (x *TransferRoomHostRequest) Reset() { *x = TransferRoomHostRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[26] + mi := &file_proto_room_v1_room_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1930,7 +2204,7 @@ func (x *TransferRoomHostRequest) String() string { func (*TransferRoomHostRequest) ProtoMessage() {} func (x *TransferRoomHostRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[26] + mi := &file_proto_room_v1_room_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1943,7 +2217,7 @@ func (x *TransferRoomHostRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TransferRoomHostRequest.ProtoReflect.Descriptor instead. func (*TransferRoomHostRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{26} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{30} } func (x *TransferRoomHostRequest) GetMeta() *RequestMeta { @@ -1973,7 +2247,7 @@ type TransferRoomHostResponse struct { func (x *TransferRoomHostResponse) Reset() { *x = TransferRoomHostResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[27] + mi := &file_proto_room_v1_room_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1986,7 +2260,7 @@ func (x *TransferRoomHostResponse) String() string { func (*TransferRoomHostResponse) ProtoMessage() {} func (x *TransferRoomHostResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[27] + mi := &file_proto_room_v1_room_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1999,7 +2273,7 @@ func (x *TransferRoomHostResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TransferRoomHostResponse.ProtoReflect.Descriptor instead. func (*TransferRoomHostResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{27} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{31} } func (x *TransferRoomHostResponse) GetResult() *CommandResult { @@ -2030,7 +2304,7 @@ type MuteUserRequest struct { func (x *MuteUserRequest) Reset() { *x = MuteUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[28] + mi := &file_proto_room_v1_room_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2043,7 +2317,7 @@ func (x *MuteUserRequest) String() string { func (*MuteUserRequest) ProtoMessage() {} func (x *MuteUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[28] + mi := &file_proto_room_v1_room_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2056,7 +2330,7 @@ func (x *MuteUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MuteUserRequest.ProtoReflect.Descriptor instead. func (*MuteUserRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{28} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{32} } func (x *MuteUserRequest) GetMeta() *RequestMeta { @@ -2093,7 +2367,7 @@ type MuteUserResponse struct { func (x *MuteUserResponse) Reset() { *x = MuteUserResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[29] + mi := &file_proto_room_v1_room_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2106,7 +2380,7 @@ func (x *MuteUserResponse) String() string { func (*MuteUserResponse) ProtoMessage() {} func (x *MuteUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[29] + mi := &file_proto_room_v1_room_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2119,7 +2393,7 @@ func (x *MuteUserResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MuteUserResponse.ProtoReflect.Descriptor instead. func (*MuteUserResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{29} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{33} } func (x *MuteUserResponse) GetResult() *CommandResult { @@ -2149,7 +2423,7 @@ type KickUserRequest struct { func (x *KickUserRequest) Reset() { *x = KickUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[30] + mi := &file_proto_room_v1_room_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2162,7 +2436,7 @@ func (x *KickUserRequest) String() string { func (*KickUserRequest) ProtoMessage() {} func (x *KickUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[30] + mi := &file_proto_room_v1_room_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2175,7 +2449,7 @@ func (x *KickUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use KickUserRequest.ProtoReflect.Descriptor instead. func (*KickUserRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{30} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{34} } func (x *KickUserRequest) GetMeta() *RequestMeta { @@ -2205,7 +2479,7 @@ type KickUserResponse struct { func (x *KickUserResponse) Reset() { *x = KickUserResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[31] + mi := &file_proto_room_v1_room_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2218,7 +2492,7 @@ func (x *KickUserResponse) String() string { func (*KickUserResponse) ProtoMessage() {} func (x *KickUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[31] + mi := &file_proto_room_v1_room_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2231,7 +2505,7 @@ func (x *KickUserResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use KickUserResponse.ProtoReflect.Descriptor instead. func (*KickUserResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{31} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{35} } func (x *KickUserResponse) GetResult() *CommandResult { @@ -2261,7 +2535,7 @@ type UnbanUserRequest struct { func (x *UnbanUserRequest) Reset() { *x = UnbanUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[32] + mi := &file_proto_room_v1_room_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2274,7 +2548,7 @@ func (x *UnbanUserRequest) String() string { func (*UnbanUserRequest) ProtoMessage() {} func (x *UnbanUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[32] + mi := &file_proto_room_v1_room_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2287,7 +2561,7 @@ func (x *UnbanUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbanUserRequest.ProtoReflect.Descriptor instead. func (*UnbanUserRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{32} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{36} } func (x *UnbanUserRequest) GetMeta() *RequestMeta { @@ -2317,7 +2591,7 @@ type UnbanUserResponse struct { func (x *UnbanUserResponse) Reset() { *x = UnbanUserResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[33] + mi := &file_proto_room_v1_room_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2330,7 +2604,7 @@ func (x *UnbanUserResponse) String() string { func (*UnbanUserResponse) ProtoMessage() {} func (x *UnbanUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[33] + mi := &file_proto_room_v1_room_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2343,7 +2617,7 @@ func (x *UnbanUserResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbanUserResponse.ProtoReflect.Descriptor instead. func (*UnbanUserResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{33} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{37} } func (x *UnbanUserResponse) GetResult() *CommandResult { @@ -2375,7 +2649,7 @@ type SendGiftRequest struct { func (x *SendGiftRequest) Reset() { *x = SendGiftRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[34] + mi := &file_proto_room_v1_room_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2388,7 +2662,7 @@ func (x *SendGiftRequest) String() string { func (*SendGiftRequest) ProtoMessage() {} func (x *SendGiftRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[34] + mi := &file_proto_room_v1_room_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2401,7 +2675,7 @@ func (x *SendGiftRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SendGiftRequest.ProtoReflect.Descriptor instead. func (*SendGiftRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{34} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{38} } func (x *SendGiftRequest) GetMeta() *RequestMeta { @@ -2448,7 +2722,7 @@ type SendGiftResponse struct { func (x *SendGiftResponse) Reset() { *x = SendGiftResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[35] + mi := &file_proto_room_v1_room_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2461,7 +2735,7 @@ func (x *SendGiftResponse) String() string { func (*SendGiftResponse) ProtoMessage() {} func (x *SendGiftResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[35] + mi := &file_proto_room_v1_room_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2474,7 +2748,7 @@ func (x *SendGiftResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SendGiftResponse.ProtoReflect.Descriptor instead. func (*SendGiftResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{35} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{39} } func (x *SendGiftResponse) GetResult() *CommandResult { @@ -2526,7 +2800,7 @@ type CheckSpeakPermissionRequest struct { func (x *CheckSpeakPermissionRequest) Reset() { *x = CheckSpeakPermissionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[36] + mi := &file_proto_room_v1_room_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2539,7 +2813,7 @@ func (x *CheckSpeakPermissionRequest) String() string { func (*CheckSpeakPermissionRequest) ProtoMessage() {} func (x *CheckSpeakPermissionRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[36] + mi := &file_proto_room_v1_room_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2552,7 +2826,7 @@ func (x *CheckSpeakPermissionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckSpeakPermissionRequest.ProtoReflect.Descriptor instead. func (*CheckSpeakPermissionRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{36} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{40} } func (x *CheckSpeakPermissionRequest) GetRoomId() string { @@ -2590,7 +2864,7 @@ type CheckSpeakPermissionResponse struct { func (x *CheckSpeakPermissionResponse) Reset() { *x = CheckSpeakPermissionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[37] + mi := &file_proto_room_v1_room_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2603,7 +2877,7 @@ func (x *CheckSpeakPermissionResponse) String() string { func (*CheckSpeakPermissionResponse) ProtoMessage() {} func (x *CheckSpeakPermissionResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[37] + mi := &file_proto_room_v1_room_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2616,7 +2890,7 @@ func (x *CheckSpeakPermissionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckSpeakPermissionResponse.ProtoReflect.Descriptor instead. func (*CheckSpeakPermissionResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{37} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{41} } func (x *CheckSpeakPermissionResponse) GetAllowed() bool { @@ -2656,7 +2930,7 @@ type VerifyRoomPresenceRequest struct { func (x *VerifyRoomPresenceRequest) Reset() { *x = VerifyRoomPresenceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[38] + mi := &file_proto_room_v1_room_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2669,7 +2943,7 @@ func (x *VerifyRoomPresenceRequest) String() string { func (*VerifyRoomPresenceRequest) ProtoMessage() {} func (x *VerifyRoomPresenceRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[38] + mi := &file_proto_room_v1_room_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2682,7 +2956,7 @@ func (x *VerifyRoomPresenceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyRoomPresenceRequest.ProtoReflect.Descriptor instead. func (*VerifyRoomPresenceRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{38} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{42} } func (x *VerifyRoomPresenceRequest) GetRoomId() string { @@ -2734,7 +3008,7 @@ type VerifyRoomPresenceResponse struct { func (x *VerifyRoomPresenceResponse) Reset() { *x = VerifyRoomPresenceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[39] + mi := &file_proto_room_v1_room_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2747,7 +3021,7 @@ func (x *VerifyRoomPresenceResponse) String() string { func (*VerifyRoomPresenceResponse) ProtoMessage() {} func (x *VerifyRoomPresenceResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[39] + mi := &file_proto_room_v1_room_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2760,7 +3034,7 @@ func (x *VerifyRoomPresenceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyRoomPresenceResponse.ProtoReflect.Descriptor instead. func (*VerifyRoomPresenceResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{39} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{43} } func (x *VerifyRoomPresenceResponse) GetPresent() bool { @@ -2803,7 +3077,7 @@ type ListRoomsRequest struct { func (x *ListRoomsRequest) Reset() { *x = ListRoomsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[40] + mi := &file_proto_room_v1_room_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2816,7 +3090,7 @@ func (x *ListRoomsRequest) String() string { func (*ListRoomsRequest) ProtoMessage() {} func (x *ListRoomsRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[40] + mi := &file_proto_room_v1_room_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2829,7 +3103,7 @@ func (x *ListRoomsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRoomsRequest.ProtoReflect.Descriptor instead. func (*ListRoomsRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{40} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{44} } func (x *ListRoomsRequest) GetMeta() *RequestMeta { @@ -2906,7 +3180,7 @@ type RoomListItem struct { func (x *RoomListItem) Reset() { *x = RoomListItem{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[41] + mi := &file_proto_room_v1_room_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2919,7 +3193,7 @@ func (x *RoomListItem) String() string { func (*RoomListItem) ProtoMessage() {} func (x *RoomListItem) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[41] + mi := &file_proto_room_v1_room_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2932,7 +3206,7 @@ func (x *RoomListItem) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomListItem.ProtoReflect.Descriptor instead. func (*RoomListItem) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{41} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{45} } func (x *RoomListItem) GetRoomId() string { @@ -3046,7 +3320,7 @@ type ListRoomsResponse struct { func (x *ListRoomsResponse) Reset() { *x = ListRoomsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[42] + mi := &file_proto_room_v1_room_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3059,7 +3333,7 @@ func (x *ListRoomsResponse) String() string { func (*ListRoomsResponse) ProtoMessage() {} func (x *ListRoomsResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[42] + mi := &file_proto_room_v1_room_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3072,7 +3346,7 @@ func (x *ListRoomsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRoomsResponse.ProtoReflect.Descriptor instead. func (*ListRoomsResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{42} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{46} } func (x *ListRoomsResponse) GetRooms() []*RoomListItem { @@ -3242,25 +3516,63 @@ var file_proto_room_v1_room_proto_rawDesc = []byte{ 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x22, 0x42, 0x0a, 0x10, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, - 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x11, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, - 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x22, 0x57, 0x0a, 0x0c, 0x4d, 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, - 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x22, 0xe5, 0x01, 0x0a, 0x0d, - 0x4d, 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, + 0x6f, 0x6d, 0x22, 0x46, 0x0a, 0x14, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, + 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, + 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xab, 0x01, 0x0a, 0x15, 0x52, + 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x75, 0x73, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x42, 0x0a, 0x10, 0x4c, 0x65, 0x61, 0x76, + 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, + 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x11, + 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x57, 0x0a, 0x0c, 0x4d, 0x69, 0x63, 0x55, + 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, + 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, + 0x6f, 0x22, 0xe5, 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, + 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, + 0x4e, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, + 0x6f, 0x6f, 0x6d, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6d, 0x73, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x44, + 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x4d, 0x73, 0x22, 0x7e, 0x0a, 0x0e, 0x4d, 0x69, 0x63, + 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, + 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, + 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, @@ -3268,39 +3580,115 @@ var file_proto_room_v1_room_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x12, 0x24, 0x0a, - 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x64, - 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x11, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, - 0x65, 0x4d, 0x73, 0x22, 0x7e, 0x0a, 0x0e, 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x85, 0x01, + 0x0a, 0x14, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, + 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, + 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x22, 0x7e, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, + 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, + 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, + 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0xf8, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, + 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, - 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x17, 0x0a, - 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, - 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, - 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x85, 0x01, 0x0a, 0x14, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x6d, + 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x22, 0x9e, 0x01, 0x0a, 0x1c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, + 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, + 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, + 0x6d, 0x22, 0x8b, 0x02, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, + 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x22, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x4d, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, + 0x97, 0x01, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x78, 0x0a, 0x15, 0x53, 0x65, 0x74, + 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, + 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x6c, + 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x6f, 0x63, + 0x6b, 0x65, 0x64, 0x22, 0x7f, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, + 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, + 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x61, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x18, 0x0a, + 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x7f, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x43, 0x68, + 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x85, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x74, + 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, - 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x22, - 0x7e, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x22, 0x7d, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, @@ -3308,351 +3696,290 @@ var file_proto_room_v1_room_proto_rawDesc = []byte{ 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, - 0xf8, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, - 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, - 0x69, 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, - 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, - 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, - 0x4d, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x1c, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, - 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, - 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x78, 0x0a, 0x15, 0x53, - 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, - 0x6d, 0x65, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x16, 0x0a, - 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, - 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x22, 0x7f, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, - 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x61, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, - 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, - 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x7f, 0x0a, 0x16, 0x53, 0x65, 0x74, - 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x85, 0x01, 0x0a, 0x13, 0x53, - 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, - 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x22, 0x7d, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, - 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x22, 0x6f, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, 0x6f, - 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, - 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x22, 0x81, 0x01, 0x0a, 0x18, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, - 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x7d, 0x0a, 0x0f, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, - 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, - 0x6d, 0x75, 0x74, 0x65, 0x64, 0x22, 0x79, 0x0a, 0x10, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, - 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, - 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, - 0x22, 0x67, 0x0a, 0x0f, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, - 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x79, 0x0a, 0x10, 0x4b, 0x69, 0x63, - 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, + 0x6f, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x48, + 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, + 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, + 0x22, 0x81, 0x01, 0x0a, 0x18, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, 0x6f, + 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, - 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x68, 0x0a, 0x10, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x7a, - 0x0a, 0x11, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x9f, 0x01, 0x0a, 0x0f, 0x53, - 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, - 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, - 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, - 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xfa, 0x01, 0x0a, - 0x10, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x7d, 0x0a, 0x0f, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, + 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, + 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, 0x75, + 0x74, 0x65, 0x64, 0x22, 0x79, 0x0a, 0x10, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, + 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, + 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x67, + 0x0a, 0x0f, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, + 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x79, 0x0a, 0x10, 0x4b, 0x69, 0x63, 0x6b, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, + 0x6f, 0x6d, 0x22, 0x68, 0x0a, 0x10, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x7a, 0x0a, 0x11, + 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, - 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, 0x65, - 0x69, 0x70, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x68, 0x65, - 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x48, 0x65, - 0x61, 0x74, 0x12, 0x34, 0x0a, 0x09, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, - 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, - 0x67, 0x69, 0x66, 0x74, 0x52, 0x61, 0x6e, 0x6b, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x6a, 0x0a, 0x1b, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, - 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, - 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, - 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x73, 0x0a, 0x1c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, - 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, - 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, - 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xa6, 0x01, 0x0a, 0x19, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, - 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, - 0x63, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, - 0x6f, 0x64, 0x65, 0x22, 0x71, 0x0a, 0x1a, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, - 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, - 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xea, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, - 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x76, - 0x69, 0x65, 0x77, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76, 0x69, - 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x10, 0x0a, - 0x03, 0x74, 0x61, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x62, 0x12, - 0x16, 0x0a, 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, - 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x74, 0x65, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x22, 0x0a, - 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x04, 0x68, 0x65, 0x61, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6e, - 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, - 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, - 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x63, 0x63, 0x75, - 0x70, 0x69, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x63, 0x63, 0x75, 0x70, 0x69, 0x65, 0x64, 0x53, - 0x65, 0x61, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, - 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, - 0x22, 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, 0x72, - 0x74, 0x49, 0x64, 0x22, 0x67, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x6d, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, - 0x65, 0x78, 0x74, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x32, 0x92, 0x0a, 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, 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, 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, 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, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x9f, 0x01, 0x0a, 0x0f, 0x53, 0x65, 0x6e, + 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, + 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, + 0x69, 0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x09, 0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xfa, 0x01, 0x0a, 0x10, 0x53, + 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, + 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, + 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x68, 0x65, 0x61, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x74, + 0x12, 0x34, 0x0a, 0x09, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, 0x6e, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x67, 0x69, + 0x66, 0x74, 0x52, 0x61, 0x6e, 0x6b, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x6a, 0x0a, 0x1b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 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, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, + 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, + 0x6f, 0x64, 0x65, 0x22, 0x73, 0x0a, 0x1c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, + 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, + 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xa6, 0x01, 0x0a, 0x19, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, + 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, + 0x65, 0x22, 0x71, 0x0a, 0x1a, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xea, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, + 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, + 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x76, 0x69, 0x65, + 0x77, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69, + 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x74, + 0x61, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x62, 0x12, 0x16, 0x0a, + 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, + 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x22, 0xbd, 0x03, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, + 0x65, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, + 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x20, 0x0a, 0x0c, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x55, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, + 0x68, 0x65, 0x61, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6e, 0x6c, 0x69, + 0x6e, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x74, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x65, 0x61, + 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x63, 0x63, 0x75, 0x70, 0x69, + 0x65, 0x64, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x63, 0x63, 0x75, 0x70, 0x69, 0x65, 0x64, 0x53, 0x65, 0x61, + 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, + 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0d, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x0a, + 0x0d, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x49, + 0x64, 0x22, 0x67, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, + 0x65, 0x6d, 0x52, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x6e, 0x65, 0x78, 0x74, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x32, 0xca, 0x0b, 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, 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, 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, + 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, } var ( @@ -3667,7 +3994,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, 44) +var file_proto_room_v1_room_proto_msgTypes = make([]protoimpl.MessageInfo, 48) var file_proto_room_v1_room_proto_goTypes = []any{ (*RequestMeta)(nil), // 0: hyapp.room.v1.RequestMeta (*CommandResult)(nil), // 1: hyapp.room.v1.CommandResult @@ -3679,46 +4006,50 @@ var file_proto_room_v1_room_proto_goTypes = []any{ (*CreateRoomResponse)(nil), // 7: hyapp.room.v1.CreateRoomResponse (*JoinRoomRequest)(nil), // 8: hyapp.room.v1.JoinRoomRequest (*JoinRoomResponse)(nil), // 9: hyapp.room.v1.JoinRoomResponse - (*LeaveRoomRequest)(nil), // 10: hyapp.room.v1.LeaveRoomRequest - (*LeaveRoomResponse)(nil), // 11: hyapp.room.v1.LeaveRoomResponse - (*MicUpRequest)(nil), // 12: hyapp.room.v1.MicUpRequest - (*MicUpResponse)(nil), // 13: hyapp.room.v1.MicUpResponse - (*MicDownRequest)(nil), // 14: hyapp.room.v1.MicDownRequest - (*MicDownResponse)(nil), // 15: hyapp.room.v1.MicDownResponse - (*ChangeMicSeatRequest)(nil), // 16: hyapp.room.v1.ChangeMicSeatRequest - (*ChangeMicSeatResponse)(nil), // 17: hyapp.room.v1.ChangeMicSeatResponse - (*ConfirmMicPublishingRequest)(nil), // 18: hyapp.room.v1.ConfirmMicPublishingRequest - (*ConfirmMicPublishingResponse)(nil), // 19: hyapp.room.v1.ConfirmMicPublishingResponse - (*SetMicSeatLockRequest)(nil), // 20: hyapp.room.v1.SetMicSeatLockRequest - (*SetMicSeatLockResponse)(nil), // 21: hyapp.room.v1.SetMicSeatLockResponse - (*SetChatEnabledRequest)(nil), // 22: hyapp.room.v1.SetChatEnabledRequest - (*SetChatEnabledResponse)(nil), // 23: hyapp.room.v1.SetChatEnabledResponse - (*SetRoomAdminRequest)(nil), // 24: hyapp.room.v1.SetRoomAdminRequest - (*SetRoomAdminResponse)(nil), // 25: hyapp.room.v1.SetRoomAdminResponse - (*TransferRoomHostRequest)(nil), // 26: hyapp.room.v1.TransferRoomHostRequest - (*TransferRoomHostResponse)(nil), // 27: hyapp.room.v1.TransferRoomHostResponse - (*MuteUserRequest)(nil), // 28: hyapp.room.v1.MuteUserRequest - (*MuteUserResponse)(nil), // 29: hyapp.room.v1.MuteUserResponse - (*KickUserRequest)(nil), // 30: hyapp.room.v1.KickUserRequest - (*KickUserResponse)(nil), // 31: hyapp.room.v1.KickUserResponse - (*UnbanUserRequest)(nil), // 32: hyapp.room.v1.UnbanUserRequest - (*UnbanUserResponse)(nil), // 33: hyapp.room.v1.UnbanUserResponse - (*SendGiftRequest)(nil), // 34: hyapp.room.v1.SendGiftRequest - (*SendGiftResponse)(nil), // 35: hyapp.room.v1.SendGiftResponse - (*CheckSpeakPermissionRequest)(nil), // 36: hyapp.room.v1.CheckSpeakPermissionRequest - (*CheckSpeakPermissionResponse)(nil), // 37: hyapp.room.v1.CheckSpeakPermissionResponse - (*VerifyRoomPresenceRequest)(nil), // 38: hyapp.room.v1.VerifyRoomPresenceRequest - (*VerifyRoomPresenceResponse)(nil), // 39: hyapp.room.v1.VerifyRoomPresenceResponse - (*ListRoomsRequest)(nil), // 40: hyapp.room.v1.ListRoomsRequest - (*RoomListItem)(nil), // 41: hyapp.room.v1.RoomListItem - (*ListRoomsResponse)(nil), // 42: hyapp.room.v1.ListRoomsResponse - nil, // 43: hyapp.room.v1.RoomSnapshot.RoomExtEntry + (*RoomHeartbeatRequest)(nil), // 10: hyapp.room.v1.RoomHeartbeatRequest + (*RoomHeartbeatResponse)(nil), // 11: hyapp.room.v1.RoomHeartbeatResponse + (*LeaveRoomRequest)(nil), // 12: hyapp.room.v1.LeaveRoomRequest + (*LeaveRoomResponse)(nil), // 13: hyapp.room.v1.LeaveRoomResponse + (*MicUpRequest)(nil), // 14: hyapp.room.v1.MicUpRequest + (*MicUpResponse)(nil), // 15: hyapp.room.v1.MicUpResponse + (*MicDownRequest)(nil), // 16: hyapp.room.v1.MicDownRequest + (*MicDownResponse)(nil), // 17: hyapp.room.v1.MicDownResponse + (*ChangeMicSeatRequest)(nil), // 18: hyapp.room.v1.ChangeMicSeatRequest + (*ChangeMicSeatResponse)(nil), // 19: hyapp.room.v1.ChangeMicSeatResponse + (*ConfirmMicPublishingRequest)(nil), // 20: hyapp.room.v1.ConfirmMicPublishingRequest + (*ConfirmMicPublishingResponse)(nil), // 21: hyapp.room.v1.ConfirmMicPublishingResponse + (*ApplyRTCEventRequest)(nil), // 22: hyapp.room.v1.ApplyRTCEventRequest + (*ApplyRTCEventResponse)(nil), // 23: hyapp.room.v1.ApplyRTCEventResponse + (*SetMicSeatLockRequest)(nil), // 24: hyapp.room.v1.SetMicSeatLockRequest + (*SetMicSeatLockResponse)(nil), // 25: hyapp.room.v1.SetMicSeatLockResponse + (*SetChatEnabledRequest)(nil), // 26: hyapp.room.v1.SetChatEnabledRequest + (*SetChatEnabledResponse)(nil), // 27: hyapp.room.v1.SetChatEnabledResponse + (*SetRoomAdminRequest)(nil), // 28: hyapp.room.v1.SetRoomAdminRequest + (*SetRoomAdminResponse)(nil), // 29: hyapp.room.v1.SetRoomAdminResponse + (*TransferRoomHostRequest)(nil), // 30: hyapp.room.v1.TransferRoomHostRequest + (*TransferRoomHostResponse)(nil), // 31: hyapp.room.v1.TransferRoomHostResponse + (*MuteUserRequest)(nil), // 32: hyapp.room.v1.MuteUserRequest + (*MuteUserResponse)(nil), // 33: hyapp.room.v1.MuteUserResponse + (*KickUserRequest)(nil), // 34: hyapp.room.v1.KickUserRequest + (*KickUserResponse)(nil), // 35: hyapp.room.v1.KickUserResponse + (*UnbanUserRequest)(nil), // 36: hyapp.room.v1.UnbanUserRequest + (*UnbanUserResponse)(nil), // 37: hyapp.room.v1.UnbanUserResponse + (*SendGiftRequest)(nil), // 38: hyapp.room.v1.SendGiftRequest + (*SendGiftResponse)(nil), // 39: hyapp.room.v1.SendGiftResponse + (*CheckSpeakPermissionRequest)(nil), // 40: hyapp.room.v1.CheckSpeakPermissionRequest + (*CheckSpeakPermissionResponse)(nil), // 41: hyapp.room.v1.CheckSpeakPermissionResponse + (*VerifyRoomPresenceRequest)(nil), // 42: hyapp.room.v1.VerifyRoomPresenceRequest + (*VerifyRoomPresenceResponse)(nil), // 43: hyapp.room.v1.VerifyRoomPresenceResponse + (*ListRoomsRequest)(nil), // 44: hyapp.room.v1.ListRoomsRequest + (*RoomListItem)(nil), // 45: hyapp.room.v1.RoomListItem + (*ListRoomsResponse)(nil), // 46: hyapp.room.v1.ListRoomsResponse + nil, // 47: 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 - 43, // 3: hyapp.room.v1.RoomSnapshot.room_ext:type_name -> hyapp.room.v1.RoomSnapshot.RoomExtEntry + 47, // 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 @@ -3726,89 +4057,100 @@ var file_proto_room_v1_room_proto_depIdxs = []int32{ 1, // 8: hyapp.room.v1.JoinRoomResponse.result:type_name -> hyapp.room.v1.CommandResult 2, // 9: hyapp.room.v1.JoinRoomResponse.user:type_name -> hyapp.room.v1.RoomUser 5, // 10: hyapp.room.v1.JoinRoomResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 11: hyapp.room.v1.LeaveRoomRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 12: hyapp.room.v1.LeaveRoomResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 13: hyapp.room.v1.LeaveRoomResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 14: hyapp.room.v1.MicUpRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 15: hyapp.room.v1.MicUpResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 16: hyapp.room.v1.MicUpResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 17: hyapp.room.v1.MicDownRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 18: hyapp.room.v1.MicDownResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 19: hyapp.room.v1.MicDownResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 20: hyapp.room.v1.ChangeMicSeatRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 21: hyapp.room.v1.ChangeMicSeatResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 22: hyapp.room.v1.ChangeMicSeatResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 23: hyapp.room.v1.ConfirmMicPublishingRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 24: hyapp.room.v1.ConfirmMicPublishingResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 25: hyapp.room.v1.ConfirmMicPublishingResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 26: hyapp.room.v1.SetMicSeatLockRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 27: hyapp.room.v1.SetMicSeatLockResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 28: hyapp.room.v1.SetMicSeatLockResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 29: hyapp.room.v1.SetChatEnabledRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 30: hyapp.room.v1.SetChatEnabledResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 31: hyapp.room.v1.SetChatEnabledResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 32: hyapp.room.v1.SetRoomAdminRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 33: hyapp.room.v1.SetRoomAdminResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 34: hyapp.room.v1.SetRoomAdminResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 35: hyapp.room.v1.TransferRoomHostRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 36: hyapp.room.v1.TransferRoomHostResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 37: hyapp.room.v1.TransferRoomHostResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 38: hyapp.room.v1.MuteUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 39: hyapp.room.v1.MuteUserResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 40: hyapp.room.v1.MuteUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 41: hyapp.room.v1.KickUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 42: hyapp.room.v1.KickUserResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 43: hyapp.room.v1.KickUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 44: hyapp.room.v1.UnbanUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 45: hyapp.room.v1.UnbanUserResponse.result:type_name -> hyapp.room.v1.CommandResult - 5, // 46: hyapp.room.v1.UnbanUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 47: hyapp.room.v1.SendGiftRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 1, // 48: hyapp.room.v1.SendGiftResponse.result:type_name -> hyapp.room.v1.CommandResult - 4, // 49: hyapp.room.v1.SendGiftResponse.gift_rank:type_name -> hyapp.room.v1.RankItem - 5, // 50: hyapp.room.v1.SendGiftResponse.room:type_name -> hyapp.room.v1.RoomSnapshot - 0, // 51: hyapp.room.v1.ListRoomsRequest.meta:type_name -> hyapp.room.v1.RequestMeta - 41, // 52: hyapp.room.v1.ListRoomsResponse.rooms:type_name -> hyapp.room.v1.RoomListItem - 6, // 53: hyapp.room.v1.RoomCommandService.CreateRoom:input_type -> hyapp.room.v1.CreateRoomRequest - 8, // 54: hyapp.room.v1.RoomCommandService.JoinRoom:input_type -> hyapp.room.v1.JoinRoomRequest - 10, // 55: hyapp.room.v1.RoomCommandService.LeaveRoom:input_type -> hyapp.room.v1.LeaveRoomRequest - 12, // 56: hyapp.room.v1.RoomCommandService.MicUp:input_type -> hyapp.room.v1.MicUpRequest - 14, // 57: hyapp.room.v1.RoomCommandService.MicDown:input_type -> hyapp.room.v1.MicDownRequest - 16, // 58: hyapp.room.v1.RoomCommandService.ChangeMicSeat:input_type -> hyapp.room.v1.ChangeMicSeatRequest - 18, // 59: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:input_type -> hyapp.room.v1.ConfirmMicPublishingRequest - 20, // 60: hyapp.room.v1.RoomCommandService.SetMicSeatLock:input_type -> hyapp.room.v1.SetMicSeatLockRequest - 22, // 61: hyapp.room.v1.RoomCommandService.SetChatEnabled:input_type -> hyapp.room.v1.SetChatEnabledRequest - 24, // 62: hyapp.room.v1.RoomCommandService.SetRoomAdmin:input_type -> hyapp.room.v1.SetRoomAdminRequest - 26, // 63: hyapp.room.v1.RoomCommandService.TransferRoomHost:input_type -> hyapp.room.v1.TransferRoomHostRequest - 28, // 64: hyapp.room.v1.RoomCommandService.MuteUser:input_type -> hyapp.room.v1.MuteUserRequest - 30, // 65: hyapp.room.v1.RoomCommandService.KickUser:input_type -> hyapp.room.v1.KickUserRequest - 32, // 66: hyapp.room.v1.RoomCommandService.UnbanUser:input_type -> hyapp.room.v1.UnbanUserRequest - 34, // 67: hyapp.room.v1.RoomCommandService.SendGift:input_type -> hyapp.room.v1.SendGiftRequest - 36, // 68: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:input_type -> hyapp.room.v1.CheckSpeakPermissionRequest - 38, // 69: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:input_type -> hyapp.room.v1.VerifyRoomPresenceRequest - 40, // 70: hyapp.room.v1.RoomQueryService.ListRooms:input_type -> hyapp.room.v1.ListRoomsRequest - 7, // 71: hyapp.room.v1.RoomCommandService.CreateRoom:output_type -> hyapp.room.v1.CreateRoomResponse - 9, // 72: hyapp.room.v1.RoomCommandService.JoinRoom:output_type -> hyapp.room.v1.JoinRoomResponse - 11, // 73: hyapp.room.v1.RoomCommandService.LeaveRoom:output_type -> hyapp.room.v1.LeaveRoomResponse - 13, // 74: hyapp.room.v1.RoomCommandService.MicUp:output_type -> hyapp.room.v1.MicUpResponse - 15, // 75: hyapp.room.v1.RoomCommandService.MicDown:output_type -> hyapp.room.v1.MicDownResponse - 17, // 76: hyapp.room.v1.RoomCommandService.ChangeMicSeat:output_type -> hyapp.room.v1.ChangeMicSeatResponse - 19, // 77: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:output_type -> hyapp.room.v1.ConfirmMicPublishingResponse - 21, // 78: hyapp.room.v1.RoomCommandService.SetMicSeatLock:output_type -> hyapp.room.v1.SetMicSeatLockResponse - 23, // 79: hyapp.room.v1.RoomCommandService.SetChatEnabled:output_type -> hyapp.room.v1.SetChatEnabledResponse - 25, // 80: hyapp.room.v1.RoomCommandService.SetRoomAdmin:output_type -> hyapp.room.v1.SetRoomAdminResponse - 27, // 81: hyapp.room.v1.RoomCommandService.TransferRoomHost:output_type -> hyapp.room.v1.TransferRoomHostResponse - 29, // 82: hyapp.room.v1.RoomCommandService.MuteUser:output_type -> hyapp.room.v1.MuteUserResponse - 31, // 83: hyapp.room.v1.RoomCommandService.KickUser:output_type -> hyapp.room.v1.KickUserResponse - 33, // 84: hyapp.room.v1.RoomCommandService.UnbanUser:output_type -> hyapp.room.v1.UnbanUserResponse - 35, // 85: hyapp.room.v1.RoomCommandService.SendGift:output_type -> hyapp.room.v1.SendGiftResponse - 37, // 86: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:output_type -> hyapp.room.v1.CheckSpeakPermissionResponse - 39, // 87: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:output_type -> hyapp.room.v1.VerifyRoomPresenceResponse - 42, // 88: hyapp.room.v1.RoomQueryService.ListRooms:output_type -> hyapp.room.v1.ListRoomsResponse - 71, // [71:89] is the sub-list for method output_type - 53, // [53:71] is the sub-list for method input_type - 53, // [53:53] is the sub-list for extension type_name - 53, // [53:53] is the sub-list for extension extendee - 0, // [0:53] is the sub-list for field type_name + 0, // 11: hyapp.room.v1.RoomHeartbeatRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 12: hyapp.room.v1.RoomHeartbeatResponse.result:type_name -> hyapp.room.v1.CommandResult + 2, // 13: hyapp.room.v1.RoomHeartbeatResponse.user:type_name -> hyapp.room.v1.RoomUser + 5, // 14: hyapp.room.v1.RoomHeartbeatResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 15: hyapp.room.v1.LeaveRoomRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 16: hyapp.room.v1.LeaveRoomResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 17: hyapp.room.v1.LeaveRoomResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 18: hyapp.room.v1.MicUpRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 19: hyapp.room.v1.MicUpResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 20: hyapp.room.v1.MicUpResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 21: hyapp.room.v1.MicDownRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 22: hyapp.room.v1.MicDownResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 23: hyapp.room.v1.MicDownResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 24: hyapp.room.v1.ChangeMicSeatRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 25: hyapp.room.v1.ChangeMicSeatResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 26: hyapp.room.v1.ChangeMicSeatResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 27: hyapp.room.v1.ConfirmMicPublishingRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 28: hyapp.room.v1.ConfirmMicPublishingResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 29: hyapp.room.v1.ConfirmMicPublishingResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 30: hyapp.room.v1.ApplyRTCEventRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 31: hyapp.room.v1.ApplyRTCEventResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 32: hyapp.room.v1.ApplyRTCEventResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 33: hyapp.room.v1.SetMicSeatLockRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 34: hyapp.room.v1.SetMicSeatLockResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 35: hyapp.room.v1.SetMicSeatLockResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 36: hyapp.room.v1.SetChatEnabledRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 37: hyapp.room.v1.SetChatEnabledResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 38: hyapp.room.v1.SetChatEnabledResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 39: hyapp.room.v1.SetRoomAdminRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 40: hyapp.room.v1.SetRoomAdminResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 41: hyapp.room.v1.SetRoomAdminResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 42: hyapp.room.v1.TransferRoomHostRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 43: hyapp.room.v1.TransferRoomHostResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 44: hyapp.room.v1.TransferRoomHostResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 45: hyapp.room.v1.MuteUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 46: hyapp.room.v1.MuteUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 47: hyapp.room.v1.MuteUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 48: hyapp.room.v1.KickUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 49: hyapp.room.v1.KickUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 50: hyapp.room.v1.KickUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 51: hyapp.room.v1.UnbanUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 52: hyapp.room.v1.UnbanUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 53: hyapp.room.v1.UnbanUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 54: hyapp.room.v1.SendGiftRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 55: hyapp.room.v1.SendGiftResponse.result:type_name -> hyapp.room.v1.CommandResult + 4, // 56: hyapp.room.v1.SendGiftResponse.gift_rank:type_name -> hyapp.room.v1.RankItem + 5, // 57: hyapp.room.v1.SendGiftResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 58: hyapp.room.v1.ListRoomsRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 45, // 59: hyapp.room.v1.ListRoomsResponse.rooms:type_name -> hyapp.room.v1.RoomListItem + 6, // 60: hyapp.room.v1.RoomCommandService.CreateRoom:input_type -> hyapp.room.v1.CreateRoomRequest + 8, // 61: hyapp.room.v1.RoomCommandService.JoinRoom:input_type -> hyapp.room.v1.JoinRoomRequest + 10, // 62: hyapp.room.v1.RoomCommandService.RoomHeartbeat:input_type -> hyapp.room.v1.RoomHeartbeatRequest + 12, // 63: hyapp.room.v1.RoomCommandService.LeaveRoom:input_type -> hyapp.room.v1.LeaveRoomRequest + 14, // 64: hyapp.room.v1.RoomCommandService.MicUp:input_type -> hyapp.room.v1.MicUpRequest + 16, // 65: hyapp.room.v1.RoomCommandService.MicDown:input_type -> hyapp.room.v1.MicDownRequest + 18, // 66: hyapp.room.v1.RoomCommandService.ChangeMicSeat:input_type -> hyapp.room.v1.ChangeMicSeatRequest + 20, // 67: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:input_type -> hyapp.room.v1.ConfirmMicPublishingRequest + 22, // 68: hyapp.room.v1.RoomCommandService.ApplyRTCEvent:input_type -> hyapp.room.v1.ApplyRTCEventRequest + 24, // 69: hyapp.room.v1.RoomCommandService.SetMicSeatLock:input_type -> hyapp.room.v1.SetMicSeatLockRequest + 26, // 70: hyapp.room.v1.RoomCommandService.SetChatEnabled:input_type -> hyapp.room.v1.SetChatEnabledRequest + 28, // 71: hyapp.room.v1.RoomCommandService.SetRoomAdmin:input_type -> hyapp.room.v1.SetRoomAdminRequest + 30, // 72: hyapp.room.v1.RoomCommandService.TransferRoomHost:input_type -> hyapp.room.v1.TransferRoomHostRequest + 32, // 73: hyapp.room.v1.RoomCommandService.MuteUser:input_type -> hyapp.room.v1.MuteUserRequest + 34, // 74: hyapp.room.v1.RoomCommandService.KickUser:input_type -> hyapp.room.v1.KickUserRequest + 36, // 75: hyapp.room.v1.RoomCommandService.UnbanUser:input_type -> hyapp.room.v1.UnbanUserRequest + 38, // 76: hyapp.room.v1.RoomCommandService.SendGift:input_type -> hyapp.room.v1.SendGiftRequest + 40, // 77: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:input_type -> hyapp.room.v1.CheckSpeakPermissionRequest + 42, // 78: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:input_type -> hyapp.room.v1.VerifyRoomPresenceRequest + 44, // 79: hyapp.room.v1.RoomQueryService.ListRooms:input_type -> hyapp.room.v1.ListRoomsRequest + 7, // 80: hyapp.room.v1.RoomCommandService.CreateRoom:output_type -> hyapp.room.v1.CreateRoomResponse + 9, // 81: hyapp.room.v1.RoomCommandService.JoinRoom:output_type -> hyapp.room.v1.JoinRoomResponse + 11, // 82: hyapp.room.v1.RoomCommandService.RoomHeartbeat:output_type -> hyapp.room.v1.RoomHeartbeatResponse + 13, // 83: hyapp.room.v1.RoomCommandService.LeaveRoom:output_type -> hyapp.room.v1.LeaveRoomResponse + 15, // 84: hyapp.room.v1.RoomCommandService.MicUp:output_type -> hyapp.room.v1.MicUpResponse + 17, // 85: hyapp.room.v1.RoomCommandService.MicDown:output_type -> hyapp.room.v1.MicDownResponse + 19, // 86: hyapp.room.v1.RoomCommandService.ChangeMicSeat:output_type -> hyapp.room.v1.ChangeMicSeatResponse + 21, // 87: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:output_type -> hyapp.room.v1.ConfirmMicPublishingResponse + 23, // 88: hyapp.room.v1.RoomCommandService.ApplyRTCEvent:output_type -> hyapp.room.v1.ApplyRTCEventResponse + 25, // 89: hyapp.room.v1.RoomCommandService.SetMicSeatLock:output_type -> hyapp.room.v1.SetMicSeatLockResponse + 27, // 90: hyapp.room.v1.RoomCommandService.SetChatEnabled:output_type -> hyapp.room.v1.SetChatEnabledResponse + 29, // 91: hyapp.room.v1.RoomCommandService.SetRoomAdmin:output_type -> hyapp.room.v1.SetRoomAdminResponse + 31, // 92: hyapp.room.v1.RoomCommandService.TransferRoomHost:output_type -> hyapp.room.v1.TransferRoomHostResponse + 33, // 93: hyapp.room.v1.RoomCommandService.MuteUser:output_type -> hyapp.room.v1.MuteUserResponse + 35, // 94: hyapp.room.v1.RoomCommandService.KickUser:output_type -> hyapp.room.v1.KickUserResponse + 37, // 95: hyapp.room.v1.RoomCommandService.UnbanUser:output_type -> hyapp.room.v1.UnbanUserResponse + 39, // 96: hyapp.room.v1.RoomCommandService.SendGift:output_type -> hyapp.room.v1.SendGiftResponse + 41, // 97: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:output_type -> hyapp.room.v1.CheckSpeakPermissionResponse + 43, // 98: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:output_type -> hyapp.room.v1.VerifyRoomPresenceResponse + 46, // 99: hyapp.room.v1.RoomQueryService.ListRooms:output_type -> hyapp.room.v1.ListRoomsResponse + 80, // [80:100] is the sub-list for method output_type + 60, // [60:80] is the sub-list for method input_type + 60, // [60:60] is the sub-list for extension type_name + 60, // [60:60] is the sub-list for extension extendee + 0, // [0:60] is the sub-list for field type_name } func init() { file_proto_room_v1_room_proto_init() } @@ -3938,7 +4280,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*LeaveRoomRequest); i { + switch v := v.(*RoomHeartbeatRequest); i { case 0: return &v.state case 1: @@ -3950,7 +4292,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*LeaveRoomResponse); i { + switch v := v.(*RoomHeartbeatResponse); i { case 0: return &v.state case 1: @@ -3962,7 +4304,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*MicUpRequest); i { + switch v := v.(*LeaveRoomRequest); i { case 0: return &v.state case 1: @@ -3974,7 +4316,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*MicUpResponse); i { + switch v := v.(*LeaveRoomResponse); i { case 0: return &v.state case 1: @@ -3986,7 +4328,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*MicDownRequest); i { + switch v := v.(*MicUpRequest); i { case 0: return &v.state case 1: @@ -3998,7 +4340,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*MicDownResponse); i { + switch v := v.(*MicUpResponse); i { case 0: return &v.state case 1: @@ -4010,7 +4352,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*ChangeMicSeatRequest); i { + switch v := v.(*MicDownRequest); i { case 0: return &v.state case 1: @@ -4022,7 +4364,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*ChangeMicSeatResponse); i { + switch v := v.(*MicDownResponse); i { case 0: return &v.state case 1: @@ -4034,7 +4376,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*ConfirmMicPublishingRequest); i { + switch v := v.(*ChangeMicSeatRequest); i { case 0: return &v.state case 1: @@ -4046,7 +4388,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[19].Exporter = func(v any, i int) any { - switch v := v.(*ConfirmMicPublishingResponse); i { + switch v := v.(*ChangeMicSeatResponse); i { case 0: return &v.state case 1: @@ -4058,7 +4400,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[20].Exporter = func(v any, i int) any { - switch v := v.(*SetMicSeatLockRequest); i { + switch v := v.(*ConfirmMicPublishingRequest); i { case 0: return &v.state case 1: @@ -4070,7 +4412,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[21].Exporter = func(v any, i int) any { - switch v := v.(*SetMicSeatLockResponse); i { + switch v := v.(*ConfirmMicPublishingResponse); i { case 0: return &v.state case 1: @@ -4082,7 +4424,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[22].Exporter = func(v any, i int) any { - switch v := v.(*SetChatEnabledRequest); i { + switch v := v.(*ApplyRTCEventRequest); i { case 0: return &v.state case 1: @@ -4094,7 +4436,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[23].Exporter = func(v any, i int) any { - switch v := v.(*SetChatEnabledResponse); i { + switch v := v.(*ApplyRTCEventResponse); i { case 0: return &v.state case 1: @@ -4106,7 +4448,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[24].Exporter = func(v any, i int) any { - switch v := v.(*SetRoomAdminRequest); i { + switch v := v.(*SetMicSeatLockRequest); i { case 0: return &v.state case 1: @@ -4118,7 +4460,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[25].Exporter = func(v any, i int) any { - switch v := v.(*SetRoomAdminResponse); i { + switch v := v.(*SetMicSeatLockResponse); i { case 0: return &v.state case 1: @@ -4130,7 +4472,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[26].Exporter = func(v any, i int) any { - switch v := v.(*TransferRoomHostRequest); i { + switch v := v.(*SetChatEnabledRequest); i { case 0: return &v.state case 1: @@ -4142,7 +4484,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[27].Exporter = func(v any, i int) any { - switch v := v.(*TransferRoomHostResponse); i { + switch v := v.(*SetChatEnabledResponse); i { case 0: return &v.state case 1: @@ -4154,7 +4496,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[28].Exporter = func(v any, i int) any { - switch v := v.(*MuteUserRequest); i { + switch v := v.(*SetRoomAdminRequest); i { case 0: return &v.state case 1: @@ -4166,7 +4508,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[29].Exporter = func(v any, i int) any { - switch v := v.(*MuteUserResponse); i { + switch v := v.(*SetRoomAdminResponse); i { case 0: return &v.state case 1: @@ -4178,7 +4520,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[30].Exporter = func(v any, i int) any { - switch v := v.(*KickUserRequest); i { + switch v := v.(*TransferRoomHostRequest); i { case 0: return &v.state case 1: @@ -4190,7 +4532,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[31].Exporter = func(v any, i int) any { - switch v := v.(*KickUserResponse); i { + switch v := v.(*TransferRoomHostResponse); i { case 0: return &v.state case 1: @@ -4202,7 +4544,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[32].Exporter = func(v any, i int) any { - switch v := v.(*UnbanUserRequest); i { + switch v := v.(*MuteUserRequest); i { case 0: return &v.state case 1: @@ -4214,7 +4556,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[33].Exporter = func(v any, i int) any { - switch v := v.(*UnbanUserResponse); i { + switch v := v.(*MuteUserResponse); i { case 0: return &v.state case 1: @@ -4226,7 +4568,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[34].Exporter = func(v any, i int) any { - switch v := v.(*SendGiftRequest); i { + switch v := v.(*KickUserRequest); i { case 0: return &v.state case 1: @@ -4238,7 +4580,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[35].Exporter = func(v any, i int) any { - switch v := v.(*SendGiftResponse); i { + switch v := v.(*KickUserResponse); i { case 0: return &v.state case 1: @@ -4250,7 +4592,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[36].Exporter = func(v any, i int) any { - switch v := v.(*CheckSpeakPermissionRequest); i { + switch v := v.(*UnbanUserRequest); i { case 0: return &v.state case 1: @@ -4262,7 +4604,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[37].Exporter = func(v any, i int) any { - switch v := v.(*CheckSpeakPermissionResponse); i { + switch v := v.(*UnbanUserResponse); i { case 0: return &v.state case 1: @@ -4274,7 +4616,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[38].Exporter = func(v any, i int) any { - switch v := v.(*VerifyRoomPresenceRequest); i { + switch v := v.(*SendGiftRequest); i { case 0: return &v.state case 1: @@ -4286,7 +4628,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[39].Exporter = func(v any, i int) any { - switch v := v.(*VerifyRoomPresenceResponse); i { + switch v := v.(*SendGiftResponse); i { case 0: return &v.state case 1: @@ -4298,7 +4640,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[40].Exporter = func(v any, i int) any { - switch v := v.(*ListRoomsRequest); i { + switch v := v.(*CheckSpeakPermissionRequest); i { case 0: return &v.state case 1: @@ -4310,7 +4652,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[41].Exporter = func(v any, i int) any { - switch v := v.(*RoomListItem); i { + switch v := v.(*CheckSpeakPermissionResponse); i { case 0: return &v.state case 1: @@ -4322,6 +4664,54 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[42].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[43].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[44].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[45].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[46].Exporter = func(v any, i int) any { switch v := v.(*ListRoomsResponse); i { case 0: return &v.state @@ -4340,7 +4730,7 @@ func file_proto_room_v1_room_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_room_v1_room_proto_rawDesc, NumEnums: 0, - NumMessages: 44, + NumMessages: 48, NumExtensions: 0, NumServices: 3, }, diff --git a/api/proto/room/v1/room.proto b/api/proto/room/v1/room.proto index 30732faf..745e8fee 100644 --- a/api/proto/room/v1/room.proto +++ b/api/proto/room/v1/room.proto @@ -120,6 +120,19 @@ message JoinRoomResponse { RoomSnapshot room = 3; } +// RoomHeartbeatRequest 显式刷新已经存在的房间业务 presence。 +// 它不能替代 JoinRoom;用户不在房间时必须拒绝,避免心跳把已离开的用户重新加入房间。 +message RoomHeartbeatRequest { + RequestMeta meta = 1; +} + +// RoomHeartbeatResponse 返回刷新后的用户 presence 和房间快照。 +message RoomHeartbeatResponse { + CommandResult result = 1; + RoomUser user = 2; + RoomSnapshot room = 3; +} + // LeaveRoomRequest 把用户从房间 presence 移出。 message LeaveRoomRequest { RequestMeta meta = 1; @@ -193,6 +206,25 @@ message ConfirmMicPublishingResponse { RoomSnapshot room = 3; } +// ApplyRTCEventRequest 把可信 RTC 服务端回调转换成 Room Cell 命令。 +// event_type 当前只接受 audio_started、audio_stopped、room_exited。 +message ApplyRTCEventRequest { + RequestMeta meta = 1; + int64 target_user_id = 2; + string event_type = 3; + int64 event_time_ms = 4; + string reason = 5; + string source = 6; + string external_event_id = 7; +} + +// ApplyRTCEventResponse 返回 RTC 事件落房间状态后的快照。 +message ApplyRTCEventResponse { + CommandResult result = 1; + int32 seat_no = 2; + RoomSnapshot room = 3; +} + // SetMicSeatLockRequest 锁定或解锁指定麦位。 message SetMicSeatLockRequest { RequestMeta meta = 1; @@ -367,11 +399,13 @@ message ListRoomsResponse { service RoomCommandService { rpc CreateRoom(CreateRoomRequest) returns (CreateRoomResponse); rpc JoinRoom(JoinRoomRequest) returns (JoinRoomResponse); + rpc RoomHeartbeat(RoomHeartbeatRequest) returns (RoomHeartbeatResponse); rpc LeaveRoom(LeaveRoomRequest) returns (LeaveRoomResponse); rpc MicUp(MicUpRequest) returns (MicUpResponse); rpc MicDown(MicDownRequest) returns (MicDownResponse); rpc ChangeMicSeat(ChangeMicSeatRequest) returns (ChangeMicSeatResponse); rpc ConfirmMicPublishing(ConfirmMicPublishingRequest) returns (ConfirmMicPublishingResponse); + rpc ApplyRTCEvent(ApplyRTCEventRequest) returns (ApplyRTCEventResponse); rpc SetMicSeatLock(SetMicSeatLockRequest) returns (SetMicSeatLockResponse); rpc SetChatEnabled(SetChatEnabledRequest) returns (SetChatEnabledResponse); rpc SetRoomAdmin(SetRoomAdminRequest) returns (SetRoomAdminResponse); diff --git a/api/proto/room/v1/room_grpc.pb.go b/api/proto/room/v1/room_grpc.pb.go index 4a4f12a9..9a65920c 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 v5.29.2 +// - protoc v7.34.1 // source: proto/room/v1/room.proto package roomv1 @@ -21,11 +21,13 @@ const _ = grpc.SupportPackageIsVersion9 const ( RoomCommandService_CreateRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/CreateRoom" RoomCommandService_JoinRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/JoinRoom" + RoomCommandService_RoomHeartbeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/RoomHeartbeat" RoomCommandService_LeaveRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/LeaveRoom" RoomCommandService_MicUp_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicUp" RoomCommandService_MicDown_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicDown" RoomCommandService_ChangeMicSeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/ChangeMicSeat" RoomCommandService_ConfirmMicPublishing_FullMethodName = "/hyapp.room.v1.RoomCommandService/ConfirmMicPublishing" + RoomCommandService_ApplyRTCEvent_FullMethodName = "/hyapp.room.v1.RoomCommandService/ApplyRTCEvent" RoomCommandService_SetMicSeatLock_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetMicSeatLock" RoomCommandService_SetChatEnabled_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetChatEnabled" RoomCommandService_SetRoomAdmin_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetRoomAdmin" @@ -44,11 +46,13 @@ const ( type RoomCommandServiceClient interface { CreateRoom(ctx context.Context, in *CreateRoomRequest, opts ...grpc.CallOption) (*CreateRoomResponse, error) JoinRoom(ctx context.Context, in *JoinRoomRequest, opts ...grpc.CallOption) (*JoinRoomResponse, error) + RoomHeartbeat(ctx context.Context, in *RoomHeartbeatRequest, opts ...grpc.CallOption) (*RoomHeartbeatResponse, error) LeaveRoom(ctx context.Context, in *LeaveRoomRequest, opts ...grpc.CallOption) (*LeaveRoomResponse, error) MicUp(ctx context.Context, in *MicUpRequest, opts ...grpc.CallOption) (*MicUpResponse, error) MicDown(ctx context.Context, in *MicDownRequest, opts ...grpc.CallOption) (*MicDownResponse, error) ChangeMicSeat(ctx context.Context, in *ChangeMicSeatRequest, opts ...grpc.CallOption) (*ChangeMicSeatResponse, error) ConfirmMicPublishing(ctx context.Context, in *ConfirmMicPublishingRequest, opts ...grpc.CallOption) (*ConfirmMicPublishingResponse, error) + ApplyRTCEvent(ctx context.Context, in *ApplyRTCEventRequest, opts ...grpc.CallOption) (*ApplyRTCEventResponse, error) SetMicSeatLock(ctx context.Context, in *SetMicSeatLockRequest, opts ...grpc.CallOption) (*SetMicSeatLockResponse, error) SetChatEnabled(ctx context.Context, in *SetChatEnabledRequest, opts ...grpc.CallOption) (*SetChatEnabledResponse, error) SetRoomAdmin(ctx context.Context, in *SetRoomAdminRequest, opts ...grpc.CallOption) (*SetRoomAdminResponse, error) @@ -87,6 +91,16 @@ func (c *roomCommandServiceClient) JoinRoom(ctx context.Context, in *JoinRoomReq return out, nil } +func (c *roomCommandServiceClient) RoomHeartbeat(ctx context.Context, in *RoomHeartbeatRequest, opts ...grpc.CallOption) (*RoomHeartbeatResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RoomHeartbeatResponse) + err := c.cc.Invoke(ctx, RoomCommandService_RoomHeartbeat_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *roomCommandServiceClient) LeaveRoom(ctx context.Context, in *LeaveRoomRequest, opts ...grpc.CallOption) (*LeaveRoomResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(LeaveRoomResponse) @@ -137,6 +151,16 @@ func (c *roomCommandServiceClient) ConfirmMicPublishing(ctx context.Context, in return out, nil } +func (c *roomCommandServiceClient) ApplyRTCEvent(ctx context.Context, in *ApplyRTCEventRequest, opts ...grpc.CallOption) (*ApplyRTCEventResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ApplyRTCEventResponse) + err := c.cc.Invoke(ctx, RoomCommandService_ApplyRTCEvent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *roomCommandServiceClient) SetMicSeatLock(ctx context.Context, in *SetMicSeatLockRequest, opts ...grpc.CallOption) (*SetMicSeatLockResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(SetMicSeatLockResponse) @@ -225,11 +249,13 @@ func (c *roomCommandServiceClient) SendGift(ctx context.Context, in *SendGiftReq type RoomCommandServiceServer interface { CreateRoom(context.Context, *CreateRoomRequest) (*CreateRoomResponse, error) JoinRoom(context.Context, *JoinRoomRequest) (*JoinRoomResponse, error) + RoomHeartbeat(context.Context, *RoomHeartbeatRequest) (*RoomHeartbeatResponse, error) LeaveRoom(context.Context, *LeaveRoomRequest) (*LeaveRoomResponse, error) MicUp(context.Context, *MicUpRequest) (*MicUpResponse, error) MicDown(context.Context, *MicDownRequest) (*MicDownResponse, error) ChangeMicSeat(context.Context, *ChangeMicSeatRequest) (*ChangeMicSeatResponse, error) ConfirmMicPublishing(context.Context, *ConfirmMicPublishingRequest) (*ConfirmMicPublishingResponse, error) + ApplyRTCEvent(context.Context, *ApplyRTCEventRequest) (*ApplyRTCEventResponse, error) SetMicSeatLock(context.Context, *SetMicSeatLockRequest) (*SetMicSeatLockResponse, error) SetChatEnabled(context.Context, *SetChatEnabledRequest) (*SetChatEnabledResponse, error) SetRoomAdmin(context.Context, *SetRoomAdminRequest) (*SetRoomAdminResponse, error) @@ -254,6 +280,9 @@ func (UnimplementedRoomCommandServiceServer) CreateRoom(context.Context, *Create func (UnimplementedRoomCommandServiceServer) JoinRoom(context.Context, *JoinRoomRequest) (*JoinRoomResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method JoinRoom not implemented") } +func (UnimplementedRoomCommandServiceServer) RoomHeartbeat(context.Context, *RoomHeartbeatRequest) (*RoomHeartbeatResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RoomHeartbeat not implemented") +} func (UnimplementedRoomCommandServiceServer) LeaveRoom(context.Context, *LeaveRoomRequest) (*LeaveRoomResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method LeaveRoom not implemented") } @@ -269,6 +298,9 @@ func (UnimplementedRoomCommandServiceServer) ChangeMicSeat(context.Context, *Cha func (UnimplementedRoomCommandServiceServer) ConfirmMicPublishing(context.Context, *ConfirmMicPublishingRequest) (*ConfirmMicPublishingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ConfirmMicPublishing not implemented") } +func (UnimplementedRoomCommandServiceServer) ApplyRTCEvent(context.Context, *ApplyRTCEventRequest) (*ApplyRTCEventResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ApplyRTCEvent not implemented") +} func (UnimplementedRoomCommandServiceServer) SetMicSeatLock(context.Context, *SetMicSeatLockRequest) (*SetMicSeatLockResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SetMicSeatLock not implemented") } @@ -350,6 +382,24 @@ func _RoomCommandService_JoinRoom_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _RoomCommandService_RoomHeartbeat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RoomHeartbeatRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoomCommandServiceServer).RoomHeartbeat(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RoomCommandService_RoomHeartbeat_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoomCommandServiceServer).RoomHeartbeat(ctx, req.(*RoomHeartbeatRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _RoomCommandService_LeaveRoom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(LeaveRoomRequest) if err := dec(in); err != nil { @@ -440,6 +490,24 @@ func _RoomCommandService_ConfirmMicPublishing_Handler(srv interface{}, ctx conte return interceptor(ctx, in, info, handler) } +func _RoomCommandService_ApplyRTCEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApplyRTCEventRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoomCommandServiceServer).ApplyRTCEvent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RoomCommandService_ApplyRTCEvent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoomCommandServiceServer).ApplyRTCEvent(ctx, req.(*ApplyRTCEventRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _RoomCommandService_SetMicSeatLock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SetMicSeatLockRequest) if err := dec(in); err != nil { @@ -599,6 +667,10 @@ var RoomCommandService_ServiceDesc = grpc.ServiceDesc{ MethodName: "JoinRoom", Handler: _RoomCommandService_JoinRoom_Handler, }, + { + MethodName: "RoomHeartbeat", + Handler: _RoomCommandService_RoomHeartbeat_Handler, + }, { MethodName: "LeaveRoom", Handler: _RoomCommandService_LeaveRoom_Handler, @@ -619,6 +691,10 @@ var RoomCommandService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ConfirmMicPublishing", Handler: _RoomCommandService_ConfirmMicPublishing_Handler, }, + { + MethodName: "ApplyRTCEvent", + Handler: _RoomCommandService_ApplyRTCEvent_Handler, + }, { MethodName: "SetMicSeatLock", Handler: _RoomCommandService_SetMicSeatLock_Handler, diff --git a/docs/auth-login-register-technical-design.md b/docs/auth-login-register-technical-design.md index 166c9bf9..fad324e1 100644 --- a/docs/auth-login-register-technical-design.md +++ b/docs/auth-login-register-technical-design.md @@ -399,19 +399,21 @@ gateway 是 profile gate 的外部入口执行点。为了避免每个业务请 ### Password Login ```text -POST /api/v1/auth/password/login +POST /api/v1/auth/account/login ``` Request: ```json { - "display_user_id": "163000", + "account": "163000", "password": "plain_password", "device_id": "device_xxx" } ``` +`account` 就是用户当前有效短号。gateway 会统一转成 user-service 的 `LoginPasswordRequest.display_user_id`。 + Response `data`: ```json @@ -433,6 +435,8 @@ Response `data`: 密码登录只接受当前有效 `display_user_id`。如果用户申请了临时靓号,默认短号在靓号有效期内不能用于密码登录;靓号过期后,默认短号恢复登录能力。 +本地联调 initdb 预置测试账号:账号 `123456`,密码 `1234567`;账号 `12345678`,密码 `12345678`。 + ### Refresh Token ```text @@ -846,7 +850,7 @@ sequenceDiagram participant G as gateway-service participant U as user-service - C->>G: POST /api/v1/auth/password/login + C->>G: POST /api/v1/auth/account/login G->>U: LoginPassword(display_user_id, password) U->>U: expire pretty display_user_id if needed U->>U: resolve current display_user_id @@ -930,7 +934,7 @@ gateway HTTP envelope 的 `code` 不使用数字。 | `INVALID_JSON` | 400 | request body is invalid JSON | | `INVALID_ARGUMENT` | 400 | field format or required field invalid | | `RATE_LIMITED` | 429 | public auth rate limit exceeded | -| `AUTH_FAILED` | 401 | display_user_id missing, password wrong, no password set, or provider rejected | +| `AUTH_FAILED` | 401 | account missing, password wrong, no password set, or provider rejected | | `UNAUTHORIZED` | 401 | missing or invalid access token | | `PROFILE_REQUIRED` | 403 | authenticated user has not completed required registration profile | | `PASSWORD_ALREADY_SET` | 409 | user already has password identity | @@ -952,11 +956,11 @@ gateway 对三方注册登录、密码登录、refresh 和 logout 做 Redis 固 | `ip` | third-party, password, refresh, logout | 限制单入口 IP 对 public auth 的总请求量 | | `device_id` | third-party, password, refresh | 限制单设备安装批量注册或刷新 | | `provider + ip` | third-party | 限制单 IP 对同一三方 provider 批量建号 | -| `display_user_id + ip` | password | 限制单 IP 对同一短号喷射尝试 | -| `display_user_id` | password | 限制同一短号被跨 IP 喷射尝试 | +| `account + ip` | password | 限制单 IP 对同一短号喷射尝试 | +| `account` | password | 限制同一短号被跨 IP 喷射尝试 | | `session_id + ip` | logout | 限制 logout 重放 | -Redis backend 使用 Lua 脚本一次性检查并递增同一请求命中的所有维度,避免部分 key 已递增但后续维度超限的非原子状态。公网可控的 provider、device_id、display_user_id、session_id 和入口 IP 在 Redis key 中只保留固定长度摘要,避免超长输入污染 key 空间。`auth_rate_limit.enabled=true` 时 gateway 启动必须连通 Redis;运行期 Redis 调用失败会 fail-closed 返回 HTTP 502 和 `UPSTREAM_ERROR`,避免入口在依赖故障时无保护放量。内存 backend 只用于单元测试或显式关闭 Redis 频控后的本地构造。 +Redis backend 使用 Lua 脚本一次性检查并递增同一请求命中的所有维度,避免部分 key 已递增但后续维度超限的非原子状态。公网可控的 provider、device_id、account、session_id 和入口 IP 在 Redis key 中只保留固定长度摘要,避免超长输入污染 key 空间。`auth_rate_limit.enabled=true` 时 gateway 启动必须连通 Redis;运行期 Redis 调用失败会 fail-closed 返回 HTTP 502 和 `UPSTREAM_ERROR`,避免入口在依赖故障时无保护放量。内存 backend 只用于单元测试或显式关闭 Redis 频控后的本地构造。 ## Security Rules @@ -1009,7 +1013,7 @@ Redis backend 使用 Lua 脚本一次性检查并递增同一请求命中的所 - 三方新用户未设置密码前,短号密码登录返回 `AUTH_FAILED`。 - 已登录用户设置密码成功。 - 重复设置密码返回 `PASSWORD_ALREADY_SET`。 -- 设置密码后可使用当前 `display_user_id + password` 登录。 +- 设置密码后可使用当前 `account + password` 登录。 - 短号不存在和密码错误都返回 `AUTH_FAILED`。 - 用户有 active 靓号时,密码登录必须使用靓号,默认短号返回 `AUTH_FAILED`。 - 靓号过期后,密码登录必须恢复使用默认短号,旧靓号返回 `AUTH_FAILED`。 diff --git a/docs/openapi/gateway.swagger.yaml b/docs/openapi/gateway.swagger.yaml index 22f2571f..0282f05f 100644 --- a/docs/openapi/gateway.swagger.yaml +++ b/docs/openapi/gateway.swagger.yaml @@ -98,6 +98,19 @@ parameters: required: false type: string description: 腾讯云 IM 回调鉴权 token header。 + TencentRTCSDKAppIDHeader: + name: SdkAppId + in: header + required: true + type: integer + format: int64 + description: 腾讯 RTC 事件回调 header 中的 SDKAppID。 + TencentRTCSignHeader: + name: Sign + in: header + required: true + type: string + description: 腾讯 RTC 事件回调签名,计算方式为 `base64(hmacsha256(callback_sign_key, raw_body))`。 responses: BadRequest: description: 请求体不是合法 JSON,或下游返回非法参数;常见 `code` 为 `INVALID_JSON`、`INVALID_ARGUMENT`、`DISPLAY_USER_ID_INVALID`。 @@ -158,12 +171,13 @@ paths: description: Gateway 不应接新请求,失败详情在 `checks`。 schema: $ref: "#/definitions/HealthResponse" - /api/v1/auth/password/login: + /api/v1/auth/account/login: post: tags: - auth - summary: 短号密码登录 - operationId: loginPassword + summary: 账号密码登录 + description: 账号就是用户当前有效短号。 + operationId: loginAccountPassword parameters: - $ref: "#/parameters/RequestIDHeader" - name: body @@ -396,6 +410,46 @@ paths: $ref: "#/definitions/ErrorEnvelope" "502": $ref: "#/responses/UpstreamError" + /api/v1/tencent-rtc/callback: + post: + tags: + - tencent-rtc + summary: 腾讯 RTC 服务端事件回调 + operationId: handleTencentRTCCallback + description: | + 腾讯 RTC 控制台配置的房间/媒体事件回调入口。gateway 校验 `SdkAppId` 与 `Sign` 后,只消费房间退出 `104`、开始推送音频 `203`、停止推送音频 `204`。 + 该接口不使用业务 envelope;成功或可忽略业务错误返回 `{"code":0}`。 + parameters: + - $ref: "#/parameters/RequestIDHeader" + - $ref: "#/parameters/TencentRTCSDKAppIDHeader" + - $ref: "#/parameters/TencentRTCSignHeader" + - name: app_code + in: query + required: false + type: string + description: 多 App 部署时建议把腾讯控制台回调 URL 配置为携带 `app_code`,用于 room-service 租户路由。 + - name: body + in: body + required: true + schema: + $ref: "#/definitions/TencentRTCCallbackRequest" + responses: + "200": + description: 回调已接受,未知事件或不可恢复业务错误也按成功 ACK,避免无意义重试。 + schema: + $ref: "#/definitions/TencentRTCCallbackResponse" + "400": + description: 回调 body 非法。 + schema: + $ref: "#/definitions/TencentRTCCallbackResponse" + "403": + description: SDKAppID 不匹配或签名校验失败。 + schema: + $ref: "#/definitions/TencentRTCCallbackResponse" + "500": + description: room-service 暂时不可用,返回非 200 让腾讯 RTC 按平台策略重试。 + schema: + $ref: "#/definitions/TencentRTCCallbackResponse" /api/v1/files/upload: post: tags: @@ -781,6 +835,41 @@ paths: $ref: "#/responses/Internal" "502": $ref: "#/responses/UpstreamError" + /api/v1/rooms/heartbeat: + post: + tags: + - rooms + summary: 刷新房间业务 presence + operationId: roomHeartbeat + description: 心跳只刷新已经存在的房间 presence;用户不在房间时返回 404,不会隐式 JoinRoom。 + security: + - BearerAuth: [] + parameters: + - $ref: "#/parameters/RequestIDHeader" + - name: body + in: body + required: true + schema: + $ref: "#/definitions/RoomHeartbeatRequest" + responses: + "200": + description: 心跳成功,`data` 返回刷新后的用户房间态和房间快照。 + schema: + $ref: "#/definitions/RoomHeartbeatEnvelope" + "400": + $ref: "#/responses/BadRequest" + "401": + $ref: "#/responses/Unauthorized" + "403": + $ref: "#/responses/Forbidden" + "404": + $ref: "#/responses/NotFound" + "409": + $ref: "#/responses/Conflict" + "500": + $ref: "#/responses/Internal" + "502": + $ref: "#/responses/UpstreamError" /api/v1/rooms/leave: post: tags: @@ -1520,11 +1609,18 @@ definitions: type: string LoginPasswordRequest: type: object + required: + - account + - password + - device_id + description: 账号就是用户当前有效短号。 properties: - display_user_id: + account: type: string + example: "123456" password: type: string + example: "1234567" device_id: type: string LoginThirdPartyRequest: @@ -1786,6 +1882,57 @@ definitions: - 0 - 1 description: 腾讯云 IM 原生回调响应;`ErrorCode=0` 允许,`ErrorCode=1` 拒绝本次入群或发言。 + TencentRTCCallbackRequest: + type: object + properties: + EventGroupId: + type: integer + format: int32 + enum: + - 1 + - 2 + description: 1 为房间事件组,2 为媒体事件组。 + EventType: + type: integer + format: int32 + enum: + - 104 + - 203 + - 204 + description: 当前只消费退出房间、开始推送音频、停止推送音频。 + CallbackTs: + type: integer + format: int64 + EventInfo: + type: object + properties: + RoomId: + description: 腾讯 RTC 房间 ID;本系统要求等于内部字符串 `room_id`。 + UserId: + type: string + description: 腾讯 RTC UserID;必须是内部长 `user_id` 的十进制字符串。 + EventTs: + type: integer + format: int64 + EventMsTs: + type: integer + format: int64 + Reason: + type: integer + format: int32 + description: 腾讯 RTC 原生回调请求;签名必须基于原始 body,不要重新序列化后计算。 + TencentRTCCallbackResponse: + type: object + properties: + code: + type: integer + format: int32 + enum: + - 0 + - 1 + message: + type: string + description: 腾讯 RTC 回调响应;`code=0` 表示 gateway 已接受或安全忽略该事件。 UserIdentityData: type: object properties: @@ -2258,7 +2405,7 @@ definitions: - command_id - amount - reason - description: `target_user_id` 和 `target_display_user_id` 至少传一个;两者都是玩家短 ID/展示号,不是 user-service 内部长 ID。 + description: "`target_user_id` 和 `target_display_user_id` 至少传一个;两者都是玩家短 ID/展示号,不是 user-service 内部长 ID。" properties: command_id: type: string @@ -2359,6 +2506,16 @@ definitions: description: 房间命令幂等键;客户端重试同一业务动作必须复用该值。未传时 gateway 自动生成新值,仅保证本次请求可执行,不保证后续 HTTP 重试幂等。 role: type: string + RoomHeartbeatRequest: + type: object + required: + - room_id + properties: + room_id: + type: string + command_id: + type: string + description: 心跳命令幂等键;建议客户端每次心跳生成新值,HTTP 重试同一次心跳复用该值。 LeaveRoomRequest: type: object properties: @@ -2676,6 +2833,15 @@ definitions: $ref: "#/definitions/RoomUser" room: $ref: "#/definitions/RoomSnapshot" + RoomHeartbeatResponse: + type: object + properties: + result: + $ref: "#/definitions/CommandResult" + user: + $ref: "#/definitions/RoomUser" + room: + $ref: "#/definitions/RoomSnapshot" LeaveRoomResponse: type: object properties: @@ -2923,6 +3089,13 @@ definitions: properties: data: $ref: "#/definitions/JoinRoomResponse" + RoomHeartbeatEnvelope: + allOf: + - $ref: "#/definitions/GatewayOKEnvelopeBase" + - type: object + properties: + data: + $ref: "#/definitions/RoomHeartbeatResponse" LeaveRoomEnvelope: allOf: - $ref: "#/definitions/GatewayOKEnvelopeBase" diff --git a/docs/room-entry-reconnect-development-requirements.md b/docs/room-entry-reconnect-development-requirements.md index b1b960f8..80a62599 100644 --- a/docs/room-entry-reconnect-development-requirements.md +++ b/docs/room-entry-reconnect-development-requirements.md @@ -228,19 +228,21 @@ room_presence_sweep_interval: "30s" | Case | Expected Behavior | | --- | --- | | IM 短断 | room-service presence 保留,客户端重新登录腾讯云 IM 后重新进群 | -| App 退后台后恢复 | 客户端先调用 `JoinRoom` 幂等刷新,再重新登录腾讯云 IM 并进群 | +| App 退后台后恢复 | 客户端先调用 `RoomHeartbeat` 刷新已有 presence;如果返回 `NOT_FOUND` 再重新 `JoinRoom` | | 超过 stale timeout | room-service 自动清理 presence,客户端需要重新进房 | 客户端重连标准流程: ```text 1. 如果 access token 过期,先 RefreshToken -2. 调 POST /api/v1/rooms/join,刷新房间业务 presence +2. 调 POST /api/v1/rooms/heartbeat,刷新房间业务 presence 3. 调 POST /api/v1/im/usersig,拿腾讯云 IM UserSig 4. 使用腾讯云 IM SDK 登录 5. 加入 room_id 对应的腾讯云 IM 群 6. 拉取腾讯云 IM 群历史或等待房间系统消息补齐 -7. 用 JoinRoom 返回的 RoomSnapshot 覆盖本地房间状态 +7. 用 RoomHeartbeat 返回的 RoomSnapshot 覆盖本地房间状态 + +如果第 2 步返回 `NOT_FOUND`,说明业务 presence 已不存在,客户端必须走完整 `JoinRoom -> IM/RTC 重进` 流程。 ``` 服务端原则: @@ -259,7 +261,7 @@ room_presence_sweep_interval: "30s" | `user_id` | 房间内业务用户 | | `role` | owner, host, admin, audience | | `joined_at_ms` | 首次进入当前房间时间 | -| `last_seen_at_ms` | 最近一次 JoinRoom、订阅或心跳时间 | +| `last_seen_at_ms` | 最近一次 JoinRoom 或 RoomHeartbeat 时间 | 建议后续追加: @@ -299,7 +301,7 @@ room_presence_sweep_interval: "30s" | JoinRoom 后进群 | `VerifyRoomPresence` 通过,腾讯云 IM 群收到房间消息 | | 未 JoinRoom 直接进群或发言 | `VerifyRoomPresence` 或 `CheckSpeakPermission` 返回 `not_in_room` | | Kick 后进群或发言 | 返回 `user_banned` | -| IM 断开后 60 秒内重连 | JoinRoom 幂等刷新,腾讯云 IM 重新登录和进群成功,历史可拉 | +| IM 断开后 60 秒内重连 | RoomHeartbeat 刷新,腾讯云 IM 重新登录和进群成功,历史可拉 | | 超过 stale timeout | presence 自动清理,需要重新 JoinRoom | | room-service 重启恢复 | snapshot + command log 恢复后 JoinRoom/subscribe 继续可用 | @@ -309,8 +311,9 @@ room_presence_sweep_interval: "30s" 1. 修正创建房间身份来源:gateway 不接收 body 的 owner/host,room-service 从 `RequestMeta.actor_user_id` 收敛 owner/default host。 2. 补齐 JoinRoom 幂等刷新 `last_seen_at_ms`。 -3. 补齐 LeaveRoom 后对订阅守卫的拒绝行为测试。 -4. 接入腾讯云 IM UserSig 签发、CreateRoom 建群和房间系统消息发布。 -5. 增加 stale presence 清理 worker。 -6. 增加重连集成测试:JoinRoom -> UserSig -> IM login/join group -> disconnect -> reconnect -> history。 -7. 增加 room-service 重启恢复测试。 +3. 增加显式 RoomHeartbeat,只刷新已有 presence,不隐式进房。 +4. 补齐 LeaveRoom 后对订阅守卫的拒绝行为测试。 +5. 接入腾讯云 IM UserSig 签发、CreateRoom 建群和房间系统消息发布。 +6. 增加 stale presence 清理 worker。 +7. 增加重连集成测试:JoinRoom -> UserSig -> IM login/join group -> disconnect -> heartbeat/reconnect -> history。 +8. 增加 room-service 重启恢复测试。 diff --git a/docs/tencent-rtc-token-uid-mapping-development.md b/docs/tencent-rtc-token-uid-mapping-development.md index 9deffaeb..89b5d7f4 100644 --- a/docs/tencent-rtc-token-uid-mapping-development.md +++ b/docs/tencent-rtc-token-uid-mapping-development.md @@ -117,7 +117,7 @@ RTC numeric roomId -> always 0 or omitted ## External HTTP API -新增 gateway 入口: +RTC token gateway 入口: ```text POST /api/v1/rtc/token @@ -171,6 +171,53 @@ Response `data`: | RTC 配置缺失 | 500 | `INTERNAL_ERROR` | fail-closed,不返回假 token | | room-service 不可用 | 502 | `UPSTREAM_ERROR` | gateway 不能自判 presence | +显式房间心跳入口: + +```text +POST /api/v1/rooms/heartbeat +Authorization: Bearer +``` + +Request: + +```json +{ + "room_id": "room_1001", + "command_id": "cmd-heartbeat-1700000000" +} +``` + +规则: + +- 心跳只刷新已经存在的 room-service presence 的 `last_seen_at_ms`。 +- 用户不在房间时返回 `NOT_FOUND`,不能通过心跳重新进入房间。 +- 客户端应按小于 `room_presence_stale_after` 的间隔发送心跳;HTTP 重试同一次心跳必须复用同一个 `command_id`。 +- 主动离房仍然必须调用 `/api/v1/rooms/leave`;心跳停止只代表后台 stale worker 最终清理。 + +腾讯 RTC 服务端事件回调入口: + +```text +POST /api/v1/tencent-rtc/callback?app_code=default +Header: SdkAppId: +Header: Sign: base64(hmacsha256(callback_sign_key, raw_body)) +``` + +消费事件: + +| Tencent Event | Internal Event | Room Cell Effect | +| --- | --- | --- | +| `EventGroupId=2, EventType=203` | `audio_started` | 当前麦位为 `pending_publish` 时确认成 `publishing` | +| `EventGroupId=2, EventType=204` | `audio_stopped` | 释放当前用户麦位 | +| `EventGroupId=1, EventType=104` | `room_exited` | 移除业务 presence,并释放麦位 | + +回调边界: + +- gateway 只负责验签、校验 `SdkAppId`、解析 Tencent 字段和派生稳定 `command_id`。 +- 房间状态变更只调用 room-service `ApplyRTCEvent`,仍进入 Room Cell、command log 和 outbox。 +- 未知事件在验签成功后返回 `{"code":0}` 并忽略,避免腾讯新增事件导致无意义重试。 +- room-service 暂时不可用时返回非 200,让腾讯 RTC 按平台策略重试。 +- 如果一个旧 `room_exited` 回调晚于新的业务心跳到达,room-service 会保留较新的业务 presence,避免旧回调清掉重连用户。 + ## Internal Flow ```mermaid @@ -196,6 +243,18 @@ sequenceDiagram C->>T: enterRoom(SDKAppID, UserID, UserSig, strRoomId) T-->>C: RTC room entered + + loop heartbeat before stale timeout + C->>G: POST /api/v1/rooms/heartbeat(room_id) + G->>R: RoomHeartbeat(actor_user_id, room_id) + R-->>G: refreshed last_seen_at_ms + end + + T->>G: RTC callback 203/204/104 with Sign + G->>G: verify HMAC-SHA256 over raw body + G->>R: ApplyRTCEvent(audio_started/audio_stopped/room_exited) + R-->>G: RoomSnapshot + G-->>T: {"code":0} ``` 签发顺序: @@ -224,11 +283,14 @@ tencent_rtc: user_sig_ttl: "2h" room_id_type: "string" app_scene: "voice_chat_room" + callback_url: "https://api.example.com/api/v1/tencent-rtc/callback?app_code=default" + callback_sign_key: "TENCENT_RTC_CALLBACK_SIGN_KEY" ``` 配置规则: - `secret_key` 只能存在服务端配置或密钥系统,不能下发客户端。 +- `callback_sign_key` 只用于腾讯 RTC 回调验签,不要复用 UserSig `secret_key`。 - `tencent_rtc` 与 `tencent_im` 分开配置,避免误把 IM 应用和 RTC 应用混用。 - 如果腾讯控制台实际使用同一个应用承载 Chat/RTC,可以让两块配置填同一组 `sdk_app_id/secret_key`,但仍必须显式配置。 - `user_sig_ttl` 不宜过长;建议 2h 到 24h,具体按客户端刷新能力和泄露窗口决定。 diff --git a/docs/voice-room-feature-inventory.md b/docs/voice-room-feature-inventory.md index 0507b3cd..02d5b424 100644 --- a/docs/voice-room-feature-inventory.md +++ b/docs/voice-room-feature-inventory.md @@ -54,8 +54,9 @@ | --- | --- | --- | --- | | 创建房间 | `DONE` | `CreateRoom` 校验 room_id、actor、seat_count、mode;写 meta/command/outbox/snapshot | 真实 IM 建群失败注入和线上重试策略联调 | | owner/host 收敛 | `DONE` | room-service 从 `actor_user_id` 默认 owner/host,拒绝外部冒用 | 后续转主持需独立命令 | -| 进房 presence | `DONE` | `JoinRoom` 写 `OnlineUsers`,返回 user 和 snapshot | 客户端心跳或定期 Join 刷新策略需定稿 | -| 重复 JoinRoom 刷新 | `DONE` | 重复进房刷新 `last_seen_at_ms`,不重复发进房事件 | 客户端断线重连自动化测试 | +| 进房 presence | `DONE` | `JoinRoom` 写 `OnlineUsers`,返回 user 和 snapshot | 客户端断线重连自动化测试 | +| 显式心跳刷新 | `DONE` | `/api/v1/rooms/heartbeat` 和 `RoomHeartbeat` 只刷新已有 `last_seen_at_ms` | 客户端按 stale timeout 配置周期调用 | +| 重复 JoinRoom 刷新 | `DONE` | 重复进房刷新 `last_seen_at_ms`,不重复发进房事件 | 新客户端优先使用 RoomHeartbeat | | 离房 | `DONE` | `LeaveRoom` 幂等,移除 presence,释放麦位,写 outbox | 客户端收到离房/被踢后退出 IM/RTC 需联调 | | stale presence 清理 | `DONE` | `RunPresenceStaleWorker` 和 `SweepStalePresence` 存在 | 多实例下只扫描本节点已装载 Cell,需压测确认 | | 房间恢复 | `DONE` | snapshot + command log + Redis lease 接管恢复测试存在 | 大房间 command log 回放性能和快照策略压测 | @@ -99,9 +100,10 @@ | RTC room_id 映射 | `DONE` | 统一使用 TRTC `strRoomId`,校验 room_id 子集 | 当前入口 fail-closed,非法 room_id 不创建房间 | | 进频道权限 | `DONE` | 签 RTC token 前调用 `VerifyRoomPresence` | 客户端必须按 JoinRoom 后再取 token | | RTC 角色 | `PARTIAL` | token 返回默认 `audience` | 上麦后切 `anchor` 或 SDK role 切换未闭环 | -| 离频道 | `PARTIAL` | 服务端 LeaveRoom 会移除业务 presence | 客户端退出 TRTC 房间、异常重进策略未联调 | +| RTC 事件回调 | `DONE` | `/api/v1/tencent-rtc/callback` 验签后消费 203/204/104 并调用 `ApplyRTCEvent` | 腾讯控制台公网回调配置和真实 TRTC 联调 | +| 离频道 | `PARTIAL` | 服务端 LeaveRoom 和 RTC 104 回调都会移除业务 presence | 客户端退出 TRTC 房间、异常重进策略未联调 | | RTC 断线恢复 | `PARTIAL` | 文档定义 RTC 断线不等于业务离房 | 客户端 SDK 回调、重新取 token、重新 enterRoom 未验收 | -| 音频权限/上麦联动 | `TODO` | MicUp 只改 Room Cell 麦位 | MicUp 后允许推流、MicDown 后停止推流的端侧策略未做 | +| 音频权限/上麦联动 | `PARTIAL` | MicUp 创建 pending_publish,客户端确认或 RTC 203 回调推进 publishing,RTC 204 回调释放麦位 | MicUp 后切 anchor、MicDown 后停止推流的端侧策略未联调 | | 音频审核/录制 | `TODO` | 当前无设计和代码 | 后续接腾讯云审核/录制能力 | ## Mic And Room Management diff --git a/pkg/tencentrtc/callback.go b/pkg/tencentrtc/callback.go new file mode 100644 index 00000000..b454b30f --- /dev/null +++ b/pkg/tencentrtc/callback.go @@ -0,0 +1,31 @@ +package tencentrtc + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "strings" +) + +const ( + // CallbackHeaderSign 是腾讯 RTC 事件回调携带的签名 header。 + CallbackHeaderSign = "Sign" + // CallbackHeaderSDKAppID 是腾讯 RTC 事件回调携带的应用 ID header。 + CallbackHeaderSDKAppID = "SdkAppId" +) + +// VerifyCallbackSignature 校验腾讯 RTC 事件回调签名。 +func VerifyCallbackSignature(key string, body []byte, sign string) bool { + key = strings.TrimSpace(key) + sign = strings.TrimSpace(sign) + if key == "" || sign == "" { + // 回调入口必须 fail-closed;没有 key 或签名都不能进入房间命令链路。 + return false + } + + mac := hmac.New(sha256.New, []byte(key)) + _, _ = mac.Write(body) + expected := base64.StdEncoding.EncodeToString(mac.Sum(nil)) + + return hmac.Equal([]byte(expected), []byte(sign)) +} diff --git a/pkg/tencentrtc/callback_test.go b/pkg/tencentrtc/callback_test.go new file mode 100644 index 00000000..f43fe81d --- /dev/null +++ b/pkg/tencentrtc/callback_test.go @@ -0,0 +1,18 @@ +package tencentrtc + +import "testing" + +func TestVerifyCallbackSignatureUsesRawBody(t *testing.T) { + body := []byte("{\n\t\"EventGroupId\":\t2,\n\t\"EventType\":\t204,\n\t\"CallbackTs\":\t1664209748188,\n\t\"EventInfo\":\t{\n\t\t\"RoomId\":\t8489,\n\t\t\"EventTs\":\t1664209748,\n\t\t\"EventMsTs\":\t1664209748180,\n\t\t\"UserId\":\t\"user_85034614\",\n\t\t\"Reason\":\t0\n\t}\n}") + sign := "kkoFeO3Oh2ZHnjtg8tEAQhtXK16/KI05W3BQff8IvGA=" + + if !VerifyCallbackSignature("123654", body, sign) { + t.Fatal("expected official Tencent RTC callback signature sample to verify") + } + if VerifyCallbackSignature("123654", []byte(`{"EventType":204}`), sign) { + t.Fatal("signature verification must use the exact raw callback body") + } + if VerifyCallbackSignature("", body, sign) || VerifyCallbackSignature("123654", body, "") { + t.Fatal("missing key or sign must fail closed") + } +} diff --git a/services/gateway-service/configs/config.docker.yaml b/services/gateway-service/configs/config.docker.yaml index 8c5e99d4..5dd58276 100644 --- a/services/gateway-service/configs/config.docker.yaml +++ b/services/gateway-service/configs/config.docker.yaml @@ -36,6 +36,8 @@ tencent_rtc: user_sig_ttl: "2h" room_id_type: "string" app_scene: "voice_chat_room" + callback_url: "" + callback_sign_key: "" tencent-cos: # Docker 本地联调 App 文件/头像上传;secret 只保存在 gateway 服务端配置。 diff --git a/services/gateway-service/configs/config.tencent.example.yaml b/services/gateway-service/configs/config.tencent.example.yaml index be76fdf7..7814511e 100644 --- a/services/gateway-service/configs/config.tencent.example.yaml +++ b/services/gateway-service/configs/config.tencent.example.yaml @@ -45,6 +45,10 @@ tencent_rtc: room_id_type: "string" # 语音房场景固定使用 VoiceChatRoom,所有客户端必须保持一致。 app_scene: "voice_chat_room" + # 腾讯 RTC 控制台配置的事件回调地址,用于房间退出和音频发布状态同步。 + callback_url: "https://api.example.com/api/v1/tencent-rtc/callback?app_code=default" + # 腾讯 RTC 回调签名 key,必须和控制台配置保持一致;不要复用 UserSig SecretKey。 + callback_sign_key: "TENCENT_RTC_CALLBACK_SIGN_KEY" tencent-cos: # App 文件/头像上传使用腾讯云 COS;SecretID/SecretKey 只允许保存在服务端配置。 diff --git a/services/gateway-service/configs/config.yaml b/services/gateway-service/configs/config.yaml index 69e240c1..70cb7877 100644 --- a/services/gateway-service/configs/config.yaml +++ b/services/gateway-service/configs/config.yaml @@ -41,6 +41,10 @@ tencent_rtc: # 当前 room_id 是字符串,客户端只能使用 TRTC strRoomId,不能混用数字 roomId。 room_id_type: "string" app_scene: "voice_chat_room" + # 腾讯 RTC 控制台回调 URL。需要公网可访问;本地为空表示暂不启用回调。 + callback_url: "" + # 腾讯 RTC 回调签名 key。启用回调后必须填写,gateway 会按原始 body 做 HMAC-SHA256 校验。 + callback_sign_key: "" tencent-cos: # App 文件/头像上传使用腾讯云 COS;secret 只保存在 gateway 服务端配置。 diff --git a/services/gateway-service/internal/app/app.go b/services/gateway-service/internal/app/app.go index 6a1ade23..a7dfef05 100644 --- a/services/gateway-service/internal/app/app.go +++ b/services/gateway-service/internal/app/app.go @@ -91,12 +91,13 @@ func New(cfg config.Config) (*App, error) { handler.SetAppConfigReader(appConfigReader) } handler.SetTencentRTC(httptransport.TencentRTCConfig{ - Enabled: cfg.TencentRTC.Enabled, - SDKAppID: cfg.TencentRTC.SDKAppID, - SecretKey: cfg.TencentRTC.SecretKey, - UserSigTTL: cfg.TencentRTC.UserSigTTL, - RoomIDType: cfg.TencentRTC.RoomIDType, - AppScene: cfg.TencentRTC.AppScene, + Enabled: cfg.TencentRTC.Enabled, + SDKAppID: cfg.TencentRTC.SDKAppID, + SecretKey: cfg.TencentRTC.SecretKey, + UserSigTTL: cfg.TencentRTC.UserSigTTL, + RoomIDType: cfg.TencentRTC.RoomIDType, + AppScene: cfg.TencentRTC.AppScene, + CallbackSignKey: cfg.TencentRTC.CallbackSignKey, }) if cfg.TencentCOS.Enabled { uploader, err := tencentcos.NewUploader(tencentcos.Config{ diff --git a/services/gateway-service/internal/client/room_client.go b/services/gateway-service/internal/client/room_client.go index bbd75dd7..706d582d 100644 --- a/services/gateway-service/internal/client/room_client.go +++ b/services/gateway-service/internal/client/room_client.go @@ -11,11 +11,13 @@ import ( type RoomClient interface { CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) (*roomv1.CreateRoomResponse, error) JoinRoom(ctx context.Context, req *roomv1.JoinRoomRequest) (*roomv1.JoinRoomResponse, error) + RoomHeartbeat(ctx context.Context, req *roomv1.RoomHeartbeatRequest) (*roomv1.RoomHeartbeatResponse, error) LeaveRoom(ctx context.Context, req *roomv1.LeaveRoomRequest) (*roomv1.LeaveRoomResponse, error) MicUp(ctx context.Context, req *roomv1.MicUpRequest) (*roomv1.MicUpResponse, error) MicDown(ctx context.Context, req *roomv1.MicDownRequest) (*roomv1.MicDownResponse, error) ChangeMicSeat(ctx context.Context, req *roomv1.ChangeMicSeatRequest) (*roomv1.ChangeMicSeatResponse, error) ConfirmMicPublishing(ctx context.Context, req *roomv1.ConfirmMicPublishingRequest) (*roomv1.ConfirmMicPublishingResponse, error) + ApplyRTCEvent(ctx context.Context, req *roomv1.ApplyRTCEventRequest) (*roomv1.ApplyRTCEventResponse, error) SetMicSeatLock(ctx context.Context, req *roomv1.SetMicSeatLockRequest) (*roomv1.SetMicSeatLockResponse, error) SetChatEnabled(ctx context.Context, req *roomv1.SetChatEnabledRequest) (*roomv1.SetChatEnabledResponse, error) SetRoomAdmin(ctx context.Context, req *roomv1.SetRoomAdminRequest) (*roomv1.SetRoomAdminResponse, error) @@ -79,6 +81,10 @@ func (c *grpcRoomClient) JoinRoom(ctx context.Context, req *roomv1.JoinRoomReque return c.client.JoinRoom(ctx, req) } +func (c *grpcRoomClient) RoomHeartbeat(ctx context.Context, req *roomv1.RoomHeartbeatRequest) (*roomv1.RoomHeartbeatResponse, error) { + return c.client.RoomHeartbeat(ctx, req) +} + func (c *grpcRoomClient) LeaveRoom(ctx context.Context, req *roomv1.LeaveRoomRequest) (*roomv1.LeaveRoomResponse, error) { return c.client.LeaveRoom(ctx, req) } @@ -99,6 +105,10 @@ func (c *grpcRoomClient) ConfirmMicPublishing(ctx context.Context, req *roomv1.C return c.client.ConfirmMicPublishing(ctx, req) } +func (c *grpcRoomClient) ApplyRTCEvent(ctx context.Context, req *roomv1.ApplyRTCEventRequest) (*roomv1.ApplyRTCEventResponse, error) { + return c.client.ApplyRTCEvent(ctx, req) +} + func (c *grpcRoomClient) SetMicSeatLock(ctx context.Context, req *roomv1.SetMicSeatLockRequest) (*roomv1.SetMicSeatLockResponse, error) { return c.client.SetMicSeatLock(ctx, req) } diff --git a/services/gateway-service/internal/config/config.go b/services/gateway-service/internal/config/config.go index fd69b16a..45be78f1 100644 --- a/services/gateway-service/internal/config/config.go +++ b/services/gateway-service/internal/config/config.go @@ -85,6 +85,10 @@ type TencentRTCConfig struct { RoomIDType string `yaml:"room_id_type"` // AppScene 首版固定 voice_chat_room,所有端必须一致。 AppScene string `yaml:"app_scene"` + // CallbackURL 是在腾讯 RTC 控制台配置的事件回调地址。 + CallbackURL string `yaml:"callback_url"` + // CallbackSignKey 是腾讯 RTC 事件回调签名 key,只用于校验回调来源。 + CallbackSignKey string `yaml:"callback_sign_key"` } // TencentCOSConfig 描述 gateway 代 App 上传文件到腾讯云 COS 所需的服务端配置。 @@ -198,6 +202,8 @@ func (cfg *Config) Normalize() error { // v1 has no gateway policy surface for multiple RTC scenes, so reject drift early. return fmt.Errorf("tencent_rtc.app_scene must be %q", tencentrtc.AppSceneVoiceChatRoom) } + cfg.TencentRTC.CallbackURL = strings.TrimSpace(cfg.TencentRTC.CallbackURL) + cfg.TencentRTC.CallbackSignKey = strings.TrimSpace(cfg.TencentRTC.CallbackSignKey) return nil } diff --git a/services/gateway-service/internal/transport/http/auth_handler.go b/services/gateway-service/internal/transport/http/auth_handler.go index 31bc053a..1de2a15e 100644 --- a/services/gateway-service/internal/transport/http/auth_handler.go +++ b/services/gateway-service/internal/transport/http/auth_handler.go @@ -29,20 +29,21 @@ type authTokenData struct { OnboardingStatus string `json:"onboarding_status"` } -// loginPassword 处理 display_user_id + 密码登录。 +// loginPassword 处理账号密码登录;账号就是当前有效短号。 func (h *Handler) loginPassword(writer http.ResponseWriter, request *http.Request) { var body struct { - DisplayUserID string `json:"display_user_id"` - Password string `json:"password"` - DeviceID string `json:"device_id"` + Account string `json:"account"` + Password string `json:"password"` + DeviceID string `json:"device_id"` } if !decode(writer, request, &body) { return } + account := strings.TrimSpace(body.Account) if !h.allowPublicAuthRequest(writer, request, authRateInput{ operation: authOperationPassword, deviceID: body.DeviceID, - displayUserID: body.DisplayUserID, + displayUserID: account, }) { return } @@ -53,7 +54,7 @@ func (h *Handler) loginPassword(writer http.ResponseWriter, request *http.Reques resp, err := h.userClient.LoginPassword(request.Context(), &userv1.LoginPasswordRequest{ Meta: authRequestMeta(request, body.DeviceID), - DisplayUserId: body.DisplayUserID, + DisplayUserId: account, Password: body.Password, }) if err != nil { diff --git a/services/gateway-service/internal/transport/http/auth_rate_limiter_test.go b/services/gateway-service/internal/transport/http/auth_rate_limiter_test.go index 79b8b2f8..95fa476b 100644 --- a/services/gateway-service/internal/transport/http/auth_rate_limiter_test.go +++ b/services/gateway-service/internal/transport/http/auth_rate_limiter_test.go @@ -81,7 +81,7 @@ func TestAuthRateKeysHashUntrustedComponents(t *testing.T) { handler := NewHandler(&fakeRoomClient{}, &fakeUserAuthClient{}) handler.SetAuthRateLimit(AuthRateLimitConfig{KeyPrefix: "test:"}) untrusted := strings.Repeat("x", 4096) - request := httptest.NewRequest("POST", "/api/v1/auth/password/login", nil) + request := httptest.NewRequest("POST", "/api/v1/auth/account/login", nil) request.Header.Set("X-Forwarded-For", untrusted) keys := handler.authRateKeys(request, authRateInput{ @@ -108,7 +108,7 @@ func TestAuthRateKeysHashUntrustedComponents(t *testing.T) { func TestPublicAuthRateLimitDisabledSkipsBackend(t *testing.T) { handler := NewHandler(&fakeRoomClient{}, &fakeUserAuthClient{}) handler.SetAuthRateLimitBackend(AuthRateLimitConfig{Enabled: false}, &fakeDenyingAuthRateLimiter{}) - request := httptest.NewRequest("POST", "/api/v1/auth/password/login", nil) + request := httptest.NewRequest("POST", "/api/v1/auth/account/login", nil) if !handler.allowPublicAuthRequest(httptest.NewRecorder(), request, authRateInput{operation: authOperationPassword}) { t.Fatal("disabled auth rate limiter must skip backend") diff --git a/services/gateway-service/internal/transport/http/handler.go b/services/gateway-service/internal/transport/http/handler.go index 3b1754c5..d13907e3 100644 --- a/services/gateway-service/internal/transport/http/handler.go +++ b/services/gateway-service/internal/transport/http/handler.go @@ -46,12 +46,13 @@ type TencentIMConfig struct { // TencentRTCConfig 是 gateway transport 层签发客户端腾讯 RTC 进房票据所需的配置。 type TencentRTCConfig struct { - Enabled bool - SDKAppID int64 - SecretKey string - UserSigTTL time.Duration - RoomIDType string - AppScene string + Enabled bool + SDKAppID int64 + SecretKey string + UserSigTTL time.Duration + RoomIDType string + AppScene string + CallbackSignKey string } // ObjectUploader 是 gateway 上传接口依赖的对象存储最小能力。 diff --git a/services/gateway-service/internal/transport/http/response_test.go b/services/gateway-service/internal/transport/http/response_test.go index a7840a9b..4be7dfc4 100644 --- a/services/gateway-service/internal/transport/http/response_test.go +++ b/services/gateway-service/internal/transport/http/response_test.go @@ -3,6 +3,9 @@ package http import ( "bytes" "context" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" "encoding/json" "errors" "io" @@ -29,11 +32,13 @@ import ( type fakeRoomClient struct { lastCreate *roomv1.CreateRoomRequest lastJoin *roomv1.JoinRoomRequest + lastHeartbeat *roomv1.RoomHeartbeatRequest lastLeave *roomv1.LeaveRoomRequest lastMicUp *roomv1.MicUpRequest lastMicDown *roomv1.MicDownRequest lastChangeMicSeat *roomv1.ChangeMicSeatRequest lastConfirmMic *roomv1.ConfirmMicPublishingRequest + lastRTCEvent *roomv1.ApplyRTCEventRequest lastMicSeatLock *roomv1.SetMicSeatLockRequest lastChatEnabled *roomv1.SetChatEnabledRequest lastSetAdmin *roomv1.SetRoomAdminRequest @@ -65,6 +70,11 @@ func (f *fakeRoomClient) JoinRoom(_ context.Context, req *roomv1.JoinRoomRequest return &roomv1.JoinRoomResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 2}}, nil } +func (f *fakeRoomClient) RoomHeartbeat(_ context.Context, req *roomv1.RoomHeartbeatRequest) (*roomv1.RoomHeartbeatResponse, error) { + f.lastHeartbeat = req + return &roomv1.RoomHeartbeatResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 2}}, nil +} + func (f *fakeRoomClient) LeaveRoom(_ context.Context, req *roomv1.LeaveRoomRequest) (*roomv1.LeaveRoomResponse, error) { f.lastLeave = req return &roomv1.LeaveRoomResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 3}}, nil @@ -90,6 +100,11 @@ func (f *fakeRoomClient) ConfirmMicPublishing(_ context.Context, req *roomv1.Con return &roomv1.ConfirmMicPublishingResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 7}}, nil } +func (f *fakeRoomClient) ApplyRTCEvent(_ context.Context, req *roomv1.ApplyRTCEventRequest) (*roomv1.ApplyRTCEventResponse, error) { + f.lastRTCEvent = req + return &roomv1.ApplyRTCEventResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 8}}, nil +} + func (f *fakeRoomClient) SetMicSeatLock(_ context.Context, req *roomv1.SetMicSeatLockRequest) (*roomv1.SetMicSeatLockResponse, error) { f.lastMicSeatLock = req return &roomv1.SetMicSeatLockResponse{Result: &roomv1.CommandResult{Applied: true, RoomVersion: 8}}, nil @@ -622,6 +637,15 @@ func TestRoomCommandsPropagateClientCommandID(t *testing.T) { return client.lastLeave.GetMeta() }, }, + { + name: "heartbeat", + path: "/api/v1/rooms/heartbeat", + body: `{"room_id":"room-1","command_id":"cmd-heartbeat-1"}`, + commandID: "cmd-heartbeat-1", + extractMeta: func(client *fakeRoomClient) *roomv1.RequestMeta { + return client.lastHeartbeat.GetMeta() + }, + }, { name: "mic_up", path: "/api/v1/rooms/mic/up", @@ -1156,17 +1180,17 @@ func TestThirdPartyLoginRateLimitByProviderAndIP(t *testing.T) { } } -func TestPasswordLoginRateLimitByDisplayUserID(t *testing.T) { +func TestAccountLoginRateLimitByAccount(t *testing.T) { userClient := &fakeUserAuthClient{} handler := NewHandler(&fakeRoomClient{}, userClient) handler.SetAuthRateLimit(authRateLimitForTest(func(config *AuthRateLimitConfig) { config.DisplayUserIDIPLimit = 1 })) router := handler.Routes(auth.NewVerifier("secret")) - body := []byte(`{"display_user_id":"100001","password":"bad","device_id":"dev-1"}`) + body := []byte(`{"account":"100001","password":"bad","device_id":"dev-1"}`) for i := 0; i < 2; i++ { - request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/password/login", bytes.NewReader(body)) + request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/account/login", bytes.NewReader(body)) request.Header.Set("X-Request-ID", "req-password-rate") request.Header.Set("X-Forwarded-For", "203.0.113.20") recorder := httptest.NewRecorder() @@ -1185,6 +1209,25 @@ func TestPasswordLoginRateLimitByDisplayUserID(t *testing.T) { } } +func TestAccountLoginAcceptsAccountField(t *testing.T) { + userClient := &fakeUserAuthClient{} + router := NewHandler(&fakeRoomClient{}, userClient).Routes(auth.NewVerifier("secret")) + body := []byte(`{"account":"123456","password":"1234567","device_id":"ios"}`) + request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/account/login", bytes.NewReader(body)) + request.Header.Set("X-Request-ID", "req-account-login") + recorder := httptest.NewRecorder() + + router.ServeHTTP(recorder, request) + + assertEnvelope(t, recorder, http.StatusOK, codeOK, "req-account-login") + if userClient.lastLoginPassword == nil || userClient.lastLoginPassword.GetDisplayUserId() != "123456" { + t.Fatalf("account was not propagated as display_user_id: %+v", userClient.lastLoginPassword) + } + if userClient.lastLoginPassword.GetPassword() != "1234567" || userClient.lastLoginPassword.GetMeta().GetDeviceId() != "ios" { + t.Fatalf("password login payload mismatch: %+v", userClient.lastLoginPassword) + } +} + func TestRefreshRateLimitByDeviceID(t *testing.T) { userClient := &fakeUserAuthClient{} handler := NewHandler(&fakeRoomClient{}, userClient) @@ -1553,6 +1596,7 @@ func TestProfileGateRejectsIncompleteUsersForRoomIMRTCPaidCapabilities(t *testin {name: "room_list", method: http.MethodGet, path: "/api/v1/rooms"}, {name: "create_room", method: http.MethodPost, path: "/api/v1/rooms/create", body: `{"room_id":"room-1"}`}, {name: "join_room", method: http.MethodPost, path: "/api/v1/rooms/join", body: `{"room_id":"room-1"}`}, + {name: "room_heartbeat", method: http.MethodPost, path: "/api/v1/rooms/heartbeat", body: `{"room_id":"room-1"}`}, {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"}`}, @@ -1576,7 +1620,7 @@ func TestProfileGateRejectsIncompleteUsersForRoomIMRTCPaidCapabilities(t *testin router.ServeHTTP(recorder, request) assertEnvelope(t, recorder, http.StatusForbidden, codeProfileRequired, "req-profile-required") - if roomClient.lastCreate != nil || roomClient.lastJoin != nil || roomClient.lastGift != nil { + if roomClient.lastCreate != nil || roomClient.lastJoin != nil || roomClient.lastHeartbeat != nil || roomClient.lastGift != nil { t.Fatalf("profile gate must stop protected request before room-service: %+v", roomClient) } }) @@ -1657,8 +1701,8 @@ func TestUploadFileRequiresObjectUploader(t *testing.T) { func TestAuthLoginMapsGRPCReason(t *testing.T) { userClient := &fakeUserAuthClient{loginErr: xerr.ToGRPCError(xerr.New(xerr.AuthFailed, "authentication failed"))} router := NewHandler(&fakeRoomClient{}, userClient).Routes(auth.NewVerifier("secret")) - body := []byte(`{"display_user_id":"100001","password":"bad","device_id":"ios"}`) - request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/password/login", bytes.NewReader(body)) + body := []byte(`{"account":"100001","password":"bad","device_id":"ios"}`) + request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/account/login", bytes.NewReader(body)) request.Header.Set("X-Request-ID", "req-auth-failed") recorder := httptest.NewRecorder() @@ -1986,6 +2030,73 @@ func TestTencentRTCTokenFailsClosedForConfigAndUpstreamErrors(t *testing.T) { assertEnvelope(t, upstreamRecorder, http.StatusBadGateway, codeUpstreamError, "req-rtc-upstream") } +func TestTencentRTCCallbackVerifiesSignatureAndAppliesEvent(t *testing.T) { + roomClient := &fakeRoomClient{} + handler := NewHandlerWithConfig(roomClient, &fakeRoomGuardClient{}, nil, nil, TencentIMConfig{}) + handler.SetTencentRTC(TencentRTCConfig{ + SDKAppID: 1400000000, + CallbackSignKey: "callback-key", + }) + router := handler.Routes(auth.NewVerifier("secret")) + body := []byte(`{"EventGroupId":2,"EventType":203,"CallbackTs":1700000001001,"EventInfo":{"RoomId":"room_1001","EventMsTs":1700000001000,"UserId":"42"}}`) + request := httptest.NewRequest(http.MethodPost, "/api/v1/tencent-rtc/callback?app_code=lalu", bytes.NewReader(body)) + request.Header.Set("X-Request-ID", "req-rtc-callback") + request.Header.Set("SdkAppId", "1400000000") + request.Header.Set("Sign", signTencentRTCCallback("callback-key", body)) + recorder := httptest.NewRecorder() + + router.ServeHTTP(recorder, request) + + assertTencentRTCCallback(t, recorder, http.StatusOK, 0) + if roomClient.lastRTCEvent == nil { + t.Fatal("RTC callback must forward known events to room-service") + } + if roomClient.lastRTCEvent.GetEventType() != "audio_started" || roomClient.lastRTCEvent.GetTargetUserId() != 42 || roomClient.lastRTCEvent.GetEventTimeMs() != 1700000001000 { + t.Fatalf("RTC event fields mismatch: %+v", roomClient.lastRTCEvent) + } + meta := roomClient.lastRTCEvent.GetMeta() + if meta.GetRoomId() != "room_1001" || meta.GetActorUserId() != 42 || meta.GetRequestId() != "req-rtc-callback" || meta.GetAppCode() != "lalu" { + t.Fatalf("RTC event meta mismatch: %+v", meta) + } + if !strings.HasPrefix(meta.GetCommandId(), "cmd_") || !strings.HasPrefix(roomClient.lastRTCEvent.GetExternalEventId(), "rtc_evt_") { + t.Fatalf("RTC callback must derive stable ids: meta=%+v event=%+v", meta, roomClient.lastRTCEvent) + } +} + +func TestTencentRTCCallbackRejectsInvalidSignatureAndIgnoresUnknownEvents(t *testing.T) { + roomClient := &fakeRoomClient{} + handler := NewHandlerWithConfig(roomClient, &fakeRoomGuardClient{}, nil, nil, TencentIMConfig{}) + handler.SetTencentRTC(TencentRTCConfig{ + SDKAppID: 1400000000, + CallbackSignKey: "callback-key", + }) + router := handler.Routes(auth.NewVerifier("secret")) + body := []byte(`{"EventGroupId":2,"EventType":204,"CallbackTs":1700000001001,"EventInfo":{"RoomId":"room_1001","EventMsTs":1700000001000,"UserId":"42","Reason":0}}`) + badRequest := httptest.NewRequest(http.MethodPost, "/api/v1/tencent-rtc/callback", bytes.NewReader(body)) + badRequest.Header.Set("SdkAppId", "1400000000") + badRequest.Header.Set("Sign", "bad-sign") + badRecorder := httptest.NewRecorder() + + router.ServeHTTP(badRecorder, badRequest) + + assertTencentRTCCallback(t, badRecorder, http.StatusForbidden, 1) + if roomClient.lastRTCEvent != nil { + t.Fatalf("invalid signature must not reach room-service: %+v", roomClient.lastRTCEvent) + } + + unknownBody := []byte(`{"EventGroupId":2,"EventType":201,"CallbackTs":1700000001001,"EventInfo":{"RoomId":"room_1001","EventMsTs":1700000001000,"UserId":"42"}}`) + unknownRequest := httptest.NewRequest(http.MethodPost, "/api/v1/tencent-rtc/callback", bytes.NewReader(unknownBody)) + unknownRequest.Header.Set("SdkAppId", "1400000000") + unknownRequest.Header.Set("Sign", signTencentRTCCallback("callback-key", unknownBody)) + unknownRecorder := httptest.NewRecorder() + router.ServeHTTP(unknownRecorder, unknownRequest) + + assertTencentRTCCallback(t, unknownRecorder, http.StatusOK, 0) + if roomClient.lastRTCEvent != nil { + t.Fatalf("unknown RTC event must be acknowledged without room-service call: %+v", roomClient.lastRTCEvent) + } +} + func TestTencentIMJoinCallbackUsesPresenceGuard(t *testing.T) { guard := &fakeRoomGuardClient{} router := NewHandlerWithConfig(&fakeRoomClient{}, guard, nil, nil, TencentIMConfig{ @@ -2100,6 +2211,28 @@ func assertTencentCallback(t *testing.T, recorder *httptest.ResponseRecorder, st } } +func assertTencentRTCCallback(t *testing.T, recorder *httptest.ResponseRecorder, statusCode int, code int) { + t.Helper() + + if recorder.Code != statusCode { + t.Fatalf("status mismatch: got %d want %d body=%s", recorder.Code, statusCode, recorder.Body.String()) + } + + var response tencentRTCCallbackResponse + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatalf("decode tencent rtc callback response failed: %v", err) + } + if response.Code != code { + t.Fatalf("unexpected tencent rtc callback response: %+v", response) + } +} + +func signTencentRTCCallback(key string, body []byte) string { + mac := hmac.New(sha256.New, []byte(key)) + _, _ = mac.Write(body) + return base64.StdEncoding.EncodeToString(mac.Sum(nil)) +} + func authRateLimitForTest(mutator func(*AuthRateLimitConfig)) AuthRateLimitConfig { config := AuthRateLimitConfig{ Enabled: true, diff --git a/services/gateway-service/internal/transport/http/room_handler.go b/services/gateway-service/internal/transport/http/room_handler.go index 41c66440..eca41c48 100644 --- a/services/gateway-service/internal/transport/http/room_handler.go +++ b/services/gateway-service/internal/transport/http/room_handler.go @@ -143,6 +143,23 @@ func (h *Handler) joinRoom(writer http.ResponseWriter, request *http.Request) { write(writer, request, resp, err) } +// roomHeartbeat 把客户端显式心跳转换为 room-service presence refresh 命令。 +func (h *Handler) roomHeartbeat(writer http.ResponseWriter, request *http.Request) { + var body struct { + RoomID string `json:"room_id"` + CommandID string `json:"command_id"` + } + + if !decode(writer, request, &body) { + return + } + + resp, err := h.roomClient.RoomHeartbeat(request.Context(), &roomv1.RoomHeartbeatRequest{ + Meta: meta(request, body.RoomID, body.CommandID), + }) + write(writer, request, resp, err) +} + // leaveRoom 把退房 HTTP JSON 请求转换为 room-service LeaveRoom 命令。 func (h *Handler) leaveRoom(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 ed80e659..e0639abd 100644 --- a/services/gateway-service/internal/transport/http/router.go +++ b/services/gateway-service/internal/transport/http/router.go @@ -13,7 +13,7 @@ const apiV1Prefix = "/api/v1" func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { mux := http.NewServeMux() - mux.Handle(apiV1Prefix+"/auth/password/login", h.publicAPIHandler(h.loginPassword)) + mux.Handle(apiV1Prefix+"/auth/account/login", h.publicAPIHandler(h.loginPassword)) mux.Handle(apiV1Prefix+"/auth/password/set", h.apiHandler(jwtVerifier, h.setPassword)) mux.Handle(apiV1Prefix+"/auth/third-party/login", h.publicAPIHandler(h.loginThirdParty)) mux.Handle(apiV1Prefix+"/auth/token/refresh", h.publicAPIHandler(h.refreshToken)) @@ -46,6 +46,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { 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)) @@ -59,6 +60,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler { 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+"/tencent-rtc/callback", h.publicAPIHandler(h.handleTencentRTCCallback)) 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/gateway-service/internal/transport/http/tencent_rtc_callback.go b/services/gateway-service/internal/transport/http/tencent_rtc_callback.go new file mode 100644 index 00000000..f1838812 --- /dev/null +++ b/services/gateway-service/internal/transport/http/tencent_rtc_callback.go @@ -0,0 +1,234 @@ +package http + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "strconv" + "strings" + "time" + + roomv1 "hyapp.local/api/proto/room/v1" + "hyapp/pkg/appcode" + "hyapp/pkg/tencentrtc" + "hyapp/pkg/xerr" +) + +const ( + tencentRTCEventGroupRoom = 1 + tencentRTCEventGroupMedia = 2 + tencentRTCEventRoomExit = 104 + tencentRTCEventStartAudio = 203 + tencentRTCEventStopAudio = 204 +) + +// tencentRTCCallbackBody 覆盖当前语音房需要消费的腾讯 RTC 房间/媒体回调字段。 +type tencentRTCCallbackBody struct { + EventGroupID int `json:"EventGroupId"` + EventType int `json:"EventType"` + CallbackTs int64 `json:"CallbackTs"` + EventInfo tencentRTCCallbackEvent `json:"EventInfo"` +} + +type tencentRTCCallbackEvent struct { + RoomID json.RawMessage `json:"RoomId"` + UserID string `json:"UserId"` + EventTs int64 `json:"EventTs"` + EventMsTs int64 `json:"EventMsTs"` + Reason int `json:"Reason"` +} + +type tencentRTCCallbackResponse struct { + Code int `json:"code"` + Message string `json:"message,omitempty"` +} + +// handleTencentRTCCallback 处理腾讯 RTC 服务端事件回调。 +func (h *Handler) handleTencentRTCCallback(writer http.ResponseWriter, request *http.Request) { + if request.Method != http.MethodPost { + writeTencentRTCCallback(writer, http.StatusMethodNotAllowed, 1, "method not allowed") + return + } + + payload, err := io.ReadAll(io.LimitReader(request.Body, 1<<20)) + if err != nil || len(bytes.TrimSpace(payload)) == 0 { + writeTencentRTCCallback(writer, http.StatusBadRequest, 1, "invalid callback body") + return + } + if !h.tencentRTCSDKAppIDMatched(request) { + writeTencentRTCCallback(writer, http.StatusForbidden, 1, "sdk_app_id mismatch") + return + } + if !tencentrtc.VerifyCallbackSignature(h.tencentRTC.CallbackSignKey, payload, request.Header.Get(tencentrtc.CallbackHeaderSign)) { + // 腾讯 RTC 回调签名使用原始 body;配置缺失或签名缺失都必须 fail-closed。 + writeTencentRTCCallback(writer, http.StatusForbidden, 1, "callback signature invalid") + return + } + + var body tencentRTCCallbackBody + if err := json.Unmarshal(payload, &body); err != nil { + writeTencentRTCCallback(writer, http.StatusBadRequest, 1, "invalid callback body") + return + } + + eventType, known := normalizeTencentRTCEventType(body.EventGroupID, body.EventType) + if !known { + // 白名单外事件只做验签和 SDKAppID 校验,避免腾讯新增事件造成重试风暴。 + writeTencentRTCCallback(writer, http.StatusOK, 0, "") + return + } + + roomID, ok := parseTencentRTCRoomID(body.EventInfo.RoomID) + userID, userOK := parseTencentIMUserID(body.EventInfo.UserID) + eventTimeMS := tencentRTCEventTimeMS(body) + if !ok || !userOK || eventTimeMS <= 0 || h.roomClient == nil { + log.Printf("gateway_rtc_callback result=ignored request_id=%s event_group=%d event_type=%d room_id=%q user_id=%q reason=input_invalid", requestIDFromContext(request.Context()), body.EventGroupID, body.EventType, roomID, body.EventInfo.UserID) + writeTencentRTCCallback(writer, http.StatusOK, 0, "") + return + } + + resp, err := h.roomClient.ApplyRTCEvent(request.Context(), &roomv1.ApplyRTCEventRequest{ + Meta: &roomv1.RequestMeta{ + RequestId: requestIDFromContext(request.Context()), + CommandId: tencentRTCCallbackCommandID(body, roomID, userID, eventTimeMS), + ActorUserId: userID, + RoomId: roomID, + AppCode: tencentRTCCallbackAppCode(request), + GatewayNodeId: "gateway-local", + SessionId: fmt.Sprintf("tencent-rtc-%d", body.EventType), + SentAtMs: time.Now().UnixMilli(), + }, + TargetUserId: userID, + EventType: eventType, + EventTimeMs: eventTimeMS, + Reason: tencentRTCCallbackReason(body), + Source: "tencent_rtc_callback", + ExternalEventId: tencentRTCCallbackExternalEventID(body, roomID, userID, eventTimeMS), + }) + if err != nil { + if tencentRTCCallbackCanAckBusinessError(err) { + log.Printf("gateway_rtc_callback result=business_ignored request_id=%s room_id=%s user_id=%d event_group=%d event_type=%d reason=%s", requestIDFromContext(request.Context()), roomID, userID, body.EventGroupID, body.EventType, xerr.ReasonFromGRPC(err)) + writeTencentRTCCallback(writer, http.StatusOK, 0, "") + return + } + log.Printf("gateway_rtc_callback result=room_service_error request_id=%s room_id=%s user_id=%d event_group=%d event_type=%d error=%q", requestIDFromContext(request.Context()), roomID, userID, body.EventGroupID, body.EventType, err.Error()) + writeTencentRTCCallback(writer, http.StatusInternalServerError, 1, "room service error") + return + } + + log.Printf("gateway_rtc_callback result=accepted request_id=%s room_id=%s user_id=%d event_group=%d event_type=%d room_version=%d applied=%t", requestIDFromContext(request.Context()), roomID, userID, body.EventGroupID, body.EventType, resp.GetResult().GetRoomVersion(), resp.GetResult().GetApplied()) + writeTencentRTCCallback(writer, http.StatusOK, 0, "") +} + +func (h *Handler) tencentRTCSDKAppIDMatched(request *http.Request) bool { + if h.tencentRTC.SDKAppID <= 0 { + return false + } + + raw := strings.TrimSpace(request.Header.Get(tencentrtc.CallbackHeaderSDKAppID)) + value, err := strconv.ParseInt(raw, 10, 64) + return err == nil && value == h.tencentRTC.SDKAppID +} + +func normalizeTencentRTCEventType(groupID int, eventType int) (string, bool) { + switch { + case groupID == tencentRTCEventGroupMedia && eventType == tencentRTCEventStartAudio: + return "audio_started", true + case groupID == tencentRTCEventGroupMedia && eventType == tencentRTCEventStopAudio: + return "audio_stopped", true + case groupID == tencentRTCEventGroupRoom && eventType == tencentRTCEventRoomExit: + return "room_exited", true + default: + return "", false + } +} + +func parseTencentRTCRoomID(raw json.RawMessage) (string, bool) { + raw = bytes.TrimSpace(raw) + if len(raw) == 0 || bytes.Equal(raw, []byte("null")) { + return "", false + } + + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.UseNumber() + var value any + if err := decoder.Decode(&value); err != nil { + return "", false + } + + switch typed := value.(type) { + case string: + roomID := strings.TrimSpace(typed) + return roomID, roomID != "" + case json.Number: + roomID := strings.TrimSpace(typed.String()) + return roomID, roomID != "" + default: + return "", false + } +} + +func tencentRTCEventTimeMS(body tencentRTCCallbackBody) int64 { + if body.EventInfo.EventMsTs > 0 { + return body.EventInfo.EventMsTs + } + if body.EventInfo.EventTs > 0 { + return body.EventInfo.EventTs * 1000 + } + + return body.CallbackTs +} + +func tencentRTCCallbackReason(body tencentRTCCallbackBody) string { + switch body.EventType { + case tencentRTCEventRoomExit: + return fmt.Sprintf("rtc_room_exited:%d", body.EventInfo.Reason) + case tencentRTCEventStopAudio: + return fmt.Sprintf("rtc_audio_stopped:%d", body.EventInfo.Reason) + case tencentRTCEventStartAudio: + return "rtc_audio_started" + default: + return fmt.Sprintf("rtc_event:%d:%d", body.EventGroupID, body.EventType) + } +} + +func tencentRTCCallbackCommandID(body tencentRTCCallbackBody, roomID string, userID int64, eventTimeMS int64) string { + return "cmd_" + tencentRTCCallbackDigest(body, roomID, userID, eventTimeMS) +} + +func tencentRTCCallbackExternalEventID(body tencentRTCCallbackBody, roomID string, userID int64, eventTimeMS int64) string { + return "rtc_evt_" + tencentRTCCallbackDigest(body, roomID, userID, eventTimeMS) +} + +func tencentRTCCallbackDigest(body tencentRTCCallbackBody, roomID string, userID int64, eventTimeMS int64) string { + seed := fmt.Sprintf("%d:%d:%s:%d:%d:%d", body.EventGroupID, body.EventType, roomID, userID, eventTimeMS, body.EventInfo.Reason) + sum := sha256.Sum256([]byte(seed)) + return hex.EncodeToString(sum[:16]) +} + +func tencentRTCCallbackAppCode(request *http.Request) string { + if raw := strings.TrimSpace(request.URL.Query().Get("app_code")); raw != "" { + return appcode.Normalize(raw) + } + + return appcode.FromContext(request.Context()) +} + +func tencentRTCCallbackCanAckBusinessError(err error) bool { + reason := xerr.ReasonFromGRPC(err) + return reason == xerr.NotFound || reason == xerr.InvalidArgument || reason == xerr.RoomClosed || reason == xerr.PermissionDenied +} + +func writeTencentRTCCallback(writer http.ResponseWriter, statusCode int, code int, message string) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(statusCode) + _ = json.NewEncoder(writer).Encode(tencentRTCCallbackResponse{ + Code: code, + Message: message, + }) +} diff --git a/services/room-service/internal/room/command/command.go b/services/room-service/internal/room/command/command.go index b6759970..581a4604 100644 --- a/services/room-service/internal/room/command/command.go +++ b/services/room-service/internal/room/command/command.go @@ -89,6 +89,14 @@ type JoinRoom struct { // Type 返回命令类型。 func (JoinRoom) Type() string { return "join_room" } +// RoomHeartbeat 定义房间业务 presence 显式心跳。 +type RoomHeartbeat struct { + Base +} + +// Type 返回命令类型。 +func (RoomHeartbeat) Type() string { return "room_heartbeat" } + // LeaveRoom 定义业务离房请求。 type LeaveRoom struct { Base @@ -143,6 +151,26 @@ type ConfirmMicPublishing struct { // Type 返回命令类型。 func (ConfirmMicPublishing) Type() string { return "confirm_mic_publishing" } +// ApplyRTCEvent 定义由可信腾讯 RTC 服务端回调驱动的房间状态事件。 +type ApplyRTCEvent struct { + Base + // TargetUserID 是腾讯 RTC 回调中的 UserId,必须映射回内部长 user_id。 + TargetUserID int64 `json:"target_user_id"` + // EventType 是 gateway 标准化后的 RTC 事件,当前为 audio_started/audio_stopped/room_exited。 + EventType string `json:"event_type"` + // EventTimeMS 是腾讯 RTC 回调中的 EventMsTs,用于丢弃旧事件。 + EventTimeMS int64 `json:"event_time_ms"` + // Reason 保留腾讯回调 reason 和入口语义,便于 IM 房间消息和审计排障。 + Reason string `json:"reason,omitempty"` + // Source 记录确认来源,当前为 tencent_rtc_callback。 + Source string `json:"source,omitempty"` + // ExternalEventID 是由 gateway 从腾讯事件字段派生的稳定事件标识。 + ExternalEventID string `json:"external_event_id,omitempty"` +} + +// Type 返回命令类型。 +func (ApplyRTCEvent) Type() string { return "apply_rtc_event" } + // ChangeMicSeat 定义换麦位请求。 type ChangeMicSeat struct { Base @@ -302,6 +330,8 @@ func Deserialize(commandType string, payload []byte) (Command, error) { cmd = &CreateRoom{} case JoinRoom{}.Type(): cmd = &JoinRoom{} + case RoomHeartbeat{}.Type(): + cmd = &RoomHeartbeat{} case LeaveRoom{}.Type(): cmd = &LeaveRoom{} case MicUp{}.Type(): @@ -310,6 +340,8 @@ func Deserialize(commandType string, payload []byte) (Command, error) { cmd = &MicDown{} case ConfirmMicPublishing{}.Type(): cmd = &ConfirmMicPublishing{} + case ApplyRTCEvent{}.Type(): + cmd = &ApplyRTCEvent{} case ChangeMicSeat{}.Type(): cmd = &ChangeMicSeat{} case SetMicSeatLock{}.Type(): diff --git a/services/room-service/internal/room/service/presence.go b/services/room-service/internal/room/service/presence.go index 18d2c0ab..09537c57 100644 --- a/services/room-service/internal/room/service/presence.go +++ b/services/room-service/internal/room/service/presence.go @@ -94,6 +94,48 @@ func (s *Service) JoinRoom(ctx context.Context, req *roomv1.JoinRoomRequest) (*r }, nil } +// RoomHeartbeat 显式刷新已在房间内用户的业务 presence。 +func (s *Service) RoomHeartbeat(ctx context.Context, req *roomv1.RoomHeartbeatRequest) (*roomv1.RoomHeartbeatResponse, error) { + ctx = contextFromMeta(ctx, req.GetMeta()) + cmd := command.RoomHeartbeat{ + Base: baseFromMeta(req.GetMeta()), + } + + result, err := s.mutateRoom(ctx, cmd, true, func(now time.Time, current *state.RoomState, _ *rank.LocalRank) (mutationResult, []outbox.Record, error) { + if err := requireActiveRoom(current); err != nil { + return mutationResult{}, nil, err + } + if current.BanUsers[cmd.ActorUserID()] { + // ban 用户不能通过心跳续住业务 presence;KickUser 已经清理 presence,这里是防御脏状态。 + return mutationResult{}, nil, xerr.New(xerr.PermissionDenied, "user is banned") + } + + existing, exists := current.OnlineUsers[cmd.ActorUserID()] + if !exists { + // 心跳只刷新已存在 presence,不能把已离房用户重新加入房间。 + return mutationResult{}, nil, xerr.New(xerr.NotFound, "user not in room") + } + + existing.LastSeenAtMS = now.UnixMilli() + current.Version++ + + snapshot := current.ToProto() + return mutationResult{ + snapshot: snapshot, + user: findProtoUser(snapshot, cmd.ActorUserID()), + }, nil, nil + }) + if err != nil { + return nil, err + } + + return &roomv1.RoomHeartbeatResponse{ + Result: commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()), + User: result.user, + Room: result.snapshot, + }, nil +} + // LeaveRoom 把用户从房间业务态移出。 func (s *Service) LeaveRoom(ctx context.Context, req *roomv1.LeaveRoomRequest) (*roomv1.LeaveRoomResponse, error) { ctx = contextFromMeta(ctx, req.GetMeta()) diff --git a/services/room-service/internal/room/service/recovery.go b/services/room-service/internal/room/service/recovery.go index fd8b3331..06332679 100644 --- a/services/room-service/internal/room/service/recovery.go +++ b/services/room-service/internal/room/service/recovery.go @@ -135,6 +135,14 @@ func replay(current *state.RoomState, cmd command.Command) error { } } current.Version++ + case *command.RoomHeartbeat: + existing, exists := current.OnlineUsers[typed.ActorUserID()] + if !exists { + return fmt.Errorf("room_heartbeat replay actor is not in room: %d", typed.ActorUserID()) + } + // 心跳只刷新 last_seen,不产生用户进房事件。 + existing.LastSeenAtMS = typed.SentAtMS + current.Version++ case *command.LeaveRoom: // 离房回放只删除业务 presence,不涉及腾讯云 IM 连接态。 delete(current.OnlineUsers, typed.ActorUserID()) @@ -174,6 +182,35 @@ func replay(current *state.RoomState, cmd command.Command) error { current.MicSeats[index].PublishState = state.MicPublishPublishing current.MicSeats[index].LastPublishEventTimeMS = typed.EventTimeMS current.Version++ + case *command.ApplyRTCEvent: + switch typed.EventType { + case rtcEventAudioStarted: + seat, exists := current.SeatByUser(typed.TargetUserID) + if !exists { + return fmt.Errorf("apply_rtc_event audio_started replay target is not on seat: %d", typed.TargetUserID) + } + index := current.SeatIndex(seat.SeatNo) + current.MicSeats[index].PublishState = state.MicPublishPublishing + current.MicSeats[index].LastPublishEventTimeMS = typed.EventTimeMS + current.Version++ + case rtcEventAudioStopped: + seat, exists := current.SeatByUser(typed.TargetUserID) + if !exists { + return fmt.Errorf("apply_rtc_event audio_stopped replay target is not on seat: %d", typed.TargetUserID) + } + index := current.SeatIndex(seat.SeatNo) + current.ClearMicSession(index) + current.Version++ + case rtcEventRoomExited: + delete(current.OnlineUsers, typed.TargetUserID) + if seat, exists := current.SeatByUser(typed.TargetUserID); exists { + index := current.SeatIndex(seat.SeatNo) + current.ClearMicSession(index) + } + current.Version++ + default: + return fmt.Errorf("apply_rtc_event replay unsupported event type: %s", typed.EventType) + } case *command.ChangeMicSeat: from, exists := current.SeatByUser(typed.TargetUserID) if !exists { diff --git a/services/room-service/internal/room/service/rtc_event.go b/services/room-service/internal/room/service/rtc_event.go new file mode 100644 index 00000000..897d6996 --- /dev/null +++ b/services/room-service/internal/room/service/rtc_event.go @@ -0,0 +1,267 @@ +package service + +import ( + "context" + "strings" + "time" + + roomeventsv1 "hyapp.local/api/proto/events/room/v1" + roomv1 "hyapp.local/api/proto/room/v1" + "hyapp/pkg/tencentim" + "hyapp/pkg/xerr" + "hyapp/services/room-service/internal/room/command" + "hyapp/services/room-service/internal/room/outbox" + "hyapp/services/room-service/internal/room/rank" + "hyapp/services/room-service/internal/room/state" +) + +const ( + rtcEventAudioStarted = "audio_started" + rtcEventAudioStopped = "audio_stopped" + rtcEventRoomExited = "room_exited" +) + +// ApplyRTCEvent 把已验签的腾讯 RTC 服务端事件落到 Room Cell。 +func (s *Service) ApplyRTCEvent(ctx context.Context, req *roomv1.ApplyRTCEventRequest) (*roomv1.ApplyRTCEventResponse, error) { + ctx = contextFromMeta(ctx, req.GetMeta()) + cmd := command.ApplyRTCEvent{ + Base: baseFromMeta(req.GetMeta()), + TargetUserID: req.GetTargetUserId(), + EventType: strings.TrimSpace(req.GetEventType()), + EventTimeMS: req.GetEventTimeMs(), + Reason: strings.TrimSpace(req.GetReason()), + Source: strings.TrimSpace(req.GetSource()), + ExternalEventID: strings.TrimSpace(req.GetExternalEventId()), + } + if cmd.TargetUserID == 0 { + // gateway 正常会显式传 target_user_id;兜底使用 actor 保持内部调用更易测试。 + cmd.TargetUserID = cmd.ActorUserID() + } + if cmd.Source == "" { + cmd.Source = "rtc_webhook" + } + + result, err := s.mutateRoom(ctx, cmd, true, func(now time.Time, current *state.RoomState, _ *rank.LocalRank) (mutationResult, []outbox.Record, error) { + if cmd.TargetUserID <= 0 || cmd.EventType == "" || cmd.EventTimeMS <= 0 { + return mutationResult{}, nil, xerr.New(xerr.InvalidArgument, "rtc event is incomplete") + } + + switch cmd.EventType { + case rtcEventAudioStarted: + return s.applyRTCAudioStarted(now, current, cmd) + case rtcEventAudioStopped: + return s.applyRTCAudioStopped(now, current, cmd) + case rtcEventRoomExited: + return s.applyRTCRoomExited(now, current, cmd) + default: + return mutationResult{}, nil, xerr.New(xerr.InvalidArgument, "rtc event type is unsupported") + } + }) + if err != nil { + return nil, err + } + + return &roomv1.ApplyRTCEventResponse{ + Result: commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()), + SeatNo: result.seatNo, + Room: result.snapshot, + }, nil +} + +func (s *Service) applyRTCAudioStarted(now time.Time, current *state.RoomState, cmd command.ApplyRTCEvent) (mutationResult, []outbox.Record, error) { + if err := requireActiveRoom(current); err != nil { + return mutationResult{}, nil, err + } + if _, exists := current.OnlineUsers[cmd.TargetUserID]; !exists { + // RTC 事件不拥有业务进房事实;用户不在业务 presence 时只忽略旧事件。 + return mutationResult{snapshot: current.ToProto()}, nil, nil + } + + seat, exists := current.SeatByUser(cmd.TargetUserID) + if !exists { + return mutationResult{snapshot: current.ToProto()}, nil, nil + } + if !rtcEventMatchesCurrentMicSession(seat, cmd.EventTimeMS, s.micPublishTimeout) { + return mutationResult{snapshot: current.ToProto(), seatNo: seat.SeatNo}, nil, nil + } + if seat.PublishState == state.MicPublishPublishing { + return mutationResult{snapshot: current.ToProto(), seatNo: seat.SeatNo}, nil, nil + } + if seat.PublishState != state.MicPublishPending { + return mutationResult{snapshot: current.ToProto(), seatNo: seat.SeatNo}, nil, nil + } + + index := current.SeatIndex(seat.SeatNo) + current.MicSeats[index].PublishState = state.MicPublishPublishing + current.MicSeats[index].LastPublishEventTimeMS = cmd.EventTimeMS + current.Version++ + + micEvent, err := outbox.Build(current.RoomID, "RoomMicChanged", current.Version, now, &roomeventsv1.RoomMicChanged{ + ActorUserId: cmd.ActorUserID(), + TargetUserId: cmd.TargetUserID, + FromSeat: seat.SeatNo, + ToSeat: seat.SeatNo, + Action: "publish_confirmed", + MicSessionId: seat.MicSessionID, + PublishState: state.MicPublishPublishing, + PublishDeadlineMs: seat.PublishDeadlineMS, + PublishEventTimeMs: cmd.EventTimeMS, + }) + if err != nil { + return mutationResult{}, nil, err + } + + return mutationResult{ + snapshot: current.ToProto(), + seatNo: seat.SeatNo, + syncEvent: &tencentim.RoomEvent{ + EventID: micEvent.EventID, + RoomID: current.RoomID, + EventType: "room_mic_publish_confirmed", + ActorUserID: cmd.ActorUserID(), + TargetUserID: cmd.TargetUserID, + SeatNo: seat.SeatNo, + RoomVersion: current.Version, + Attributes: map[string]string{ + "action": "publish_confirmed", + "publish_state": state.MicPublishPublishing, + "mic_session_id": seat.MicSessionID, + "publish_event_time_ms": int64String(cmd.EventTimeMS), + "source": cmd.Source, + "external_event_id": cmd.ExternalEventID, + }, + }, + }, []outbox.Record{micEvent}, nil +} + +func (s *Service) applyRTCAudioStopped(now time.Time, current *state.RoomState, cmd command.ApplyRTCEvent) (mutationResult, []outbox.Record, error) { + seat, exists := current.SeatByUser(cmd.TargetUserID) + if !exists { + return mutationResult{snapshot: current.ToProto()}, nil, nil + } + if !rtcStopEventMatchesCurrentMicSession(seat, cmd.EventTimeMS, s.micPublishTimeout) { + return mutationResult{snapshot: current.ToProto(), seatNo: seat.SeatNo}, nil, nil + } + + index := current.SeatIndex(seat.SeatNo) + micSessionID := current.MicSeats[index].MicSessionID + current.ClearMicSession(index) + current.Version++ + + micEvent, err := outbox.Build(current.RoomID, "RoomMicChanged", current.Version, now, &roomeventsv1.RoomMicChanged{ + ActorUserId: cmd.ActorUserID(), + TargetUserId: cmd.TargetUserID, + FromSeat: seat.SeatNo, + ToSeat: 0, + Action: "down", + MicSessionId: micSessionID, + PublishState: state.MicPublishIdle, + Reason: cmd.Reason, + PublishEventTimeMs: cmd.EventTimeMS, + }) + if err != nil { + return mutationResult{}, nil, err + } + + return mutationResult{ + snapshot: current.ToProto(), + seatNo: seat.SeatNo, + syncEvent: &tencentim.RoomEvent{ + EventID: micEvent.EventID, + RoomID: current.RoomID, + EventType: "room_mic_down", + ActorUserID: cmd.ActorUserID(), + TargetUserID: cmd.TargetUserID, + SeatNo: seat.SeatNo, + RoomVersion: current.Version, + Attributes: map[string]string{ + "action": "down", + "publish_state": state.MicPublishIdle, + "mic_session_id": micSessionID, + "reason": cmd.Reason, + "publish_event_time_ms": int64String(cmd.EventTimeMS), + "source": cmd.Source, + "external_event_id": cmd.ExternalEventID, + }, + }, + }, []outbox.Record{micEvent}, nil +} + +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 已被更新到事件之后,保留当前重连状态。 + 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 { + 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 +} + +func rtcEventMatchesCurrentMicSession(seat state.MicSeat, eventTimeMS int64, timeout time.Duration) bool { + if !rtcStopEventMatchesCurrentMicSession(seat, eventTimeMS, timeout) { + return false + } + if seat.PublishDeadlineMS > 0 && eventTimeMS > seat.PublishDeadlineMS { + return false + } + + return true +} + +func rtcStopEventMatchesCurrentMicSession(seat state.MicSeat, eventTimeMS int64, timeout time.Duration) bool { + if seat.MicSessionID == "" || eventTimeMS <= seat.LastPublishEventTimeMS { + return false + } + if createdAtMS := rtcMicSessionCreatedAtMS(seat, timeout); createdAtMS > 0 && eventTimeMS < createdAtMS { + return false + } + + return true +} + +func rtcMicSessionCreatedAtMS(seat state.MicSeat, timeout time.Duration) int64 { + timeoutMS := timeout.Milliseconds() + if seat.PublishDeadlineMS <= 0 || timeoutMS <= 0 { + return 0 + } + + return seat.PublishDeadlineMS - timeoutMS +} diff --git a/services/room-service/internal/room/service/service_test.go b/services/room-service/internal/room/service/service_test.go index 1c893169..a4d5fa9d 100644 --- a/services/room-service/internal/room/service/service_test.go +++ b/services/room-service/internal/room/service/service_test.go @@ -569,6 +569,85 @@ func TestMicPublishingConfirmAndStaleEvents(t *testing.T) { } } +func TestApplyRTCEventConfirmsAudioAndClearsOnStopOrExit(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + usedClock := &mutableClock{now: time.UnixMilli(1_700_000_000_000)} + syncPublisher := &fakeSyncPublisher{} + svc := newRoomServiceWithClock("node-a", 1, router.NewMemoryDirectory(), repository, syncPublisher, &fakeOutboxPublisher{}, usedClock, time.Minute) + roomID := "room-rtc-event" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 1), SeatCount: 4, Mode: "voice", RoomName: "Test 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 user2 failed: %v", err) + } + micResp, err := svc.MicUp(ctx, &roomv1.MicUpRequest{Meta: roomservice.NewRequestMeta(roomID, 2), SeatNo: 1}) + if err != nil { + t.Fatalf("MicUp user2 failed: %v", err) + } + + startEventTime := usedClock.now.Add(time.Second).UnixMilli() + startResp, err := svc.ApplyRTCEvent(ctx, &roomv1.ApplyRTCEventRequest{ + Meta: roomservice.NewRequestMeta(roomID, 2), + TargetUserId: 2, + EventType: "audio_started", + EventTimeMs: startEventTime, + Source: "tencent_rtc_callback", + ExternalEventId: "rtc_evt_start", + }) + if err != nil { + t.Fatalf("ApplyRTCEvent audio_started failed: %v", err) + } + seat := findSeat(startResp.GetRoom(), 1) + if seat == nil || seat.GetPublishState() != "publishing" || seat.GetMicSessionId() != micResp.GetMicSessionId() || seat.GetLastPublishEventTimeMs() != startEventTime { + t.Fatalf("RTC audio_started should confirm current mic session: seat=%+v", seat) + } + + stopResp, err := svc.ApplyRTCEvent(ctx, &roomv1.ApplyRTCEventRequest{ + Meta: roomservice.NewRequestMeta(roomID, 2), + TargetUserId: 2, + EventType: "audio_stopped", + EventTimeMs: usedClock.now.Add(2 * time.Second).UnixMilli(), + Reason: "rtc_audio_stopped:0", + Source: "tencent_rtc_callback", + }) + if err != nil { + t.Fatalf("ApplyRTCEvent audio_stopped failed: %v", err) + } + if seat := findSeat(stopResp.GetRoom(), 1); seat == nil || seat.GetUserId() != 0 || seat.GetMicSessionId() != "" { + t.Fatalf("RTC audio_stopped should release mic seat: seat=%+v", seat) + } + + if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 3)}); err != nil { + t.Fatalf("JoinRoom user3 failed: %v", err) + } + if _, err := svc.MicUp(ctx, &roomv1.MicUpRequest{Meta: roomservice.NewRequestMeta(roomID, 3), SeatNo: 2}); err != nil { + t.Fatalf("MicUp user3 failed: %v", err) + } + exitResp, err := svc.ApplyRTCEvent(ctx, &roomv1.ApplyRTCEventRequest{ + Meta: roomservice.NewRequestMeta(roomID, 3), + TargetUserId: 3, + EventType: "room_exited", + EventTimeMs: usedClock.now.Add(3 * time.Second).UnixMilli(), + Reason: "rtc_room_exited:2", + Source: "tencent_rtc_callback", + }) + 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 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) + } +} + func TestMicPublishTimeoutMicDownsPendingSession(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) @@ -931,6 +1010,44 @@ func TestRepeatedJoinRefreshesPresenceWithoutDuplicateJoinEvent(t *testing.T) { } } +func TestRoomHeartbeatRefreshesExistingPresenceOnly(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + usedClock := &mutableClock{now: time.UnixMilli(1_700_000_000_000)} + svc := newRoomServiceWithClock("node-a", 1, router.NewMemoryDirectory(), repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}, usedClock, time.Minute) + roomID := "room-heartbeat" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ + Meta: roomservice.NewRequestMeta(roomID, 1), + SeatCount: 4, + Mode: "voice", + RoomName: "Test 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) + } + beforeJoinEvents := countPendingOutboxType(t, repository, "RoomUserJoined") + + usedClock.now = usedClock.now.Add(30 * time.Second) + heartbeatResp, err := svc.RoomHeartbeat(ctx, &roomv1.RoomHeartbeatRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}) + if err != nil { + t.Fatalf("RoomHeartbeat failed: %v", err) + } + user := findRoomUser(heartbeatResp.GetRoom(), 2) + if user == nil || user.GetLastSeenAtMs() != usedClock.now.UnixMilli() { + t.Fatalf("heartbeat should refresh last_seen only: user=%+v now=%d", user, usedClock.now.UnixMilli()) + } + if after := countPendingOutboxType(t, repository, "RoomUserJoined"); after != beforeJoinEvents { + t.Fatalf("heartbeat must not create join outbox: before=%d after=%d", beforeJoinEvents, after) + } + + if _, err := svc.RoomHeartbeat(ctx, &roomv1.RoomHeartbeatRequest{Meta: roomservice.NewRequestMeta(roomID, 3)}); !xerr.IsCode(err, xerr.NotFound) { + t.Fatalf("heartbeat must not create missing presence, got %v", err) + } +} + // TestLeaveRoomReleasesSeatAndBlocksGuards 验证离房同时移除 presence 和麦位占用。 func TestLeaveRoomReleasesSeatAndBlocksGuards(t *testing.T) { ctx := context.Background() diff --git a/services/room-service/internal/transport/grpc/server.go b/services/room-service/internal/transport/grpc/server.go index 15e4806f..d983957e 100644 --- a/services/room-service/internal/transport/grpc/server.go +++ b/services/room-service/internal/transport/grpc/server.go @@ -54,6 +54,13 @@ func (s *Server) JoinRoom(ctx context.Context, req *roomv1.JoinRoomRequest) (*ro return mapServiceResult(s.svc.JoinRoom(ctx, req)) } +// RoomHeartbeat 代理到领域服务。 +func (s *Server) RoomHeartbeat(ctx context.Context, req *roomv1.RoomHeartbeatRequest) (*roomv1.RoomHeartbeatResponse, error) { + // 心跳只刷新已有业务 presence,不能隐式创建进房状态。 + ctx = contextWithMetaApp(ctx, req.GetMeta()) + return mapServiceResult(s.svc.RoomHeartbeat(ctx, req)) +} + // LeaveRoom 代理到领域服务。 func (s *Server) LeaveRoom(ctx context.Context, req *roomv1.LeaveRoomRequest) (*roomv1.LeaveRoomResponse, error) { // LeaveRoom 不直接操作腾讯云 IM 连接,只修改房间业务态。 @@ -89,6 +96,13 @@ func (s *Server) ConfirmMicPublishing(ctx context.Context, req *roomv1.ConfirmMi return mapServiceResult(s.svc.ConfirmMicPublishing(ctx, req)) } +// ApplyRTCEvent 代理到领域服务。 +func (s *Server) ApplyRTCEvent(ctx context.Context, req *roomv1.ApplyRTCEventRequest) (*roomv1.ApplyRTCEventResponse, error) { + // 腾讯 RTC 回调已在 gateway 验签;房间状态变化仍必须由 Room Cell 串行提交。 + ctx = contextWithMetaApp(ctx, req.GetMeta()) + return mapServiceResult(s.svc.ApplyRTCEvent(ctx, req)) +} + // SetMicSeatLock 代理到领域服务。 func (s *Server) SetMicSeatLock(ctx context.Context, req *roomv1.SetMicSeatLockRequest) (*roomv1.SetMicSeatLockResponse, error) { // 锁麦权限和目标麦位状态由 Room Cell 判定。 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 08725943..151283f9 100644 --- a/services/user-service/deploy/mysql/initdb/001_user_service.sql +++ b/services/user-service/deploy/mysql/initdb/001_user_service.sql @@ -1272,3 +1272,165 @@ CREATE TABLE IF NOT EXISTS login_audit ( KEY idx_login_audit_request_id (app_code, request_id), KEY idx_login_audit_created_at (app_code, created_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 本地联调测试账号。 +-- 密码登录仍以 users.current_display_user_id 为账号,password_accounts 只保存 user_id 维度密码身份。 +INSERT INTO users ( + app_code, + user_id, + default_display_user_id, + current_display_user_id, + current_display_user_id_kind, + current_display_user_id_expires_at_ms, + username, + profile_completed, + profile_completed_at_ms, + onboarding_status, + status, + created_at_ms, + updated_at_ms +) +VALUES ( + 'lalu', + 123456, + '123456', + '123456', + 'default', + NULL, + 'test_123456', + 1, + 0, + 'completed', + 'active', + 0, + 0 +) +ON DUPLICATE KEY UPDATE + current_display_user_id = VALUES(current_display_user_id), + current_display_user_id_kind = VALUES(current_display_user_id_kind), + current_display_user_id_expires_at_ms = VALUES(current_display_user_id_expires_at_ms), + username = VALUES(username), + profile_completed = VALUES(profile_completed), + onboarding_status = VALUES(onboarding_status), + status = VALUES(status), + updated_at_ms = VALUES(updated_at_ms); + +INSERT INTO user_display_user_ids ( + app_code, + display_user_id, + user_id, + display_user_id_kind, + status, + assigned_at_ms, + activated_at_ms, + created_at_ms, + updated_at_ms +) +VALUES ('lalu', '123456', 123456, 'default', 'active', 0, 0, 0, 0) +ON DUPLICATE KEY UPDATE + display_user_id = VALUES(display_user_id), + display_user_id_kind = VALUES(display_user_id_kind), + status = VALUES(status), + activated_at_ms = VALUES(activated_at_ms), + updated_at_ms = VALUES(updated_at_ms); + +INSERT INTO password_accounts ( + app_code, + user_id, + password_hash, + hash_alg, + created_at_ms, + updated_at_ms +) +VALUES ( + 'lalu', + 123456, + '$2a$10$9eyyJvfGdkb3oU8EAPUHiuLz1C/AmhGTU1nq8AeOIMNFwznk7B69G', + 'bcrypt', + 0, + 0 +) +ON DUPLICATE KEY UPDATE + password_hash = VALUES(password_hash), + hash_alg = VALUES(hash_alg), + updated_at_ms = VALUES(updated_at_ms); + +INSERT INTO users ( + app_code, + user_id, + default_display_user_id, + current_display_user_id, + current_display_user_id_kind, + current_display_user_id_expires_at_ms, + username, + profile_completed, + profile_completed_at_ms, + onboarding_status, + status, + created_at_ms, + updated_at_ms +) +VALUES ( + 'lalu', + 12345678, + '12345678', + '12345678', + 'default', + NULL, + 'test_12345678', + 1, + 0, + 'completed', + 'active', + 0, + 0 +) +ON DUPLICATE KEY UPDATE + current_display_user_id = VALUES(current_display_user_id), + current_display_user_id_kind = VALUES(current_display_user_id_kind), + current_display_user_id_expires_at_ms = VALUES(current_display_user_id_expires_at_ms), + username = VALUES(username), + profile_completed = VALUES(profile_completed), + onboarding_status = VALUES(onboarding_status), + status = VALUES(status), + updated_at_ms = VALUES(updated_at_ms); + +INSERT INTO user_display_user_ids ( + app_code, + display_user_id, + user_id, + display_user_id_kind, + status, + assigned_at_ms, + activated_at_ms, + created_at_ms, + updated_at_ms +) +VALUES ('lalu', '12345678', 12345678, 'default', 'active', 0, 0, 0, 0) +ON DUPLICATE KEY UPDATE + display_user_id = VALUES(display_user_id), + display_user_id_kind = VALUES(display_user_id_kind), + status = VALUES(status), + activated_at_ms = VALUES(activated_at_ms), + updated_at_ms = VALUES(updated_at_ms); + +INSERT INTO password_accounts ( + app_code, + user_id, + password_hash, + hash_alg, + created_at_ms, + updated_at_ms +) +VALUES ( + 'lalu', + 12345678, + '$2a$10$2sdtdAzFlPu23vC0vMQT6OIIm5.KCzATuwvn8i09/SKHz.hmkzJce', + 'bcrypt', + 0, + 0 +) +ON DUPLICATE KEY UPDATE + password_hash = VALUES(password_hash), + hash_alg = VALUES(hash_alg), + updated_at_ms = VALUES(updated_at_ms);