From 975d21a63ade783a00a076ca35d6701f30ac6071 Mon Sep 17 00:00:00 2001 From: local Date: Wed, 6 May 2026 00:30:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=88=BF=E9=97=B4=E7=8A=B6?= =?UTF-8?q?=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/proto/events/room/v1/events.pb.go | 384 +++-- api/proto/events/room/v1/events.proto | 6 + api/proto/room/v1/room.pb.go | 1498 +++++++++-------- api/proto/room/v1/room.proto | 13 + api/proto/room/v1/room_grpc.pb.go | 38 + docs/room-cell-state-machines.md | 127 ++ docs/room-outbox-compensation-development.md | 65 +- docs/voice-room-basic-loop-implementation.md | 6 + services/room-service/configs/config.yaml | 2 +- .../deploy/mysql/initdb/001_room_service.sql | 17 +- services/room-service/internal/app/app.go | 3 + .../internal/integration/clients.go | 2 +- .../internal/room/command/command.go | 12 + .../internal/room/outbox/outbox.go | 14 +- .../internal/room/service/authorization.go | 2 +- .../internal/room/service/create_room.go | 35 +- .../internal/room/service/helpers.go | 33 +- .../internal/room/service/lifecycle.go | 75 +- .../room-service/internal/room/service/mic.go | 2 +- .../room/service/mic_publish_timeout.go | 23 + .../internal/room/service/outbox_worker.go | 20 +- .../internal/room/service/pipeline.go | 85 +- .../internal/room/service/presence.go | 23 + .../internal/room/service/recovery.go | 28 +- .../internal/room/service/repository.go | 24 +- .../internal/room/service/service.go | 17 + .../internal/room/service/service_test.go | 402 ++++- .../internal/room/service/snapshot.go | 4 + .../room-service/internal/room/state/state.go | 11 +- .../room-service/internal/router/directory.go | 15 + .../internal/router/redis_directory.go | 34 + .../internal/storage/mysql/repository.go | 256 ++- .../internal/testutil/mysqltest/mysqltest.go | 10 +- .../internal/transport/grpc/server.go | 7 + 34 files changed, 2309 insertions(+), 984 deletions(-) create mode 100644 docs/room-cell-state-machines.md diff --git a/api/proto/events/room/v1/events.pb.go b/api/proto/events/room/v1/events.pb.go index 9645a796..0ac4ffc4 100644 --- a/api/proto/events/room/v1/events.pb.go +++ b/api/proto/events/room/v1/events.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v5.29.2 +// protoc v7.34.1 // source: proto/events/room/v1/events.proto package roomeventsv1 @@ -318,6 +318,62 @@ func (x *RoomUserLeft) GetUserId() int64 { return 0 } +// RoomClosed 表达房间生命周期关闭完成。 +type RoomClosed struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ActorUserId int64 `protobuf:"varint,1,opt,name=actor_user_id,json=actorUserId,proto3" json:"actor_user_id,omitempty"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` +} + +func (x *RoomClosed) Reset() { + *x = RoomClosed{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_events_room_v1_events_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RoomClosed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoomClosed) ProtoMessage() {} + +func (x *RoomClosed) ProtoReflect() protoreflect.Message { + mi := &file_proto_events_room_v1_events_proto_msgTypes[4] + 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 RoomClosed.ProtoReflect.Descriptor instead. +func (*RoomClosed) Descriptor() ([]byte, []int) { + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{4} +} + +func (x *RoomClosed) GetActorUserId() int64 { + if x != nil { + return x.ActorUserId + } + return 0 +} + +func (x *RoomClosed) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + // RoomMicChanged 表达任意上下麦和换麦位动作。 type RoomMicChanged struct { state protoimpl.MessageState @@ -342,7 +398,7 @@ type RoomMicChanged struct { func (x *RoomMicChanged) Reset() { *x = RoomMicChanged{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[4] + mi := &file_proto_events_room_v1_events_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -355,7 +411,7 @@ func (x *RoomMicChanged) String() string { func (*RoomMicChanged) ProtoMessage() {} func (x *RoomMicChanged) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[4] + mi := &file_proto_events_room_v1_events_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -368,7 +424,7 @@ func (x *RoomMicChanged) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomMicChanged.ProtoReflect.Descriptor instead. func (*RoomMicChanged) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{4} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{5} } func (x *RoomMicChanged) GetActorUserId() int64 { @@ -455,7 +511,7 @@ type RoomMicSeatLocked struct { func (x *RoomMicSeatLocked) Reset() { *x = RoomMicSeatLocked{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[5] + mi := &file_proto_events_room_v1_events_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -468,7 +524,7 @@ func (x *RoomMicSeatLocked) String() string { func (*RoomMicSeatLocked) ProtoMessage() {} func (x *RoomMicSeatLocked) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[5] + mi := &file_proto_events_room_v1_events_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -481,7 +537,7 @@ func (x *RoomMicSeatLocked) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomMicSeatLocked.ProtoReflect.Descriptor instead. func (*RoomMicSeatLocked) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{5} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{6} } func (x *RoomMicSeatLocked) GetActorUserId() int64 { @@ -518,7 +574,7 @@ type RoomChatEnabledChanged struct { func (x *RoomChatEnabledChanged) Reset() { *x = RoomChatEnabledChanged{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[6] + mi := &file_proto_events_room_v1_events_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -531,7 +587,7 @@ func (x *RoomChatEnabledChanged) String() string { func (*RoomChatEnabledChanged) ProtoMessage() {} func (x *RoomChatEnabledChanged) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[6] + mi := &file_proto_events_room_v1_events_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -544,7 +600,7 @@ func (x *RoomChatEnabledChanged) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomChatEnabledChanged.ProtoReflect.Descriptor instead. func (*RoomChatEnabledChanged) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{6} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{7} } func (x *RoomChatEnabledChanged) GetActorUserId() int64 { @@ -575,7 +631,7 @@ type RoomAdminChanged struct { func (x *RoomAdminChanged) Reset() { *x = RoomAdminChanged{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[7] + mi := &file_proto_events_room_v1_events_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -588,7 +644,7 @@ func (x *RoomAdminChanged) String() string { func (*RoomAdminChanged) ProtoMessage() {} func (x *RoomAdminChanged) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[7] + mi := &file_proto_events_room_v1_events_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -601,7 +657,7 @@ func (x *RoomAdminChanged) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomAdminChanged.ProtoReflect.Descriptor instead. func (*RoomAdminChanged) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{7} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{8} } func (x *RoomAdminChanged) GetActorUserId() int64 { @@ -639,7 +695,7 @@ type RoomHostTransferred struct { func (x *RoomHostTransferred) Reset() { *x = RoomHostTransferred{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[8] + mi := &file_proto_events_room_v1_events_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -652,7 +708,7 @@ func (x *RoomHostTransferred) String() string { func (*RoomHostTransferred) ProtoMessage() {} func (x *RoomHostTransferred) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[8] + mi := &file_proto_events_room_v1_events_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -665,7 +721,7 @@ func (x *RoomHostTransferred) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomHostTransferred.ProtoReflect.Descriptor instead. func (*RoomHostTransferred) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{8} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{9} } func (x *RoomHostTransferred) GetActorUserId() int64 { @@ -703,7 +759,7 @@ type RoomUserMuted struct { func (x *RoomUserMuted) Reset() { *x = RoomUserMuted{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[9] + mi := &file_proto_events_room_v1_events_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -716,7 +772,7 @@ func (x *RoomUserMuted) String() string { func (*RoomUserMuted) ProtoMessage() {} func (x *RoomUserMuted) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[9] + mi := &file_proto_events_room_v1_events_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -729,7 +785,7 @@ func (x *RoomUserMuted) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomUserMuted.ProtoReflect.Descriptor instead. func (*RoomUserMuted) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{9} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{10} } func (x *RoomUserMuted) GetActorUserId() int64 { @@ -766,7 +822,7 @@ type RoomUserKicked struct { func (x *RoomUserKicked) Reset() { *x = RoomUserKicked{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[10] + mi := &file_proto_events_room_v1_events_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -779,7 +835,7 @@ func (x *RoomUserKicked) String() string { func (*RoomUserKicked) ProtoMessage() {} func (x *RoomUserKicked) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[10] + mi := &file_proto_events_room_v1_events_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -792,7 +848,7 @@ func (x *RoomUserKicked) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomUserKicked.ProtoReflect.Descriptor instead. func (*RoomUserKicked) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{10} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{11} } func (x *RoomUserKicked) GetActorUserId() int64 { @@ -822,7 +878,7 @@ type RoomUserUnbanned struct { func (x *RoomUserUnbanned) Reset() { *x = RoomUserUnbanned{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[11] + mi := &file_proto_events_room_v1_events_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -835,7 +891,7 @@ func (x *RoomUserUnbanned) String() string { func (*RoomUserUnbanned) ProtoMessage() {} func (x *RoomUserUnbanned) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[11] + mi := &file_proto_events_room_v1_events_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -848,7 +904,7 @@ func (x *RoomUserUnbanned) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomUserUnbanned.ProtoReflect.Descriptor instead. func (*RoomUserUnbanned) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{11} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{12} } func (x *RoomUserUnbanned) GetActorUserId() int64 { @@ -882,7 +938,7 @@ type RoomGiftSent struct { func (x *RoomGiftSent) Reset() { *x = RoomGiftSent{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[12] + mi := &file_proto_events_room_v1_events_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -895,7 +951,7 @@ func (x *RoomGiftSent) String() string { func (*RoomGiftSent) ProtoMessage() {} func (x *RoomGiftSent) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[12] + mi := &file_proto_events_room_v1_events_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -908,7 +964,7 @@ func (x *RoomGiftSent) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomGiftSent.ProtoReflect.Descriptor instead. func (*RoomGiftSent) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{12} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{13} } func (x *RoomGiftSent) GetSenderUserId() int64 { @@ -966,7 +1022,7 @@ type RoomHeatChanged struct { func (x *RoomHeatChanged) Reset() { *x = RoomHeatChanged{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[13] + mi := &file_proto_events_room_v1_events_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -979,7 +1035,7 @@ func (x *RoomHeatChanged) String() string { func (*RoomHeatChanged) ProtoMessage() {} func (x *RoomHeatChanged) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[13] + mi := &file_proto_events_room_v1_events_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -992,7 +1048,7 @@ func (x *RoomHeatChanged) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomHeatChanged.ProtoReflect.Descriptor instead. func (*RoomHeatChanged) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{13} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{14} } func (x *RoomHeatChanged) GetDelta() int64 { @@ -1023,7 +1079,7 @@ type RoomRankChanged struct { func (x *RoomRankChanged) Reset() { *x = RoomRankChanged{} if protoimpl.UnsafeEnabled { - mi := &file_proto_events_room_v1_events_proto_msgTypes[14] + mi := &file_proto_events_room_v1_events_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1036,7 +1092,7 @@ func (x *RoomRankChanged) String() string { func (*RoomRankChanged) ProtoMessage() {} func (x *RoomRankChanged) ProtoReflect() protoreflect.Message { - mi := &file_proto_events_room_v1_events_proto_msgTypes[14] + mi := &file_proto_events_room_v1_events_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1049,7 +1105,7 @@ func (x *RoomRankChanged) ProtoReflect() protoreflect.Message { // Deprecated: Use RoomRankChanged.ProtoReflect.Descriptor instead. func (*RoomRankChanged) Descriptor() ([]byte, []int) { - return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{14} + return file_proto_events_room_v1_events_proto_rawDescGZIP(), []int{15} } func (x *RoomRankChanged) GetUserId() int64 { @@ -1115,105 +1171,110 @@ var file_proto_events_room_v1_events_proto_rawDesc = []byte{ 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0x27, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x66, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x22, 0xee, 0x02, 0x0a, 0x0e, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, 0x69, 0x63, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, - 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, - 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x53, 0x65, 0x61, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, - 0x5f, 0x73, 0x65, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x6f, 0x53, - 0x65, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x6d, - 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, - 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x2e, - 0x0a, 0x13, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, - 0x6e, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x73, 0x68, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x4d, 0x73, 0x12, 0x31, - 0x0a, 0x15, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, - 0x73, 0x22, 0x68, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, - 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, + 0x22, 0x48, 0x0a, 0x0a, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x22, + 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xee, 0x02, 0x0a, 0x0e, 0x52, + 0x6f, 0x6f, 0x6d, 0x4d, 0x69, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, + 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x5f, + 0x73, 0x65, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, + 0x53, 0x65, 0x61, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x6f, 0x53, 0x65, 0x61, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, + 0x69, 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x5f, 0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6d, 0x73, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x44, 0x65, + 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x4d, 0x73, 0x12, 0x31, 0x0a, 0x15, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, + 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x22, 0x68, 0x0a, 0x11, 0x52, + 0x6f, 0x6f, 0x6d, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, + 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x16, 0x0a, + 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, + 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x22, 0x56, 0x0a, 0x16, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x68, 0x61, + 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, + 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x76, 0x0a, + 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x8b, 0x01, 0x0a, 0x13, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, + 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x12, 0x22, 0x0a, + 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x27, 0x0a, 0x10, 0x6f, 0x6c, 0x64, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6f, 0x6c, 0x64, + 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x10, 0x6e, 0x65, + 0x77, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x65, 0x77, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x22, 0x6f, 0x0a, 0x0d, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4d, + 0x75, 0x74, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, + 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, + 0x75, 0x74, 0x65, 0x64, 0x22, 0x5a, 0x0a, 0x0e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, + 0x4b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, - 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, - 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, - 0x74, 0x4e, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x22, 0x56, 0x0a, 0x16, 0x52, - 0x6f, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, - 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x22, 0x76, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, - 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, - 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x8b, 0x01, 0x0a, 0x13, - 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, - 0x72, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, - 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x10, 0x6f, 0x6c, 0x64, 0x5f, 0x68, - 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0d, 0x6f, 0x6c, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x27, 0x0a, 0x10, 0x6e, 0x65, 0x77, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x65, 0x77, 0x48, - 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x6f, 0x0a, 0x0d, 0x52, 0x6f, 0x6f, - 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, - 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, - 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x22, 0x5a, 0x0a, 0x0e, 0x52, 0x6f, - 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, - 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x5c, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, - 0x65, 0x72, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, - 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, - 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x22, 0xdf, 0x01, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x47, 0x69, 0x66, - 0x74, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, - 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, - 0x65, 0x6e, 0x64, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, - 0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, - 0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66, - 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x67, - 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, - 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, - 0x65, 0x69, 0x70, 0x74, 0x49, 0x64, 0x22, 0x4a, 0x0a, 0x0f, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, - 0x61, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, - 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x12, - 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x65, - 0x61, 0x74, 0x22, 0x5f, 0x0a, 0x0f, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x61, 0x6e, 0x6b, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, - 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, - 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x6f, 0x6f, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x6f, 0x6f, 0x6d, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, + 0x22, 0x5c, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x55, 0x6e, 0x62, 0x61, + 0x6e, 0x6e, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, + 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0xdf, + 0x01, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x47, 0x69, 0x66, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x12, + 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, + 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, + 0x66, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, + 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x49, 0x64, + 0x22, 0x4a, 0x0a, 0x0f, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x74, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x74, 0x22, 0x5f, 0x0a, 0x0f, + 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x61, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, + 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x33, 0x5a, + 0x31, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x6f, + 0x6f, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x6f, 0x6f, 0x6d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1228,23 +1289,24 @@ func file_proto_events_room_v1_events_proto_rawDescGZIP() []byte { return file_proto_events_room_v1_events_proto_rawDescData } -var file_proto_events_room_v1_events_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_proto_events_room_v1_events_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_proto_events_room_v1_events_proto_goTypes = []any{ (*EventEnvelope)(nil), // 0: hyapp.events.room.v1.EventEnvelope (*RoomCreated)(nil), // 1: hyapp.events.room.v1.RoomCreated (*RoomUserJoined)(nil), // 2: hyapp.events.room.v1.RoomUserJoined (*RoomUserLeft)(nil), // 3: hyapp.events.room.v1.RoomUserLeft - (*RoomMicChanged)(nil), // 4: hyapp.events.room.v1.RoomMicChanged - (*RoomMicSeatLocked)(nil), // 5: hyapp.events.room.v1.RoomMicSeatLocked - (*RoomChatEnabledChanged)(nil), // 6: hyapp.events.room.v1.RoomChatEnabledChanged - (*RoomAdminChanged)(nil), // 7: hyapp.events.room.v1.RoomAdminChanged - (*RoomHostTransferred)(nil), // 8: hyapp.events.room.v1.RoomHostTransferred - (*RoomUserMuted)(nil), // 9: hyapp.events.room.v1.RoomUserMuted - (*RoomUserKicked)(nil), // 10: hyapp.events.room.v1.RoomUserKicked - (*RoomUserUnbanned)(nil), // 11: hyapp.events.room.v1.RoomUserUnbanned - (*RoomGiftSent)(nil), // 12: hyapp.events.room.v1.RoomGiftSent - (*RoomHeatChanged)(nil), // 13: hyapp.events.room.v1.RoomHeatChanged - (*RoomRankChanged)(nil), // 14: hyapp.events.room.v1.RoomRankChanged + (*RoomClosed)(nil), // 4: hyapp.events.room.v1.RoomClosed + (*RoomMicChanged)(nil), // 5: hyapp.events.room.v1.RoomMicChanged + (*RoomMicSeatLocked)(nil), // 6: hyapp.events.room.v1.RoomMicSeatLocked + (*RoomChatEnabledChanged)(nil), // 7: hyapp.events.room.v1.RoomChatEnabledChanged + (*RoomAdminChanged)(nil), // 8: hyapp.events.room.v1.RoomAdminChanged + (*RoomHostTransferred)(nil), // 9: hyapp.events.room.v1.RoomHostTransferred + (*RoomUserMuted)(nil), // 10: hyapp.events.room.v1.RoomUserMuted + (*RoomUserKicked)(nil), // 11: hyapp.events.room.v1.RoomUserKicked + (*RoomUserUnbanned)(nil), // 12: hyapp.events.room.v1.RoomUserUnbanned + (*RoomGiftSent)(nil), // 13: hyapp.events.room.v1.RoomGiftSent + (*RoomHeatChanged)(nil), // 14: hyapp.events.room.v1.RoomHeatChanged + (*RoomRankChanged)(nil), // 15: hyapp.events.room.v1.RoomRankChanged } var file_proto_events_room_v1_events_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type @@ -1309,7 +1371,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*RoomMicChanged); i { + switch v := v.(*RoomClosed); i { case 0: return &v.state case 1: @@ -1321,7 +1383,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*RoomMicSeatLocked); i { + switch v := v.(*RoomMicChanged); i { case 0: return &v.state case 1: @@ -1333,7 +1395,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*RoomChatEnabledChanged); i { + switch v := v.(*RoomMicSeatLocked); i { case 0: return &v.state case 1: @@ -1345,7 +1407,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*RoomAdminChanged); i { + switch v := v.(*RoomChatEnabledChanged); i { case 0: return &v.state case 1: @@ -1357,7 +1419,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*RoomHostTransferred); i { + switch v := v.(*RoomAdminChanged); i { case 0: return &v.state case 1: @@ -1369,7 +1431,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*RoomUserMuted); i { + switch v := v.(*RoomHostTransferred); i { case 0: return &v.state case 1: @@ -1381,7 +1443,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*RoomUserKicked); i { + switch v := v.(*RoomUserMuted); i { case 0: return &v.state case 1: @@ -1393,7 +1455,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*RoomUserUnbanned); i { + switch v := v.(*RoomUserKicked); i { case 0: return &v.state case 1: @@ -1405,7 +1467,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*RoomGiftSent); i { + switch v := v.(*RoomUserUnbanned); i { case 0: return &v.state case 1: @@ -1417,7 +1479,7 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*RoomHeatChanged); i { + switch v := v.(*RoomGiftSent); i { case 0: return &v.state case 1: @@ -1429,6 +1491,18 @@ func file_proto_events_room_v1_events_proto_init() { } } file_proto_events_room_v1_events_proto_msgTypes[14].Exporter = func(v any, i int) any { + switch v := v.(*RoomHeatChanged); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_events_room_v1_events_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*RoomRankChanged); i { case 0: return &v.state @@ -1447,7 +1521,7 @@ func file_proto_events_room_v1_events_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_events_room_v1_events_proto_rawDesc, NumEnums: 0, - NumMessages: 15, + NumMessages: 16, NumExtensions: 0, NumServices: 0, }, diff --git a/api/proto/events/room/v1/events.proto b/api/proto/events/room/v1/events.proto index e1e0d5c5..d89949e3 100644 --- a/api/proto/events/room/v1/events.proto +++ b/api/proto/events/room/v1/events.proto @@ -39,6 +39,12 @@ message RoomUserLeft { int64 user_id = 1; } +// RoomClosed 表达房间生命周期关闭完成。 +message RoomClosed { + int64 actor_user_id = 1; + string reason = 2; +} + // RoomMicChanged 表达任意上下麦和换麦位动作。 message RoomMicChanged { int64 actor_user_id = 1; diff --git a/api/proto/room/v1/room.pb.go b/api/proto/room/v1/room.pb.go index 21165f6b..18a620c5 100644 --- a/api/proto/room/v1/room.pb.go +++ b/api/proto/room/v1/room.pb.go @@ -1126,6 +1126,118 @@ func (x *LeaveRoomResponse) GetRoom() *RoomSnapshot { return nil } +// CloseRoomRequest 关闭房间并清理业务 presence 和麦位。 +type CloseRoomRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` +} + +func (x *CloseRoomRequest) Reset() { + *x = CloseRoomRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_room_v1_room_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CloseRoomRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CloseRoomRequest) ProtoMessage() {} + +func (x *CloseRoomRequest) ProtoReflect() protoreflect.Message { + 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 { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CloseRoomRequest.ProtoReflect.Descriptor instead. +func (*CloseRoomRequest) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{14} +} + +func (x *CloseRoomRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *CloseRoomRequest) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +// CloseRoomResponse 返回关闭后的房间快照。 +type CloseRoomResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result *CommandResult `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + Room *RoomSnapshot `protobuf:"bytes,2,opt,name=room,proto3" json:"room,omitempty"` +} + +func (x *CloseRoomResponse) Reset() { + *x = CloseRoomResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_room_v1_room_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CloseRoomResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CloseRoomResponse) ProtoMessage() {} + +func (x *CloseRoomResponse) ProtoReflect() protoreflect.Message { + 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 { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CloseRoomResponse.ProtoReflect.Descriptor instead. +func (*CloseRoomResponse) Descriptor() ([]byte, []int) { + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{15} +} + +func (x *CloseRoomResponse) GetResult() *CommandResult { + if x != nil { + return x.Result + } + return nil +} + +func (x *CloseRoomResponse) GetRoom() *RoomSnapshot { + if x != nil { + return x.Room + } + return nil +} + // MicUpRequest 申请把用户放到指定麦位。 type MicUpRequest struct { state protoimpl.MessageState @@ -1139,7 +1251,7 @@ type MicUpRequest struct { func (x *MicUpRequest) Reset() { *x = MicUpRequest{} 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) } @@ -1152,7 +1264,7 @@ func (x *MicUpRequest) String() string { func (*MicUpRequest) ProtoMessage() {} func (x *MicUpRequest) 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 { @@ -1165,7 +1277,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{14} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{16} } func (x *MicUpRequest) GetMeta() *RequestMeta { @@ -1198,7 +1310,7 @@ type MicUpResponse struct { func (x *MicUpResponse) Reset() { *x = MicUpResponse{} 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) } @@ -1211,7 +1323,7 @@ func (x *MicUpResponse) String() string { func (*MicUpResponse) ProtoMessage() {} func (x *MicUpResponse) 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 { @@ -1224,7 +1336,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{15} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{17} } func (x *MicUpResponse) GetResult() *CommandResult { @@ -1277,7 +1389,7 @@ type MicDownRequest struct { func (x *MicDownRequest) Reset() { *x = MicDownRequest{} 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) } @@ -1290,7 +1402,7 @@ func (x *MicDownRequest) String() string { func (*MicDownRequest) ProtoMessage() {} func (x *MicDownRequest) 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 { @@ -1303,7 +1415,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{16} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{18} } func (x *MicDownRequest) GetMeta() *RequestMeta { @@ -1341,7 +1453,7 @@ type MicDownResponse struct { func (x *MicDownResponse) Reset() { *x = MicDownResponse{} 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) } @@ -1354,7 +1466,7 @@ func (x *MicDownResponse) String() string { func (*MicDownResponse) ProtoMessage() {} func (x *MicDownResponse) 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 { @@ -1367,7 +1479,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{17} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{19} } func (x *MicDownResponse) GetResult() *CommandResult { @@ -1405,7 +1517,7 @@ type ChangeMicSeatRequest struct { func (x *ChangeMicSeatRequest) Reset() { *x = ChangeMicSeatRequest{} 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) } @@ -1418,7 +1530,7 @@ func (x *ChangeMicSeatRequest) String() string { func (*ChangeMicSeatRequest) ProtoMessage() {} func (x *ChangeMicSeatRequest) 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 { @@ -1431,7 +1543,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{18} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{20} } func (x *ChangeMicSeatRequest) GetMeta() *RequestMeta { @@ -1468,7 +1580,7 @@ type ChangeMicSeatResponse struct { func (x *ChangeMicSeatResponse) Reset() { *x = ChangeMicSeatResponse{} 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) } @@ -1481,7 +1593,7 @@ func (x *ChangeMicSeatResponse) String() string { func (*ChangeMicSeatResponse) ProtoMessage() {} func (x *ChangeMicSeatResponse) 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 { @@ -1494,7 +1606,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{19} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{21} } func (x *ChangeMicSeatResponse) GetResult() *CommandResult { @@ -1530,7 +1642,7 @@ type ConfirmMicPublishingRequest struct { func (x *ConfirmMicPublishingRequest) Reset() { *x = ConfirmMicPublishingRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[20] + mi := &file_proto_room_v1_room_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1543,7 +1655,7 @@ func (x *ConfirmMicPublishingRequest) String() string { func (*ConfirmMicPublishingRequest) ProtoMessage() {} func (x *ConfirmMicPublishingRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[20] + 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 { @@ -1556,7 +1668,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{20} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{22} } func (x *ConfirmMicPublishingRequest) GetMeta() *RequestMeta { @@ -1615,7 +1727,7 @@ type ConfirmMicPublishingResponse struct { func (x *ConfirmMicPublishingResponse) Reset() { *x = ConfirmMicPublishingResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[21] + mi := &file_proto_room_v1_room_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1628,7 +1740,7 @@ func (x *ConfirmMicPublishingResponse) String() string { func (*ConfirmMicPublishingResponse) ProtoMessage() {} func (x *ConfirmMicPublishingResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[21] + 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 { @@ -1641,7 +1753,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{21} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{23} } func (x *ConfirmMicPublishingResponse) GetResult() *CommandResult { @@ -1684,7 +1796,7 @@ type ApplyRTCEventRequest struct { func (x *ApplyRTCEventRequest) Reset() { *x = ApplyRTCEventRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[22] + mi := &file_proto_room_v1_room_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1697,7 +1809,7 @@ func (x *ApplyRTCEventRequest) String() string { func (*ApplyRTCEventRequest) ProtoMessage() {} func (x *ApplyRTCEventRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[22] + 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 { @@ -1710,7 +1822,7 @@ func (x *ApplyRTCEventRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyRTCEventRequest.ProtoReflect.Descriptor instead. func (*ApplyRTCEventRequest) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{22} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{24} } func (x *ApplyRTCEventRequest) GetMeta() *RequestMeta { @@ -1776,7 +1888,7 @@ type ApplyRTCEventResponse struct { func (x *ApplyRTCEventResponse) Reset() { *x = ApplyRTCEventResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[23] + mi := &file_proto_room_v1_room_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1789,7 +1901,7 @@ func (x *ApplyRTCEventResponse) String() string { func (*ApplyRTCEventResponse) ProtoMessage() {} func (x *ApplyRTCEventResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[23] + 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 { @@ -1802,7 +1914,7 @@ func (x *ApplyRTCEventResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyRTCEventResponse.ProtoReflect.Descriptor instead. func (*ApplyRTCEventResponse) Descriptor() ([]byte, []int) { - return file_proto_room_v1_room_proto_rawDescGZIP(), []int{23} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{25} } func (x *ApplyRTCEventResponse) GetResult() *CommandResult { @@ -1840,7 +1952,7 @@ type SetMicSeatLockRequest struct { func (x *SetMicSeatLockRequest) Reset() { *x = SetMicSeatLockRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[24] + mi := &file_proto_room_v1_room_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1853,7 +1965,7 @@ func (x *SetMicSeatLockRequest) String() string { func (*SetMicSeatLockRequest) ProtoMessage() {} func (x *SetMicSeatLockRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[24] + 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 { @@ -1866,7 +1978,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{24} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{26} } func (x *SetMicSeatLockRequest) GetMeta() *RequestMeta { @@ -1903,7 +2015,7 @@ type SetMicSeatLockResponse struct { func (x *SetMicSeatLockResponse) Reset() { *x = SetMicSeatLockResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[25] + mi := &file_proto_room_v1_room_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1916,7 +2028,7 @@ func (x *SetMicSeatLockResponse) String() string { func (*SetMicSeatLockResponse) ProtoMessage() {} func (x *SetMicSeatLockResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[25] + 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 { @@ -1929,7 +2041,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{25} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{27} } func (x *SetMicSeatLockResponse) GetResult() *CommandResult { @@ -1959,7 +2071,7 @@ type SetChatEnabledRequest struct { func (x *SetChatEnabledRequest) Reset() { *x = SetChatEnabledRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[26] + mi := &file_proto_room_v1_room_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1972,7 +2084,7 @@ func (x *SetChatEnabledRequest) String() string { func (*SetChatEnabledRequest) ProtoMessage() {} func (x *SetChatEnabledRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[26] + 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 { @@ -1985,7 +2097,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{26} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{28} } func (x *SetChatEnabledRequest) GetMeta() *RequestMeta { @@ -2015,7 +2127,7 @@ type SetChatEnabledResponse struct { func (x *SetChatEnabledResponse) Reset() { *x = SetChatEnabledResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[27] + mi := &file_proto_room_v1_room_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2028,7 +2140,7 @@ func (x *SetChatEnabledResponse) String() string { func (*SetChatEnabledResponse) ProtoMessage() {} func (x *SetChatEnabledResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[27] + 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 { @@ -2041,7 +2153,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{27} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{29} } func (x *SetChatEnabledResponse) GetResult() *CommandResult { @@ -2072,7 +2184,7 @@ type SetRoomAdminRequest struct { func (x *SetRoomAdminRequest) Reset() { *x = SetRoomAdminRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[28] + mi := &file_proto_room_v1_room_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2085,7 +2197,7 @@ func (x *SetRoomAdminRequest) String() string { func (*SetRoomAdminRequest) ProtoMessage() {} func (x *SetRoomAdminRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[28] + 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 { @@ -2098,7 +2210,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{28} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{30} } func (x *SetRoomAdminRequest) GetMeta() *RequestMeta { @@ -2135,7 +2247,7 @@ type SetRoomAdminResponse struct { func (x *SetRoomAdminResponse) Reset() { *x = SetRoomAdminResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[29] + mi := &file_proto_room_v1_room_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2148,7 +2260,7 @@ func (x *SetRoomAdminResponse) String() string { func (*SetRoomAdminResponse) ProtoMessage() {} func (x *SetRoomAdminResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[29] + 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 { @@ -2161,7 +2273,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{29} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{31} } func (x *SetRoomAdminResponse) GetResult() *CommandResult { @@ -2191,7 +2303,7 @@ type TransferRoomHostRequest struct { func (x *TransferRoomHostRequest) Reset() { *x = TransferRoomHostRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[30] + mi := &file_proto_room_v1_room_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2204,7 +2316,7 @@ func (x *TransferRoomHostRequest) String() string { func (*TransferRoomHostRequest) ProtoMessage() {} func (x *TransferRoomHostRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[30] + 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 { @@ -2217,7 +2329,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{30} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{32} } func (x *TransferRoomHostRequest) GetMeta() *RequestMeta { @@ -2247,7 +2359,7 @@ type TransferRoomHostResponse struct { func (x *TransferRoomHostResponse) Reset() { *x = TransferRoomHostResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[31] + mi := &file_proto_room_v1_room_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2260,7 +2372,7 @@ func (x *TransferRoomHostResponse) String() string { func (*TransferRoomHostResponse) ProtoMessage() {} func (x *TransferRoomHostResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[31] + 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 { @@ -2273,7 +2385,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{31} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{33} } func (x *TransferRoomHostResponse) GetResult() *CommandResult { @@ -2304,7 +2416,7 @@ type MuteUserRequest struct { func (x *MuteUserRequest) Reset() { *x = MuteUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[32] + mi := &file_proto_room_v1_room_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2317,7 +2429,7 @@ func (x *MuteUserRequest) String() string { func (*MuteUserRequest) ProtoMessage() {} func (x *MuteUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[32] + 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 { @@ -2330,7 +2442,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{32} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{34} } func (x *MuteUserRequest) GetMeta() *RequestMeta { @@ -2367,7 +2479,7 @@ type MuteUserResponse struct { func (x *MuteUserResponse) Reset() { *x = MuteUserResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[33] + mi := &file_proto_room_v1_room_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2380,7 +2492,7 @@ func (x *MuteUserResponse) String() string { func (*MuteUserResponse) ProtoMessage() {} func (x *MuteUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[33] + 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 { @@ -2393,7 +2505,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{33} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{35} } func (x *MuteUserResponse) GetResult() *CommandResult { @@ -2423,7 +2535,7 @@ type KickUserRequest struct { func (x *KickUserRequest) Reset() { *x = KickUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[34] + mi := &file_proto_room_v1_room_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2436,7 +2548,7 @@ func (x *KickUserRequest) String() string { func (*KickUserRequest) ProtoMessage() {} func (x *KickUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[34] + 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 { @@ -2449,7 +2561,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{34} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{36} } func (x *KickUserRequest) GetMeta() *RequestMeta { @@ -2479,7 +2591,7 @@ type KickUserResponse struct { func (x *KickUserResponse) Reset() { *x = KickUserResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[35] + mi := &file_proto_room_v1_room_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2492,7 +2604,7 @@ func (x *KickUserResponse) String() string { func (*KickUserResponse) ProtoMessage() {} func (x *KickUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[35] + 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 { @@ -2505,7 +2617,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{35} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{37} } func (x *KickUserResponse) GetResult() *CommandResult { @@ -2535,7 +2647,7 @@ type UnbanUserRequest struct { func (x *UnbanUserRequest) Reset() { *x = UnbanUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[36] + mi := &file_proto_room_v1_room_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2548,7 +2660,7 @@ func (x *UnbanUserRequest) String() string { func (*UnbanUserRequest) ProtoMessage() {} func (x *UnbanUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[36] + 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 { @@ -2561,7 +2673,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{36} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{38} } func (x *UnbanUserRequest) GetMeta() *RequestMeta { @@ -2591,7 +2703,7 @@ type UnbanUserResponse struct { func (x *UnbanUserResponse) Reset() { *x = UnbanUserResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[37] + mi := &file_proto_room_v1_room_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2604,7 +2716,7 @@ func (x *UnbanUserResponse) String() string { func (*UnbanUserResponse) ProtoMessage() {} func (x *UnbanUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[37] + 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 { @@ -2617,7 +2729,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{37} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{39} } func (x *UnbanUserResponse) GetResult() *CommandResult { @@ -2649,7 +2761,7 @@ type SendGiftRequest struct { func (x *SendGiftRequest) Reset() { *x = SendGiftRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[38] + mi := &file_proto_room_v1_room_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2662,7 +2774,7 @@ func (x *SendGiftRequest) String() string { func (*SendGiftRequest) ProtoMessage() {} func (x *SendGiftRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[38] + 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 { @@ -2675,7 +2787,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{38} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{40} } func (x *SendGiftRequest) GetMeta() *RequestMeta { @@ -2722,7 +2834,7 @@ type SendGiftResponse struct { func (x *SendGiftResponse) Reset() { *x = SendGiftResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[39] + mi := &file_proto_room_v1_room_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2735,7 +2847,7 @@ func (x *SendGiftResponse) String() string { func (*SendGiftResponse) ProtoMessage() {} func (x *SendGiftResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[39] + 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 { @@ -2748,7 +2860,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{39} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{41} } func (x *SendGiftResponse) GetResult() *CommandResult { @@ -2800,7 +2912,7 @@ type CheckSpeakPermissionRequest struct { func (x *CheckSpeakPermissionRequest) Reset() { *x = CheckSpeakPermissionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[40] + mi := &file_proto_room_v1_room_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2813,7 +2925,7 @@ func (x *CheckSpeakPermissionRequest) String() string { func (*CheckSpeakPermissionRequest) ProtoMessage() {} func (x *CheckSpeakPermissionRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[40] + 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 { @@ -2826,7 +2938,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{40} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{42} } func (x *CheckSpeakPermissionRequest) GetRoomId() string { @@ -2864,7 +2976,7 @@ type CheckSpeakPermissionResponse struct { func (x *CheckSpeakPermissionResponse) Reset() { *x = CheckSpeakPermissionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[41] + mi := &file_proto_room_v1_room_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2877,7 +2989,7 @@ func (x *CheckSpeakPermissionResponse) String() string { func (*CheckSpeakPermissionResponse) ProtoMessage() {} func (x *CheckSpeakPermissionResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[41] + 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 { @@ -2890,7 +3002,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{41} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{43} } func (x *CheckSpeakPermissionResponse) GetAllowed() bool { @@ -2930,7 +3042,7 @@ type VerifyRoomPresenceRequest struct { func (x *VerifyRoomPresenceRequest) Reset() { *x = VerifyRoomPresenceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[42] + mi := &file_proto_room_v1_room_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2943,7 +3055,7 @@ func (x *VerifyRoomPresenceRequest) String() string { func (*VerifyRoomPresenceRequest) ProtoMessage() {} func (x *VerifyRoomPresenceRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[42] + 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 { @@ -2956,7 +3068,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{42} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{44} } func (x *VerifyRoomPresenceRequest) GetRoomId() string { @@ -3008,7 +3120,7 @@ type VerifyRoomPresenceResponse struct { func (x *VerifyRoomPresenceResponse) Reset() { *x = VerifyRoomPresenceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[43] + mi := &file_proto_room_v1_room_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3021,7 +3133,7 @@ func (x *VerifyRoomPresenceResponse) String() string { func (*VerifyRoomPresenceResponse) ProtoMessage() {} func (x *VerifyRoomPresenceResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[43] + 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 { @@ -3034,7 +3146,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{43} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{45} } func (x *VerifyRoomPresenceResponse) GetPresent() bool { @@ -3077,7 +3189,7 @@ type ListRoomsRequest struct { func (x *ListRoomsRequest) Reset() { *x = ListRoomsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[44] + mi := &file_proto_room_v1_room_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3090,7 +3202,7 @@ func (x *ListRoomsRequest) String() string { func (*ListRoomsRequest) ProtoMessage() {} func (x *ListRoomsRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[44] + 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 { @@ -3103,7 +3215,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{44} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{46} } func (x *ListRoomsRequest) GetMeta() *RequestMeta { @@ -3180,7 +3292,7 @@ type RoomListItem struct { func (x *RoomListItem) Reset() { *x = RoomListItem{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[45] + mi := &file_proto_room_v1_room_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3193,7 +3305,7 @@ func (x *RoomListItem) String() string { func (*RoomListItem) ProtoMessage() {} func (x *RoomListItem) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[45] + mi := &file_proto_room_v1_room_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3206,7 +3318,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{45} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{47} } func (x *RoomListItem) GetRoomId() string { @@ -3320,7 +3432,7 @@ type ListRoomsResponse struct { func (x *ListRoomsResponse) Reset() { *x = ListRoomsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_room_v1_room_proto_msgTypes[46] + mi := &file_proto_room_v1_room_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3333,7 +3445,7 @@ func (x *ListRoomsResponse) String() string { func (*ListRoomsResponse) ProtoMessage() {} func (x *ListRoomsResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_room_v1_room_proto_msgTypes[46] + mi := &file_proto_room_v1_room_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3346,7 +3458,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{46} + return file_proto_room_v1_room_proto_rawDescGZIP(), []int{48} } func (x *ListRoomsResponse) GetRooms() []*RoomListItem { @@ -3543,78 +3655,118 @@ var file_proto_room_v1_room_proto_rawDesc = []byte{ 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, - 0x75, 0x6c, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x2f, 0x0a, 0x04, - 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x85, 0x01, - 0x0a, 0x14, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, - 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, - 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, - 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x22, 0x7e, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, - 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, - 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x5a, 0x0a, 0x10, 0x43, 0x6c, 0x6f, 0x73, + 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, + 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, + 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x7a, 0x0a, 0x11, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, + 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 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, 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, 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, + 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x85, 0x01, 0x0a, 0x14, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, + 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, + 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x22, 0x7e, 0x0a, + 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, + 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0xf8, 0x01, + 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, + 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, + 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x72, 0x6f, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x1c, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 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, @@ -3623,363 +3775,342 @@ var file_proto_room_v1_room_proto_rawDesc = []byte{ 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, + 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, 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, + 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, - 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, + 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, 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, 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, 0x65, 0x12, + 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, 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, + 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, 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, + 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, + 0x79, 0x0a, 0x10, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, + 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x68, 0x0a, 0x10, 0x55, 0x6e, + 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, + 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x24, + 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x22, 0x7a, 0x0a, 0x11, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, + 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, + 0x6f, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x22, 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, 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, 0x9a, 0x0c, 0x0a, 0x12, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, + 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, + 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, + 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x6f, 0x6f, + 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x52, 0x6f, 0x6f, + 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x48, + 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, + 0x6f, 0x6d, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, + 0x6f, 0x6d, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x05, 0x4d, 0x69, 0x63, 0x55, 0x70, 0x12, 0x1b, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x69, 0x63, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x63, 0x55, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x07, 0x4d, 0x69, 0x63, + 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x63, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, + 0x53, 0x65, 0x61, 0x74, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x69, 0x63, 0x53, 0x65, + 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, + 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x6f, 0x0a, 0x14, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, + 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, + 0x69, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x4d, 0x69, 0x63, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x5a, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x54, 0x43, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, + 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x24, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x53, + 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x24, 0x2e, + 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x53, 0x65, + 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, + 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x6f, + 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, + 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, - 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x4b, 0x0a, 0x08, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, - 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, - 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, - 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, - 0x08, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, - 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x55, 0x6e, - 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, - 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, - 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x53, 0x65, - 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, - 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xee, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, - 0x47, 0x75, 0x61, 0x72, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6f, 0x0a, 0x14, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, - 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, - 0x6e, 0x63, 0x65, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, - 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, - 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 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, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x6f, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x4d, 0x75, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x12, 0x1e, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, + 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x65, 0x6e, 0x64, 0x47, 0x69, 0x66, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, + 0xee, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x47, 0x75, 0x61, 0x72, 0x64, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, 0x65, + 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x68, + 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x53, 0x70, 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x70, + 0x65, 0x61, 0x6b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, + 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x2e, 0x68, 0x79, + 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, + 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x6f, 0x6f, 0x6d, + 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x32, 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 ( @@ -3994,7 +4125,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, 48) +var file_proto_room_v1_room_proto_msgTypes = make([]protoimpl.MessageInfo, 50) var file_proto_room_v1_room_proto_goTypes = []any{ (*RequestMeta)(nil), // 0: hyapp.room.v1.RequestMeta (*CommandResult)(nil), // 1: hyapp.room.v1.CommandResult @@ -4010,46 +4141,48 @@ var file_proto_room_v1_room_proto_goTypes = []any{ (*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 + (*CloseRoomRequest)(nil), // 14: hyapp.room.v1.CloseRoomRequest + (*CloseRoomResponse)(nil), // 15: hyapp.room.v1.CloseRoomResponse + (*MicUpRequest)(nil), // 16: hyapp.room.v1.MicUpRequest + (*MicUpResponse)(nil), // 17: hyapp.room.v1.MicUpResponse + (*MicDownRequest)(nil), // 18: hyapp.room.v1.MicDownRequest + (*MicDownResponse)(nil), // 19: hyapp.room.v1.MicDownResponse + (*ChangeMicSeatRequest)(nil), // 20: hyapp.room.v1.ChangeMicSeatRequest + (*ChangeMicSeatResponse)(nil), // 21: hyapp.room.v1.ChangeMicSeatResponse + (*ConfirmMicPublishingRequest)(nil), // 22: hyapp.room.v1.ConfirmMicPublishingRequest + (*ConfirmMicPublishingResponse)(nil), // 23: hyapp.room.v1.ConfirmMicPublishingResponse + (*ApplyRTCEventRequest)(nil), // 24: hyapp.room.v1.ApplyRTCEventRequest + (*ApplyRTCEventResponse)(nil), // 25: hyapp.room.v1.ApplyRTCEventResponse + (*SetMicSeatLockRequest)(nil), // 26: hyapp.room.v1.SetMicSeatLockRequest + (*SetMicSeatLockResponse)(nil), // 27: hyapp.room.v1.SetMicSeatLockResponse + (*SetChatEnabledRequest)(nil), // 28: hyapp.room.v1.SetChatEnabledRequest + (*SetChatEnabledResponse)(nil), // 29: hyapp.room.v1.SetChatEnabledResponse + (*SetRoomAdminRequest)(nil), // 30: hyapp.room.v1.SetRoomAdminRequest + (*SetRoomAdminResponse)(nil), // 31: hyapp.room.v1.SetRoomAdminResponse + (*TransferRoomHostRequest)(nil), // 32: hyapp.room.v1.TransferRoomHostRequest + (*TransferRoomHostResponse)(nil), // 33: hyapp.room.v1.TransferRoomHostResponse + (*MuteUserRequest)(nil), // 34: hyapp.room.v1.MuteUserRequest + (*MuteUserResponse)(nil), // 35: hyapp.room.v1.MuteUserResponse + (*KickUserRequest)(nil), // 36: hyapp.room.v1.KickUserRequest + (*KickUserResponse)(nil), // 37: hyapp.room.v1.KickUserResponse + (*UnbanUserRequest)(nil), // 38: hyapp.room.v1.UnbanUserRequest + (*UnbanUserResponse)(nil), // 39: hyapp.room.v1.UnbanUserResponse + (*SendGiftRequest)(nil), // 40: hyapp.room.v1.SendGiftRequest + (*SendGiftResponse)(nil), // 41: hyapp.room.v1.SendGiftResponse + (*CheckSpeakPermissionRequest)(nil), // 42: hyapp.room.v1.CheckSpeakPermissionRequest + (*CheckSpeakPermissionResponse)(nil), // 43: hyapp.room.v1.CheckSpeakPermissionResponse + (*VerifyRoomPresenceRequest)(nil), // 44: hyapp.room.v1.VerifyRoomPresenceRequest + (*VerifyRoomPresenceResponse)(nil), // 45: hyapp.room.v1.VerifyRoomPresenceResponse + (*ListRoomsRequest)(nil), // 46: hyapp.room.v1.ListRoomsRequest + (*RoomListItem)(nil), // 47: hyapp.room.v1.RoomListItem + (*ListRoomsResponse)(nil), // 48: hyapp.room.v1.ListRoomsResponse + nil, // 49: hyapp.room.v1.RoomSnapshot.RoomExtEntry } 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 - 47, // 3: hyapp.room.v1.RoomSnapshot.room_ext:type_name -> hyapp.room.v1.RoomSnapshot.RoomExtEntry + 49, // 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 @@ -4064,93 +4197,98 @@ var file_proto_room_v1_room_proto_depIdxs = []int32{ 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 + 0, // 18: hyapp.room.v1.CloseRoomRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 19: hyapp.room.v1.CloseRoomResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 20: hyapp.room.v1.CloseRoomResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 21: hyapp.room.v1.MicUpRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 22: hyapp.room.v1.MicUpResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 23: hyapp.room.v1.MicUpResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 24: hyapp.room.v1.MicDownRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 25: hyapp.room.v1.MicDownResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 26: hyapp.room.v1.MicDownResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 27: hyapp.room.v1.ChangeMicSeatRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 28: hyapp.room.v1.ChangeMicSeatResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 29: hyapp.room.v1.ChangeMicSeatResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 30: hyapp.room.v1.ConfirmMicPublishingRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 31: hyapp.room.v1.ConfirmMicPublishingResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 32: hyapp.room.v1.ConfirmMicPublishingResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 33: hyapp.room.v1.ApplyRTCEventRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 34: hyapp.room.v1.ApplyRTCEventResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 35: hyapp.room.v1.ApplyRTCEventResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 36: hyapp.room.v1.SetMicSeatLockRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 37: hyapp.room.v1.SetMicSeatLockResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 38: hyapp.room.v1.SetMicSeatLockResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 39: hyapp.room.v1.SetChatEnabledRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 40: hyapp.room.v1.SetChatEnabledResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 41: hyapp.room.v1.SetChatEnabledResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 42: hyapp.room.v1.SetRoomAdminRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 43: hyapp.room.v1.SetRoomAdminResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 44: hyapp.room.v1.SetRoomAdminResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 45: hyapp.room.v1.TransferRoomHostRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 46: hyapp.room.v1.TransferRoomHostResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 47: hyapp.room.v1.TransferRoomHostResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 48: hyapp.room.v1.MuteUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 49: hyapp.room.v1.MuteUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 50: hyapp.room.v1.MuteUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 51: hyapp.room.v1.KickUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 52: hyapp.room.v1.KickUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 53: hyapp.room.v1.KickUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 54: hyapp.room.v1.UnbanUserRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 55: hyapp.room.v1.UnbanUserResponse.result:type_name -> hyapp.room.v1.CommandResult + 5, // 56: hyapp.room.v1.UnbanUserResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 57: hyapp.room.v1.SendGiftRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 1, // 58: hyapp.room.v1.SendGiftResponse.result:type_name -> hyapp.room.v1.CommandResult + 4, // 59: hyapp.room.v1.SendGiftResponse.gift_rank:type_name -> hyapp.room.v1.RankItem + 5, // 60: hyapp.room.v1.SendGiftResponse.room:type_name -> hyapp.room.v1.RoomSnapshot + 0, // 61: hyapp.room.v1.ListRoomsRequest.meta:type_name -> hyapp.room.v1.RequestMeta + 47, // 62: hyapp.room.v1.ListRoomsResponse.rooms:type_name -> hyapp.room.v1.RoomListItem + 6, // 63: hyapp.room.v1.RoomCommandService.CreateRoom:input_type -> hyapp.room.v1.CreateRoomRequest + 8, // 64: hyapp.room.v1.RoomCommandService.JoinRoom:input_type -> hyapp.room.v1.JoinRoomRequest + 10, // 65: hyapp.room.v1.RoomCommandService.RoomHeartbeat:input_type -> hyapp.room.v1.RoomHeartbeatRequest + 12, // 66: hyapp.room.v1.RoomCommandService.LeaveRoom:input_type -> hyapp.room.v1.LeaveRoomRequest + 14, // 67: hyapp.room.v1.RoomCommandService.CloseRoom:input_type -> hyapp.room.v1.CloseRoomRequest + 16, // 68: hyapp.room.v1.RoomCommandService.MicUp:input_type -> hyapp.room.v1.MicUpRequest + 18, // 69: hyapp.room.v1.RoomCommandService.MicDown:input_type -> hyapp.room.v1.MicDownRequest + 20, // 70: hyapp.room.v1.RoomCommandService.ChangeMicSeat:input_type -> hyapp.room.v1.ChangeMicSeatRequest + 22, // 71: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:input_type -> hyapp.room.v1.ConfirmMicPublishingRequest + 24, // 72: hyapp.room.v1.RoomCommandService.ApplyRTCEvent:input_type -> hyapp.room.v1.ApplyRTCEventRequest + 26, // 73: hyapp.room.v1.RoomCommandService.SetMicSeatLock:input_type -> hyapp.room.v1.SetMicSeatLockRequest + 28, // 74: hyapp.room.v1.RoomCommandService.SetChatEnabled:input_type -> hyapp.room.v1.SetChatEnabledRequest + 30, // 75: hyapp.room.v1.RoomCommandService.SetRoomAdmin:input_type -> hyapp.room.v1.SetRoomAdminRequest + 32, // 76: hyapp.room.v1.RoomCommandService.TransferRoomHost:input_type -> hyapp.room.v1.TransferRoomHostRequest + 34, // 77: hyapp.room.v1.RoomCommandService.MuteUser:input_type -> hyapp.room.v1.MuteUserRequest + 36, // 78: hyapp.room.v1.RoomCommandService.KickUser:input_type -> hyapp.room.v1.KickUserRequest + 38, // 79: hyapp.room.v1.RoomCommandService.UnbanUser:input_type -> hyapp.room.v1.UnbanUserRequest + 40, // 80: hyapp.room.v1.RoomCommandService.SendGift:input_type -> hyapp.room.v1.SendGiftRequest + 42, // 81: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:input_type -> hyapp.room.v1.CheckSpeakPermissionRequest + 44, // 82: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:input_type -> hyapp.room.v1.VerifyRoomPresenceRequest + 46, // 83: hyapp.room.v1.RoomQueryService.ListRooms:input_type -> hyapp.room.v1.ListRoomsRequest + 7, // 84: hyapp.room.v1.RoomCommandService.CreateRoom:output_type -> hyapp.room.v1.CreateRoomResponse + 9, // 85: hyapp.room.v1.RoomCommandService.JoinRoom:output_type -> hyapp.room.v1.JoinRoomResponse + 11, // 86: hyapp.room.v1.RoomCommandService.RoomHeartbeat:output_type -> hyapp.room.v1.RoomHeartbeatResponse + 13, // 87: hyapp.room.v1.RoomCommandService.LeaveRoom:output_type -> hyapp.room.v1.LeaveRoomResponse + 15, // 88: hyapp.room.v1.RoomCommandService.CloseRoom:output_type -> hyapp.room.v1.CloseRoomResponse + 17, // 89: hyapp.room.v1.RoomCommandService.MicUp:output_type -> hyapp.room.v1.MicUpResponse + 19, // 90: hyapp.room.v1.RoomCommandService.MicDown:output_type -> hyapp.room.v1.MicDownResponse + 21, // 91: hyapp.room.v1.RoomCommandService.ChangeMicSeat:output_type -> hyapp.room.v1.ChangeMicSeatResponse + 23, // 92: hyapp.room.v1.RoomCommandService.ConfirmMicPublishing:output_type -> hyapp.room.v1.ConfirmMicPublishingResponse + 25, // 93: hyapp.room.v1.RoomCommandService.ApplyRTCEvent:output_type -> hyapp.room.v1.ApplyRTCEventResponse + 27, // 94: hyapp.room.v1.RoomCommandService.SetMicSeatLock:output_type -> hyapp.room.v1.SetMicSeatLockResponse + 29, // 95: hyapp.room.v1.RoomCommandService.SetChatEnabled:output_type -> hyapp.room.v1.SetChatEnabledResponse + 31, // 96: hyapp.room.v1.RoomCommandService.SetRoomAdmin:output_type -> hyapp.room.v1.SetRoomAdminResponse + 33, // 97: hyapp.room.v1.RoomCommandService.TransferRoomHost:output_type -> hyapp.room.v1.TransferRoomHostResponse + 35, // 98: hyapp.room.v1.RoomCommandService.MuteUser:output_type -> hyapp.room.v1.MuteUserResponse + 37, // 99: hyapp.room.v1.RoomCommandService.KickUser:output_type -> hyapp.room.v1.KickUserResponse + 39, // 100: hyapp.room.v1.RoomCommandService.UnbanUser:output_type -> hyapp.room.v1.UnbanUserResponse + 41, // 101: hyapp.room.v1.RoomCommandService.SendGift:output_type -> hyapp.room.v1.SendGiftResponse + 43, // 102: hyapp.room.v1.RoomGuardService.CheckSpeakPermission:output_type -> hyapp.room.v1.CheckSpeakPermissionResponse + 45, // 103: hyapp.room.v1.RoomGuardService.VerifyRoomPresence:output_type -> hyapp.room.v1.VerifyRoomPresenceResponse + 48, // 104: hyapp.room.v1.RoomQueryService.ListRooms:output_type -> hyapp.room.v1.ListRoomsResponse + 84, // [84:105] is the sub-list for method output_type + 63, // [63:84] is the sub-list for method input_type + 63, // [63:63] is the sub-list for extension type_name + 63, // [63:63] is the sub-list for extension extendee + 0, // [0:63] is the sub-list for field type_name } func init() { file_proto_room_v1_room_proto_init() } @@ -4328,7 +4466,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.(*MicUpRequest); i { + switch v := v.(*CloseRoomRequest); i { case 0: return &v.state case 1: @@ -4340,7 +4478,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.(*MicUpResponse); i { + switch v := v.(*CloseRoomResponse); i { case 0: return &v.state case 1: @@ -4352,7 +4490,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.(*MicDownRequest); i { + switch v := v.(*MicUpRequest); i { case 0: return &v.state case 1: @@ -4364,7 +4502,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.(*MicDownResponse); i { + switch v := v.(*MicUpResponse); i { case 0: return &v.state case 1: @@ -4376,7 +4514,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.(*ChangeMicSeatRequest); i { + switch v := v.(*MicDownRequest); i { case 0: return &v.state case 1: @@ -4388,7 +4526,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.(*ChangeMicSeatResponse); i { + switch v := v.(*MicDownResponse); i { case 0: return &v.state case 1: @@ -4400,7 +4538,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.(*ConfirmMicPublishingRequest); i { + switch v := v.(*ChangeMicSeatRequest); i { case 0: return &v.state case 1: @@ -4412,7 +4550,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.(*ConfirmMicPublishingResponse); i { + switch v := v.(*ChangeMicSeatResponse); i { case 0: return &v.state case 1: @@ -4424,7 +4562,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.(*ApplyRTCEventRequest); i { + switch v := v.(*ConfirmMicPublishingRequest); i { case 0: return &v.state case 1: @@ -4436,7 +4574,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.(*ApplyRTCEventResponse); i { + switch v := v.(*ConfirmMicPublishingResponse); i { case 0: return &v.state case 1: @@ -4448,7 +4586,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.(*SetMicSeatLockRequest); i { + switch v := v.(*ApplyRTCEventRequest); i { case 0: return &v.state case 1: @@ -4460,7 +4598,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.(*SetMicSeatLockResponse); i { + switch v := v.(*ApplyRTCEventResponse); i { case 0: return &v.state case 1: @@ -4472,7 +4610,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.(*SetChatEnabledRequest); i { + switch v := v.(*SetMicSeatLockRequest); i { case 0: return &v.state case 1: @@ -4484,7 +4622,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.(*SetChatEnabledResponse); i { + switch v := v.(*SetMicSeatLockResponse); i { case 0: return &v.state case 1: @@ -4496,7 +4634,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.(*SetRoomAdminRequest); i { + switch v := v.(*SetChatEnabledRequest); i { case 0: return &v.state case 1: @@ -4508,7 +4646,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.(*SetRoomAdminResponse); i { + switch v := v.(*SetChatEnabledResponse); i { case 0: return &v.state case 1: @@ -4520,7 +4658,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.(*TransferRoomHostRequest); i { + switch v := v.(*SetRoomAdminRequest); i { case 0: return &v.state case 1: @@ -4532,7 +4670,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.(*TransferRoomHostResponse); i { + switch v := v.(*SetRoomAdminResponse); i { case 0: return &v.state case 1: @@ -4544,7 +4682,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.(*MuteUserRequest); i { + switch v := v.(*TransferRoomHostRequest); i { case 0: return &v.state case 1: @@ -4556,7 +4694,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.(*MuteUserResponse); i { + switch v := v.(*TransferRoomHostResponse); i { case 0: return &v.state case 1: @@ -4568,7 +4706,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.(*KickUserRequest); i { + switch v := v.(*MuteUserRequest); i { case 0: return &v.state case 1: @@ -4580,7 +4718,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.(*KickUserResponse); i { + switch v := v.(*MuteUserResponse); i { case 0: return &v.state case 1: @@ -4592,7 +4730,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.(*UnbanUserRequest); i { + switch v := v.(*KickUserRequest); i { case 0: return &v.state case 1: @@ -4604,7 +4742,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.(*UnbanUserResponse); i { + switch v := v.(*KickUserResponse); i { case 0: return &v.state case 1: @@ -4616,7 +4754,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.(*SendGiftRequest); i { + switch v := v.(*UnbanUserRequest); i { case 0: return &v.state case 1: @@ -4628,7 +4766,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.(*SendGiftResponse); i { + switch v := v.(*UnbanUserResponse); i { case 0: return &v.state case 1: @@ -4640,7 +4778,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.(*CheckSpeakPermissionRequest); i { + switch v := v.(*SendGiftRequest); i { case 0: return &v.state case 1: @@ -4652,7 +4790,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.(*CheckSpeakPermissionResponse); i { + switch v := v.(*SendGiftResponse); i { case 0: return &v.state case 1: @@ -4664,7 +4802,7 @@ 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 { + switch v := v.(*CheckSpeakPermissionRequest); i { case 0: return &v.state case 1: @@ -4676,7 +4814,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[43].Exporter = func(v any, i int) any { - switch v := v.(*VerifyRoomPresenceResponse); i { + switch v := v.(*CheckSpeakPermissionResponse); i { case 0: return &v.state case 1: @@ -4688,7 +4826,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[44].Exporter = func(v any, i int) any { - switch v := v.(*ListRoomsRequest); i { + switch v := v.(*VerifyRoomPresenceRequest); i { case 0: return &v.state case 1: @@ -4700,7 +4838,7 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[45].Exporter = func(v any, i int) any { - switch v := v.(*RoomListItem); i { + switch v := v.(*VerifyRoomPresenceResponse); i { case 0: return &v.state case 1: @@ -4712,6 +4850,30 @@ func file_proto_room_v1_room_proto_init() { } } file_proto_room_v1_room_proto_msgTypes[46].Exporter = func(v any, i int) any { + switch v := v.(*ListRoomsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_room_v1_room_proto_msgTypes[47].Exporter = func(v any, i int) any { + switch v := v.(*RoomListItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_room_v1_room_proto_msgTypes[48].Exporter = func(v any, i int) any { switch v := v.(*ListRoomsResponse); i { case 0: return &v.state @@ -4730,7 +4892,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: 48, + NumMessages: 50, NumExtensions: 0, NumServices: 3, }, diff --git a/api/proto/room/v1/room.proto b/api/proto/room/v1/room.proto index 745e8fee..94231c8f 100644 --- a/api/proto/room/v1/room.proto +++ b/api/proto/room/v1/room.proto @@ -144,6 +144,18 @@ message LeaveRoomResponse { RoomSnapshot room = 2; } +// CloseRoomRequest 关闭房间并清理业务 presence 和麦位。 +message CloseRoomRequest { + RequestMeta meta = 1; + string reason = 2; +} + +// CloseRoomResponse 返回关闭后的房间快照。 +message CloseRoomResponse { + CommandResult result = 1; + RoomSnapshot room = 2; +} + // MicUpRequest 申请把用户放到指定麦位。 message MicUpRequest { RequestMeta meta = 1; @@ -401,6 +413,7 @@ service RoomCommandService { rpc JoinRoom(JoinRoomRequest) returns (JoinRoomResponse); rpc RoomHeartbeat(RoomHeartbeatRequest) returns (RoomHeartbeatResponse); rpc LeaveRoom(LeaveRoomRequest) returns (LeaveRoomResponse); + rpc CloseRoom(CloseRoomRequest) returns (CloseRoomResponse); rpc MicUp(MicUpRequest) returns (MicUpResponse); rpc MicDown(MicDownRequest) returns (MicDownResponse); rpc ChangeMicSeat(ChangeMicSeatRequest) returns (ChangeMicSeatResponse); diff --git a/api/proto/room/v1/room_grpc.pb.go b/api/proto/room/v1/room_grpc.pb.go index 9a65920c..0fddd3e2 100644 --- a/api/proto/room/v1/room_grpc.pb.go +++ b/api/proto/room/v1/room_grpc.pb.go @@ -23,6 +23,7 @@ const ( 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_CloseRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/CloseRoom" RoomCommandService_MicUp_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicUp" RoomCommandService_MicDown_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicDown" RoomCommandService_ChangeMicSeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/ChangeMicSeat" @@ -48,6 +49,7 @@ type RoomCommandServiceClient interface { 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) + CloseRoom(ctx context.Context, in *CloseRoomRequest, opts ...grpc.CallOption) (*CloseRoomResponse, 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) @@ -111,6 +113,16 @@ func (c *roomCommandServiceClient) LeaveRoom(ctx context.Context, in *LeaveRoomR return out, nil } +func (c *roomCommandServiceClient) CloseRoom(ctx context.Context, in *CloseRoomRequest, opts ...grpc.CallOption) (*CloseRoomResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CloseRoomResponse) + err := c.cc.Invoke(ctx, RoomCommandService_CloseRoom_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *roomCommandServiceClient) MicUp(ctx context.Context, in *MicUpRequest, opts ...grpc.CallOption) (*MicUpResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(MicUpResponse) @@ -251,6 +263,7 @@ type RoomCommandServiceServer interface { JoinRoom(context.Context, *JoinRoomRequest) (*JoinRoomResponse, error) RoomHeartbeat(context.Context, *RoomHeartbeatRequest) (*RoomHeartbeatResponse, error) LeaveRoom(context.Context, *LeaveRoomRequest) (*LeaveRoomResponse, error) + CloseRoom(context.Context, *CloseRoomRequest) (*CloseRoomResponse, error) MicUp(context.Context, *MicUpRequest) (*MicUpResponse, error) MicDown(context.Context, *MicDownRequest) (*MicDownResponse, error) ChangeMicSeat(context.Context, *ChangeMicSeatRequest) (*ChangeMicSeatResponse, error) @@ -286,6 +299,9 @@ func (UnimplementedRoomCommandServiceServer) RoomHeartbeat(context.Context, *Roo func (UnimplementedRoomCommandServiceServer) LeaveRoom(context.Context, *LeaveRoomRequest) (*LeaveRoomResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method LeaveRoom not implemented") } +func (UnimplementedRoomCommandServiceServer) CloseRoom(context.Context, *CloseRoomRequest) (*CloseRoomResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CloseRoom not implemented") +} func (UnimplementedRoomCommandServiceServer) MicUp(context.Context, *MicUpRequest) (*MicUpResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method MicUp not implemented") } @@ -418,6 +434,24 @@ func _RoomCommandService_LeaveRoom_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _RoomCommandService_CloseRoom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CloseRoomRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoomCommandServiceServer).CloseRoom(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RoomCommandService_CloseRoom_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoomCommandServiceServer).CloseRoom(ctx, req.(*CloseRoomRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _RoomCommandService_MicUp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MicUpRequest) if err := dec(in); err != nil { @@ -675,6 +709,10 @@ var RoomCommandService_ServiceDesc = grpc.ServiceDesc{ MethodName: "LeaveRoom", Handler: _RoomCommandService_LeaveRoom_Handler, }, + { + MethodName: "CloseRoom", + Handler: _RoomCommandService_CloseRoom_Handler, + }, { MethodName: "MicUp", Handler: _RoomCommandService_MicUp_Handler, diff --git a/docs/room-cell-state-machines.md b/docs/room-cell-state-machines.md new file mode 100644 index 00000000..f9d4fdb6 --- /dev/null +++ b/docs/room-cell-state-machines.md @@ -0,0 +1,127 @@ +# Room Cell State Machines + +本文档定义 `room-service` 在微服务多机部署下必须遵守的 Room Cell 状态机。Room Cell 的目标是让同一个房间在同一时间只有一个执行节点提交状态,并且在节点重启、发布、RTC 回调延迟和 outbox 重试时不丢状态、不双写、不重复扣费。 + +## Room + +Room 是房间生命周期的主状态。只有 `active` 房间允许进房、麦位、管理和送礼命令。 + +```mermaid +stateDiagram-v2 + [*] --> creating + creating --> active: CreateRoom 持久化成功 + active --> closing: CloseRoom 开始收尾 + closing --> closed: command log/outbox/meta 提交 + active --> closed: CloseRoom 当前实现一次提交完成 + closed --> [*] +``` + +状态语义: + +| State | Meaning | +| --- | --- | +| `creating` | 正在创建房间外部依赖,不对客户端开放 | +| `active` | 可进房、可管理、可上麦、可送礼 | +| `closing` | 正在关闭,不再接收新业务命令 | +| `closed` | 已关闭,`JoinRoom` 和 guard 查询都必须拒绝 | + +`CloseRoom` 必须作为 Room Cell 命令提交,不能只从后台直接更新 `rooms.status`。关闭房间时必须清空业务 presence、释放麦位、写 command log、写 `RoomClosed` outbox、更新 `rooms` 和 `room_list_entries` 状态。 + +## Presence + +Presence 是 room-service 自己维护的业务进房状态,不等同于腾讯云 IM 或 RTC 的真实连接。 + +```mermaid +stateDiagram-v2 + [*] --> absent + absent --> present: JoinRoom + present --> present: JoinRoom 重试或 RoomHeartbeat 刷新 last_seen_at_ms + present --> left: LeaveRoom + present --> stale_left: stale worker 超时清理 + present --> kicked: KickUser + present --> closed_left: CloseRoom + left --> present: JoinRoom + stale_left --> present: JoinRoom + kicked --> present: UnbanUser 后重新 JoinRoom + closed_left --> [*] +``` + +规则: + +- `RoomHeartbeat` 只能刷新已有 presence,不能创建 presence。 +- `LeaveRoom` 要同步释放用户占用的麦位。 +- RTC `room_exited` 可以清理 presence,但如果用户已经在事件时间之后重新刷新 presence,旧事件必须忽略。 +- `KickUser` 写入 ban 集合,用户必须先 `UnbanUser` 才能重新 `JoinRoom`。 + +## Mic + +Mic 是麦位和 RTC 发流确认状态。业务上麦不等于已经在 RTC 发流。 + +```mermaid +stateDiagram-v2 + [*] --> idle + idle --> locked: SetMicSeatLock(true) + locked --> idle: SetMicSeatLock(false) + idle --> pending_publish: MicUp + pending_publish --> publishing: ConfirmMicPublishing 或 RTC audio_started + pending_publish --> idle: publish_timeout 或 MicDown 或 LeaveRoom + publishing --> idle: MicDown 或 RTC audio_stopped 或 LeaveRoom + publishing --> pending_publish: ChangeMicSeat 保留 mic_session + pending_publish --> pending_publish: ChangeMicSeat 保留 mic_session +``` + +规则: + +- `mic_session_id` 是单次上麦会话 ID,旧会话的确认、停止和超时任务不能清掉新会话。 +- `mic_session_room_version` 和 `last_publish_event_time_ms` 用于丢弃旧 RTC 事件。 +- `pending_publish` 超过 `publish_deadline_ms` 后由 worker 自动下麦。 +- `LeaveRoom` 与 RTC `room_exited` 并发时以业务 presence 的 `last_seen_at_ms` 和当前 `mic_session_id` 为准;旧的 RTC 退房事件不能释放用户重进房后的新麦位会话。 +- `CloseRoom` 必须释放全部麦位,但保留麦位编号和锁定结构。 + +## Lease + +Lease 是多机部署下的房间执行权。Redis 只保存热路由,不是恢复来源;MySQL snapshot + command log 才是恢复来源。 + +```mermaid +stateDiagram-v2 + [*] --> unowned + unowned --> owned_by_node: EnsureOwner + owned_by_node --> owned_by_node: 同节点续约并生成新 lease_token + owned_by_node --> expired: TTL 到期 + expired --> owned_by_other_node: 新节点 EnsureOwner + owned_by_node --> fenced_out: 提交前 VerifyOwner 失败 + fenced_out --> [*] +``` + +规则: + +- Redis runtime route key 统一使用 `app_code + "\0" + room_id`,包括默认 App;不能再使用裸 `room_id` 作为兼容 key。 +- 命令开始前通过 `EnsureOwner` 获得执行权。 +- 命令真正写 command log/outbox 前必须用 `lease_token` 再做一次 `VerifyOwner`。 +- 如果提交前 lease 已经过期或 token 已变化,旧节点必须返回 `UNAVAILABLE`,不能写房间状态。 +- `room_command_log` 保存 `owner_node_id` 和 `lease_token`,用于排查谁在什么 lease 下提交了命令。 +- stale presence worker 和 mic publish timeout worker 只能扫描本节点已加载 Cell;清理前必须确认当前 Redis lease 仍属于本节点,并在读完快照后再次用相同 `lease_token` 校验,最后由命令提交链路再做 fencing。 +- 节点进入 draining 后不能再接收新的 Room Cell 命令,也不能恢复或创建新的 Cell。 + +## Outbox + +Outbox 是房间事件对外投递状态机。它允许重复投递,但多 worker 不应该同时抢同一批。 + +```mermaid +stateDiagram-v2 + [*] --> pending + pending --> delivering: ClaimPendingOutbox + retryable --> delivering: ClaimPendingOutbox + delivering --> delivered: 投递成功并确认 + delivering --> retryable: 投递失败或状态未知 + delivering --> failed: 明确不可重试 + retryable --> failed: 超过策略上限或人工判定 +``` + +规则: + +- `ClaimPendingOutbox` 必须把事件从 `pending/retryable` 原子改成 `delivering`,并写入 `worker_id` 和 `lock_until`。 +- 其他 worker 不能抢到未过期的 `delivering` 事件。 +- 投递成功后才能标记 `delivered`。 +- 投递失败必须保留 envelope 和 last_error,转入 `retryable` 等待下一轮抢占。 +- outbox 事件必须带 `app_code`,消费者按 App 隔离幂等。 diff --git a/docs/room-outbox-compensation-development.md b/docs/room-outbox-compensation-development.md index 26c20042..0a54aa43 100644 --- a/docs/room-outbox-compensation-development.md +++ b/docs/room-outbox-compensation-development.md @@ -11,7 +11,7 @@ | App 生命周期接入 | `room-service` 启动时启动 outbox worker,下线时先停止扫描新批次,再关闭 gRPC/MySQL/Redis | | worker 配置 | 支持启停、扫描间隔、批量大小、单条投递超时和固定间隔重试策略 | | 腾讯云 IM 补偿 | 同步 `PublishRoomEvent` 失败不回滚房间状态,pending outbox 后续补投到腾讯云 IM | -| 可验证测试 | 单测覆盖同步失败后状态已提交、outbox pending、worker 成功补投并标记 published | +| 可验证测试 | 单测覆盖同步失败后状态已提交、outbox pending、worker 成功补投并标记 delivered | 本阶段不做: @@ -29,17 +29,17 @@ | Component | Current Fact | | --- | --- | -| `room-service/internal/room/service/pipeline.go` | 命令成功后先写 command log/outbox,再尝试同步 `PublishRoomEvent`;同步成功 best-effort 标记 `published`,同步失败不回滚状态 | +| `room-service/internal/room/service/pipeline.go` | 命令成功后先写 command log/outbox,再尝试同步 `PublishRoomEvent`;同步成功 best-effort 标记 `delivered`,同步失败不回滚状态 | | `room-service/internal/room/service/outbox_worker.go` | 已有 `RunOutboxWorker(ctx, options)` 持续循环和 `ProcessPendingOutbox(ctx, options)` 单批处理 | -| `room-service/internal/storage/mysql/repository.go` | 已有 `ListPendingOutbox`、`MarkOutboxPublished`、`MarkOutboxFailed` | +| `room-service/internal/storage/mysql/repository.go` | 已有 `ClaimPendingOutbox`、`MarkOutboxDelivered`、`MarkOutboxFailed` | | `room-service/internal/integration/tencent_im.go` | 已能把 `EventEnvelope` 转换成腾讯云 IM 房间系统事件 | | `room-service/internal/app/app.go` | 已在进程生命周期中启动 presence stale worker 和 outbox worker,下线时先停 worker 再关闭 gRPC/MySQL/Redis | 当前风险: - 代码接入前已经残留的 `pending` 事件仍会被补投;V1 接受 at-least-once,客户端按 `event_id` 去重。 -- `room_outbox.status` 目前只有 `pending/published`,适合先表达腾讯云 IM 补偿状态,不适合同时表达 activity/audit 消费状态。 -- 多个 room-service 实例同时扫描同一批 pending 时可能重复投递;V1 接受 at-least-once,客户端按 `event_id` 去重。 +- `room_outbox.status` 统一为 `pending/delivering/delivered/retryable/failed`,不再使用旧的 `published` 命名。 +- 多个 room-service 实例通过 `ClaimPendingOutbox` 抢占同一批事件;未过期的 `delivering` 记录不会被其他 worker 重复抢占。 ## Target Semantics @@ -52,18 +52,19 @@ Room Cell command applied -> persist snapshot if needed -> replace in-memory RoomState -> try synchronous PublishRoomEvent - -> if sync publish success, best-effort mark that event published + -> if sync publish success, best-effort mark that event delivered -> if sync publish fails, keep pending for worker ``` 补偿 worker 语义: ```text -scan room_outbox where status=pending +claim room_outbox where status in (pending, retryable) + -> status=delivering, set worker_id and lock_until -> publish one EventEnvelope to configured OutboxPublisher - -> success: status=published, last_error=NULL - -> failure: status=pending, retry_count=retry_count+1, last_error= - -> next scan retries failed pending records + -> success: status=delivered, last_error=NULL + -> failure: status=retryable, retry_count=retry_count+1, last_error= + -> next scan retries failed retryable records ``` 重要边界: @@ -72,7 +73,7 @@ scan room_outbox where status=pending - worker 只处理已经持久化的 outbox envelope。 - worker 投递失败不能影响 `room-service` ready;腾讯云 IM 抖动时 room 状态服务仍应接收房间命令。 - `request_id` 仍然只做追踪;outbox 去重键是 `event_id`,房间命令幂等键是 `command_id`。 -- `published` 在本阶段表示腾讯云 IM 补偿通道已处理,不表示 activity/audit 已消费。 +- `delivered` 在本阶段表示腾讯云 IM 补偿通道已处理,不表示 activity/audit 已消费。 ## Configuration @@ -165,7 +166,7 @@ type App struct { - 不能在 worker 退出前关闭 MySQL,否则可能无法标记投递结果。 - worker 收到 cancel 后不再拉取新批次;已经进入投递的事件可以完成成功标记或失败标记。 -- 如果进程被强杀,未标记成功的记录保持 `pending`,下次启动继续补偿。 +- 如果进程被强杀,已抢占未完成的记录保持 `delivering`,`lock_until` 过期后下次启动继续补偿。 ## Worker API @@ -201,12 +202,12 @@ func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorker 处理规则: -- 每轮调用 `repository.ListPendingOutbox(ctx, batch_size)`。 +- 每轮调用 `repository.ClaimPendingOutbox(ctx, worker_id, batch_size, lock_until)`,把 `pending/retryable` 事件抢占为 `delivering`。 - 每条记录单独创建 `context.WithTimeout(ctx, publish_timeout)`。 -- `PublishOutboxEvent` 成功后调用 `MarkOutboxPublished`。 +- `PublishOutboxEvent` 成功后调用 `MarkOutboxDelivered`。 - `PublishOutboxEvent` 失败后调用 `MarkOutboxFailed`。 - 单条失败不阻断同批后续记录。 -- `ListPendingOutbox` 或 `MarkOutboxPublished/Failed` 失败属于本轮 worker 错误,记录后等待下一轮。 +- `ClaimPendingOutbox` 或 `MarkOutboxDelivered/Failed` 失败属于本轮 worker 错误,记录后等待下一轮。 ## Sync Publish Interaction @@ -216,16 +217,16 @@ func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorker if result.applied && result.syncEvent != nil: err := syncPublisher.PublishRoomEvent(ctx, *result.syncEvent) if err == nil: - repository.MarkOutboxPublished(ctx, result.syncEvent.EventID) + repository.MarkOutboxDelivered(ctx, result.syncEvent.EventID) if err != nil: keep room_outbox pending ``` 约束: -- `MarkOutboxPublished` 失败不能让已经成功提交的房间命令返回失败;最多造成后续重复投递。 -- 同步成功但进程在标记 published 前崩溃时,worker 后续可能重复投递;客户端必须用 `event_id` 去重。 -- 对 `RoomCreated`、`RoomHeatChanged`、`RoomRankChanged` 这类不推 IM 的事件,`PublishOutboxEvent` 返回 no-op success 后可标记 `published`,避免长期 pending。 +- `MarkOutboxDelivered` 失败不能让已经成功提交的房间命令返回失败;最多造成后续重复投递。 +- 同步成功但进程在标记 delivered 前崩溃时,worker 后续可能重复投递;客户端必须用 `event_id` 去重。 +- 对 `RoomCreated`、`RoomHeatChanged`、`RoomRankChanged` 这类不推 IM 的事件,`PublishOutboxEvent` 返回 no-op success 后可标记 `delivered`,避免长期 pending。 ## Retry Strategy @@ -233,11 +234,11 @@ V1 采用固定间隔无限重试: | Case | Behavior | | --- | --- | -| 腾讯云 IM 网络错误 | `retry_count + 1`,保留 `pending`,下一轮继续 | -| 腾讯云 IM 返回可重试错误 | `retry_count + 1`,保留 `pending`,下一轮继续 | +| 腾讯云 IM 网络错误 | `retry_count + 1`,转为 `retryable`,下一轮继续 | +| 腾讯云 IM 返回可重试错误 | `retry_count + 1`,转为 `retryable`,下一轮继续 | | envelope 反序列化失败 | worker 本轮返回错误,不删除记录;后续需要人工排查或补工具 | -| 不需要推 IM 的事件类型 | no-op success,标记 `published` | -| 进程退出 | 未成功标记的记录保持 `pending` | +| 不需要推 IM 的事件类型 | no-op success,标记 `delivered` | +| 进程退出 | 已抢占未完成的记录保持 `delivering`,`lock_until` 过期后可被重新抢占 | 为什么不加最大重试次数: @@ -257,7 +258,7 @@ V1 采用固定间隔无限重试: | `event_type` | RoomUserJoined、RoomGiftSent 等 | | `room_id` | 事件所属房间 | | `retry_count` | 当前失败次数 | -| `status` | pending 或 published | +| `status` | pending、delivering、delivered、retryable 或 failed | | `error` | 最近一次失败原因,不能包含密钥或完整腾讯响应体 | 指标后续可补: @@ -277,9 +278,9 @@ room_outbox_oldest_pending_age_ms 1. 扩展 room-service 配置结构和三份 YAML,增加 `outbox_worker` 配置。 2. 给 `room/service` 增加 `OutboxWorkerOptions` 和 `RunOutboxWorker`。 3. 调整 `ProcessPendingOutbox`,支持 `batch_size`、单条 `publish_timeout`、单条失败不中断批次。 -4. 调整命令链路:同步 `PublishRoomEvent` 成功后 best-effort `MarkOutboxPublished(event_id)`;失败保持 pending。 +4. 调整命令链路:同步 `PublishRoomEvent` 成功后 best-effort `MarkOutboxDelivered(event_id)`;同步失败保留初始 `pending`,worker 投递失败转为 `retryable`。 5. 在 `app.Run` 启动 outbox worker,在 `app.Close` cancel 并等待 worker 退出。 -6. 增加单测覆盖同步失败补偿、重试失败保留 pending、worker cancel 退出。 +6. 增加单测覆盖同步失败补偿、重试失败转为 `retryable`、worker cancel 退出。 7. 更新 README 当前限制,说明 outbox worker 已接入生命周期。 ## Acceptance Tests @@ -290,12 +291,12 @@ room_outbox_oldest_pending_age_ms | --- | --- | | 同步 IM 失败后命令成功 | `JoinRoom` 或 `SendGift` 返回成功,RoomSnapshot 已更新 | | 同步 IM 失败后 outbox pending | 对应 `event_id` 仍为 `pending`,`retry_count` 未因同步失败被提前增加 | -| worker 补投成功 | fake outbox publisher 收到同一 `event_id`,repository 标记 `published` | -| worker 补投失败 | 记录仍为 `pending`,`retry_count+1`,`last_error` 有值 | -| 下一轮成功 | 第一次失败、第二次成功后状态变为 `published` | -| 同步 IM 成功 | 对应 `event_id` best-effort 标记 `published`,worker 不再扫描该事件 | +| worker 补投成功 | fake outbox publisher 收到同一 `event_id`,repository 标记 `delivered` | +| worker 补投失败 | 记录转为 `retryable`,`retry_count+1`,`last_error` 有值 | +| 下一轮成功 | 第一次失败、第二次成功后状态变为 `delivered` | +| 同步 IM 成功 | 对应 `event_id` best-effort 标记 `delivered`,worker 不再扫描该事件 | | worker cancel | cancel 后不再扫描新批次,当前投递受 `publish_timeout` 约束后退出 | -| 非 IM 事件 | `RoomCreated/RoomHeatChanged/RoomRankChanged` 不发送腾讯 IM,但会标记 `published` | +| 非 IM 事件 | `RoomCreated/RoomHeatChanged/RoomRankChanged` 不发送腾讯 IM,但会标记 `delivered` | 已有测试 `TestRoomOutboxCompensationWhenSyncPublishFails` 可以作为基础,但需要补齐持续 worker 和同步成功去重场景。 @@ -337,7 +338,7 @@ room command committed -> outbox remains pending -> app-level worker scans pending -> worker publishes same event_id to Tencent IM publisher - -> outbox status becomes published + -> outbox status becomes delivered -> process shutdown stops worker before closing MySQL ``` diff --git a/docs/voice-room-basic-loop-implementation.md b/docs/voice-room-basic-loop-implementation.md index 360ca232..b9447da6 100644 --- a/docs/voice-room-basic-loop-implementation.md +++ b/docs/voice-room-basic-loop-implementation.md @@ -2,6 +2,12 @@ 本文档定义语音房 v1 基础闭环的实现顺序和验收边界。目标不是做完整语音房,而是先让“登录用户创建房间、进入房间、登录腾讯云 IM、加入房间群、接收房间系统消息、离房、重连恢复”成为可测闭环。 +Room Cell 的完整状态机见: + +```text +docs/room-cell-state-machines.md +``` + ## Scope 本阶段必须打通: diff --git a/services/room-service/configs/config.yaml b/services/room-service/configs/config.yaml index 22cc2529..6f961504 100644 --- a/services/room-service/configs/config.yaml +++ b/services/room-service/configs/config.yaml @@ -29,7 +29,7 @@ presence_stale_scan_interval: "30s" mic_publish_timeout: "15s" mic_publish_scan_interval: "1s" outbox_worker: - # room_outbox 是腾讯云 IM 系统消息补偿通道;失败保持 pending 并固定间隔重试。 + # room_outbox 是腾讯云 IM 系统消息补偿通道;失败转为 retryable 并固定间隔重试。 enabled: true poll_interval: "1s" batch_size: 100 diff --git a/services/room-service/deploy/mysql/initdb/001_room_service.sql b/services/room-service/deploy/mysql/initdb/001_room_service.sql index c3dececd..c965f5cd 100644 --- a/services/room-service/deploy/mysql/initdb/001_room_service.sql +++ b/services/room-service/deploy/mysql/initdb/001_room_service.sql @@ -7,7 +7,7 @@ CREATE DATABASE IF NOT EXISTS hyapp_room USE hyapp_room; CREATE TABLE IF NOT EXISTS rooms ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, room_id VARCHAR(64) NOT NULL, room_short_id VARCHAR(32) NOT NULL DEFAULT '', owner_user_id BIGINT NOT NULL, @@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS rooms ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS room_list_entries ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, room_id VARCHAR(64) NOT NULL, room_short_id VARCHAR(32) NOT NULL DEFAULT '', visible_region_id BIGINT NOT NULL DEFAULT 0, @@ -50,7 +50,7 @@ CREATE TABLE IF NOT EXISTS room_list_entries ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS room_snapshots ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, room_id VARCHAR(64) NOT NULL, room_version BIGINT NOT NULL, payload LONGBLOB NOT NULL, @@ -61,12 +61,14 @@ CREATE TABLE IF NOT EXISTS room_snapshots ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS room_command_log ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, room_id VARCHAR(64) NOT NULL, room_version BIGINT NOT NULL, command_id VARCHAR(128) NOT NULL, command_type VARCHAR(64) NOT NULL, + owner_node_id VARCHAR(128) NOT NULL DEFAULT '', + lease_token VARCHAR(128) NOT NULL DEFAULT '', payload LONGBLOB NOT NULL, replayable BOOLEAN NOT NULL, created_at TIMESTAMP(3) NOT NULL, @@ -75,16 +77,19 @@ CREATE TABLE IF NOT EXISTS room_command_log ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS room_outbox ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, event_id VARCHAR(128) NOT NULL, event_type VARCHAR(64) NOT NULL, room_id VARCHAR(64) NOT NULL, status VARCHAR(32) NOT NULL, + worker_id VARCHAR(128) NOT NULL DEFAULT '', + lock_until TIMESTAMP(3) NULL, envelope LONGBLOB NOT NULL, created_at TIMESTAMP(3) NOT NULL, retry_count INT NOT NULL DEFAULT 0, last_error TEXT NULL, updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (app_code, event_id), - KEY idx_room_outbox_pending (app_code, status, created_at) + KEY idx_room_outbox_pending (app_code, status, created_at), + KEY idx_room_outbox_claim (app_code, status, lock_until, created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/services/room-service/internal/app/app.go b/services/room-service/internal/app/app.go index 2f7551a4..f74051d5 100644 --- a/services/room-service/internal/app/app.go +++ b/services/room-service/internal/app/app.go @@ -206,6 +206,9 @@ func (a *App) Close() { a.closeOnce.Do(func() { // 先进入 draining,避免下线中的节点继续接管房间 lease 或接收新命令。 a.health.MarkDraining() + if a.service != nil { + a.service.MarkDraining() + } if a.workerCancel != nil { // 先停后台 worker 并等待当前投递结果落库,再关闭 gRPC/MySQL/Redis。 a.workerCancel() diff --git a/services/room-service/internal/integration/clients.go b/services/room-service/internal/integration/clients.go index b4c7653c..766656c2 100644 --- a/services/room-service/internal/integration/clients.go +++ b/services/room-service/internal/integration/clients.go @@ -25,6 +25,6 @@ type RoomEventPublisher interface { // OutboxPublisher 抽象 outbox worker 对外部消费者的异步投递。 type OutboxPublisher interface { - // PublishOutboxEvent 投递 protobuf outbox 信封,失败由 room_outbox 保留 pending 状态重试。 + // PublishOutboxEvent 投递 protobuf outbox 信封,失败由 room_outbox 转为 retryable 状态重试。 PublishOutboxEvent(ctx context.Context, envelope *roomeventsv1.EventEnvelope) error } diff --git a/services/room-service/internal/room/command/command.go b/services/room-service/internal/room/command/command.go index 581a4604..5f2f5354 100644 --- a/services/room-service/internal/room/command/command.go +++ b/services/room-service/internal/room/command/command.go @@ -105,6 +105,16 @@ type LeaveRoom struct { // Type 返回命令类型。 func (LeaveRoom) Type() string { return "leave_room" } +// CloseRoom 定义房间关闭请求。 +type CloseRoom struct { + Base + // Reason 记录关闭来源,例如 closed_by_owner 或 admin_closed。 + Reason string `json:"reason,omitempty"` +} + +// Type 返回命令类型。 +func (CloseRoom) Type() string { return "close_room" } + // MicUp 定义上麦请求。 type MicUp struct { Base @@ -334,6 +344,8 @@ func Deserialize(commandType string, payload []byte) (Command, error) { cmd = &RoomHeartbeat{} case LeaveRoom{}.Type(): cmd = &LeaveRoom{} + case CloseRoom{}.Type(): + cmd = &CloseRoom{} case MicUp{}.Type(): cmd = &MicUp{} case MicDown{}.Type(): diff --git a/services/room-service/internal/room/outbox/outbox.go b/services/room-service/internal/room/outbox/outbox.go index 968aa2ae..b02ffb82 100644 --- a/services/room-service/internal/room/outbox/outbox.go +++ b/services/room-service/internal/room/outbox/outbox.go @@ -13,8 +13,14 @@ import ( const ( // StatusPending 表示事件已经入库,但尚未投递完成。 StatusPending = "pending" - // StatusPublished 表示事件已成功投递到外部消费者。 - StatusPublished = "published" + // StatusDelivering 表示事件已被某个 worker 抢占,正在投递中。 + StatusDelivering = "delivering" + // StatusRetryable 表示上次投递失败,后续 worker 可继续重试。 + StatusRetryable = "retryable" + // StatusFailed 表示事件不可重试,需要人工或专项补偿处理。 + StatusFailed = "failed" + // StatusDelivered 表示事件已成功投递到外部消费者。 + StatusDelivered = "delivered" ) // Record 表达 room_outbox 表的一条逻辑记录。 @@ -37,6 +43,10 @@ type Record struct { RetryCount int // LastError 保存最近一次投递失败原因。 LastError string + // WorkerID 记录当前抢占该事件的 worker。 + WorkerID string + // LockUntilMS 是 delivering 锁的截止时间。 + LockUntilMS int64 } // Build 把具体事件体封装成统一 outbox 记录。 diff --git a/services/room-service/internal/room/service/authorization.go b/services/room-service/internal/room/service/authorization.go index b46d99db..248973e9 100644 --- a/services/room-service/internal/room/service/authorization.go +++ b/services/room-service/internal/room/service/authorization.go @@ -37,7 +37,7 @@ func actorRole(current *state.RoomState, actorUserID int64) roomRole { func requireActiveRoom(current *state.RoomState) error { // 当前只有 active 房间可执行管理和麦位命令;CloseRoom 语义后续单独扩展。 - if current == nil || current.Status != "active" { + if current == nil || current.Status != state.RoomStatusActive { return xerr.New(xerr.Conflict, "room is not active") } return nil diff --git a/services/room-service/internal/room/service/create_room.go b/services/room-service/internal/room/service/create_room.go index ed283430..aadeaccc 100644 --- a/services/room-service/internal/room/service/create_room.go +++ b/services/room-service/internal/room/service/create_room.go @@ -65,6 +65,9 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) // CreateRoom 的 owner/host 默认来自已鉴权调用方,不允许匿名内部命令造房间。 return nil, xerr.New(xerr.InvalidArgument, "actor_user_id is required") } + if s.isDraining() { + return nil, xerr.New(xerr.Unavailable, "room service is draining") + } // protobuf 请求先收敛为 command,后续幂等、持久化和恢复都只认识 command 模型。 cmd := command.CreateRoom{ @@ -135,6 +138,9 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) // 房间创建必须先保证外部群组可用。 return nil, err } + if err := s.ensureLeaseStillOwned(ctx, cmd.RoomID(), lease); err != nil { + return nil, err + } // 创建态直接初始化 RoomState,owner 作为首个在线用户进入房间。 now := s.clock.Now() @@ -175,30 +181,31 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) HostUserID: cmd.HostUserID, SeatCount: cmd.SeatCount, Mode: cmd.Mode, - Status: "active", + Status: state.RoomStatusActive, VisibleRegionID: cmd.VisibleRegionID, RoomShortID: cmd.RoomShortID, }); err != nil { return nil, err } - if err := s.repository.SaveCommand(ctx, CommandRecord{ - AppCode: cmd.AppCode, - RoomID: cmd.RoomID(), - RoomVersion: roomState.Version, - CommandID: cmd.ID(), - CommandType: cmd.Type(), - Payload: payload, - Replayable: true, - CreatedAt: now, + if err := s.repository.SaveMutation(ctx, MutationCommit{ + Command: CommandRecord{ + AppCode: cmd.AppCode, + RoomID: cmd.RoomID(), + RoomVersion: roomState.Version, + CommandID: cmd.ID(), + CommandType: cmd.Type(), + Payload: payload, + Replayable: true, + OwnerNodeID: s.nodeID, + LeaseToken: lease.LeaseToken, + CreatedAt: now, + }, + OutboxRecords: []outbox.Record{createdEvent}, }); err != nil { return nil, err } - if err := s.repository.SaveOutbox(ctx, []outbox.Record{createdEvent}); err != nil { - return nil, err - } - snapshot := snapshotWithApp(ctx, roomState.ToProto()) if err := s.persistSnapshot(ctx, snapshot); err != nil { return nil, err diff --git a/services/room-service/internal/room/service/helpers.go b/services/room-service/internal/room/service/helpers.go index 6781f82f..4abfb4e0 100644 --- a/services/room-service/internal/room/service/helpers.go +++ b/services/room-service/internal/room/service/helpers.go @@ -2,7 +2,6 @@ package service import ( "context" - "strings" "time" roomv1 "hyapp.local/api/proto/room/v1" @@ -11,6 +10,7 @@ import ( "hyapp/services/room-service/internal/room/cell" "hyapp/services/room-service/internal/room/command" "hyapp/services/room-service/internal/room/state" + "hyapp/services/room-service/internal/router" ) type loadedRoomRef struct { @@ -49,11 +49,6 @@ func (s *Service) loadedRoomRefs() []loadedRoomRef { func runtimeRoomKey(appCode string, roomID string) string { appCode = appcode.Normalize(appCode) - if appCode == appcode.Default { - // 默认 App 仍使用旧 key,测试和本地 Redis 可继续用 room_id 直接排查。 - return roomID - } - return appCode + "\x00" + roomID } @@ -61,12 +56,30 @@ func runtimeRoomKeyFromContext(ctx context.Context, roomID string) string { return runtimeRoomKey(appcode.FromContext(ctx), roomID) } -func runtimeRoomRef(key string) loadedRoomRef { - if app, roomID, ok := strings.Cut(key, "\x00"); ok { - return loadedRoomRef{AppCode: appcode.Normalize(app), RoomID: roomID} +func (s *Service) loadedRoomLease(ctx context.Context, roomRef loadedRoomRef, now time.Time) (router.Lease, bool, error) { + lease, exists, err := s.directory.Lookup(ctx, runtimeRoomKey(roomRef.AppCode, roomRef.RoomID)) + if err != nil || !exists { + return router.Lease{}, false, err + } + if lease.NodeID != s.nodeID || !lease.ValidAt(now) { + return router.Lease{}, false, nil } - return loadedRoomRef{AppCode: appcode.Default, RoomID: key} + return lease, true, nil +} + +func (s *Service) verifyLoadedRoomLease(ctx context.Context, roomRef loadedRoomRef, lease router.Lease, now time.Time) (bool, error) { + return s.directory.VerifyOwner(ctx, runtimeRoomKey(roomRef.AppCode, roomRef.RoomID), s.nodeID, lease.LeaseToken, now) +} + +func runtimeRoomRef(key string) loadedRoomRef { + for index := 0; index < len(key); index++ { + if key[index] == 0 { + return loadedRoomRef{AppCode: appcode.Normalize(key[:index]), RoomID: key[index+1:]} + } + } + + return loadedRoomRef{AppCode: "", RoomID: key} } func commandResult(applied bool, roomVersion int64, now time.Time) *roomv1.CommandResult { diff --git a/services/room-service/internal/room/service/lifecycle.go b/services/room-service/internal/room/service/lifecycle.go index 19f947ea..c45aeaf4 100644 --- a/services/room-service/internal/room/service/lifecycle.go +++ b/services/room-service/internal/room/service/lifecycle.go @@ -3,8 +3,16 @@ 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" ) func (s *Service) requireRoomOpenForEntry(ctx context.Context, roomID string) error { @@ -25,5 +33,70 @@ func (s *Service) isRoomClosed(ctx context.Context, roomID string) (bool, error) func isClosedRoomStatus(status string) bool { value := strings.TrimSpace(status) - return value != "" && !strings.EqualFold(value, "active") + return value != "" && !strings.EqualFold(value, state.RoomStatusActive) +} + +// CloseRoom 关闭房间,统一清理 presence、麦位、读模型状态和房间外事件。 +func (s *Service) CloseRoom(ctx context.Context, req *roomv1.CloseRoomRequest) (*roomv1.CloseRoomResponse, error) { + ctx = contextFromMeta(ctx, req.GetMeta()) + cmd := command.CloseRoom{ + Base: baseFromMeta(req.GetMeta()), + Reason: strings.TrimSpace(req.GetReason()), + } + if cmd.Reason == "" { + cmd.Reason = "closed_by_owner" + } + + result, err := s.mutateRoom(ctx, cmd, true, func(now time.Time, current *state.RoomState, _ *rank.LocalRank) (mutationResult, []outbox.Record, error) { + if current == nil { + return mutationResult{}, nil, xerr.New(xerr.NotFound, "room not found") + } + if current.Status == state.RoomStatusClosed { + return mutationResult{snapshot: current.ToProto()}, nil, nil + } + if current.Status != state.RoomStatusActive && current.Status != state.RoomStatusClosing { + return mutationResult{}, nil, xerr.New(xerr.Conflict, "room is not active") + } + if err := requireOwnerOrHostPresent(current, cmd.ActorUserID()); err != nil { + return mutationResult{}, nil, err + } + + current.Status = state.RoomStatusClosed + current.OnlineUsers = map[int64]*state.RoomUserState{} + for index := range current.MicSeats { + current.ClearMicSession(index) + } + current.Version++ + + closedEvent, err := outbox.Build(current.RoomID, "RoomClosed", current.Version, now, &roomeventsv1.RoomClosed{ + ActorUserId: cmd.ActorUserID(), + Reason: cmd.Reason, + }) + if err != nil { + return mutationResult{}, nil, err + } + + return mutationResult{ + snapshot: current.ToProto(), + roomStatus: state.RoomStatusClosed, + syncEvent: &tencentim.RoomEvent{ + EventID: closedEvent.EventID, + RoomID: current.RoomID, + EventType: "room_closed", + ActorUserID: cmd.ActorUserID(), + RoomVersion: current.Version, + Attributes: map[string]string{ + "reason": cmd.Reason, + }, + }, + }, []outbox.Record{closedEvent}, nil + }) + if err != nil { + return nil, err + } + + return &roomv1.CloseRoomResponse{ + Result: commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()), + Room: result.snapshot, + }, nil } diff --git a/services/room-service/internal/room/service/mic.go b/services/room-service/internal/room/service/mic.go index 15eafcd6..7d16107f 100644 --- a/services/room-service/internal/room/service/mic.go +++ b/services/room-service/internal/room/service/mic.go @@ -240,7 +240,7 @@ func (s *Service) ChangeMicSeat(ctx context.Context, req *roomv1.ChangeMicSeatRe if err := requireActorPresent(current, cmd.ActorUserID()); err != nil { return mutationResult{}, nil, err } - if err := canManageTarget(current, cmd.ActorUserID(), cmd.TargetUserID); err != nil { + if err := canSelfOrManageTarget(current, cmd.ActorUserID(), cmd.TargetUserID); err != nil { return mutationResult{}, nil, err } diff --git a/services/room-service/internal/room/service/mic_publish_timeout.go b/services/room-service/internal/room/service/mic_publish_timeout.go index dcb68da4..de7bc11e 100644 --- a/services/room-service/internal/room/service/mic_publish_timeout.go +++ b/services/room-service/internal/room/service/mic_publish_timeout.go @@ -38,6 +38,14 @@ func (s *Service) SweepMicPublishTimeouts(ctx context.Context) error { nowMs := now.UnixMilli() for _, roomRef := range s.loadedRoomRefs() { roomCtx := appcode.WithContext(ctx, roomRef.AppCode) + lease, owned, err := s.loadedRoomLease(roomCtx, roomRef, now) + if err != nil { + return err + } + if !owned { + continue + } + roomCell := s.loadCell(roomCtx, roomRef.RoomID) if roomCell == nil { continue @@ -47,8 +55,23 @@ func (s *Service) SweepMicPublishTimeouts(ctx context.Context) error { if err != nil { return err } + owned, err = s.verifyLoadedRoomLease(roomCtx, roomRef, lease, s.clock.Now()) + if err != nil { + return err + } + if !owned { + continue + } for _, seat := range pendingPublishTimedOutSeats(currentState, nowMs) { + owned, err = s.verifyLoadedRoomLease(roomCtx, roomRef, lease, s.clock.Now()) + if err != nil { + return err + } + if !owned { + break + } + cmd := command.MicDown{ Base: command.Base{ RequestID: idgen.New("req_mic_publish_timeout"), diff --git a/services/room-service/internal/room/service/outbox_worker.go b/services/room-service/internal/room/service/outbox_worker.go index 072de22f..e777840a 100644 --- a/services/room-service/internal/room/service/outbox_worker.go +++ b/services/room-service/internal/room/service/outbox_worker.go @@ -6,6 +6,8 @@ import ( "log" "strings" "time" + + "hyapp/pkg/appcode" ) const ( @@ -96,8 +98,8 @@ func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorker return fmt.Errorf("unsupported outbox retry_strategy %q", options.RetryStrategy) } - // 补偿 worker 从 repository 扫描 pending 事件;同步 room->im 失败不会回滚房间状态。 - records, err := s.repository.ListPendingOutbox(ctx, options.BatchSize) + // 补偿 worker 先抢占 pending/retryable 事件,再投递,避免多机同时处理同一批。 + records, err := s.repository.ClaimPendingOutbox(ctx, s.nodeID, options.BatchSize, time.Now().Add(options.PublishTimeout)) if err != nil { return err } @@ -113,27 +115,27 @@ func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorker err := s.outboxPublisher.PublishOutboxEvent(publishCtx, record.Envelope) cancel() if err != nil { - // 投递失败保持 pending,并记录错误和重试次数,等待下一轮 worker 再试。 - markCtx, markCancel := context.WithTimeout(context.Background(), options.PublishTimeout) + // 投递失败转为 retryable,并记录错误和重试次数,等待下一轮 worker 再抢占。 + markCtx, markCancel := context.WithTimeout(appcode.WithContext(context.Background(), record.AppCode), options.PublishTimeout) markErr := s.repository.MarkOutboxFailed(markCtx, record.EventID, trimOutboxError(err.Error())) markCancel() if markErr != nil { return markErr } - log.Printf("worker=%s node_id=%s event_id=%s event_type=%s room_id=%s retry_count=%d status=pending error=%q", outboxWorkerName, s.nodeID, record.EventID, record.EventType, record.RoomID, record.RetryCount+1, trimOutboxError(err.Error())) + log.Printf("worker=%s node_id=%s event_id=%s event_type=%s room_id=%s retry_count=%d status=retryable error=%q", outboxWorkerName, s.nodeID, record.EventID, record.EventType, record.RoomID, record.RetryCount+1, trimOutboxError(err.Error())) continue } - // 只有外部发布成功后才能标记 published。 - markCtx, markCancel := context.WithTimeout(context.Background(), options.PublishTimeout) - markErr := s.repository.MarkOutboxPublished(markCtx, record.EventID) + // 只有外部发布成功后才能标记 delivered。 + markCtx, markCancel := context.WithTimeout(appcode.WithContext(context.Background(), record.AppCode), options.PublishTimeout) + markErr := s.repository.MarkOutboxDelivered(markCtx, record.EventID) markCancel() if markErr != nil { return markErr } - log.Printf("worker=%s node_id=%s event_id=%s event_type=%s room_id=%s retry_count=%d status=published", outboxWorkerName, s.nodeID, record.EventID, record.EventType, record.RoomID, record.RetryCount) + log.Printf("worker=%s node_id=%s event_id=%s event_type=%s room_id=%s retry_count=%d status=delivered", outboxWorkerName, s.nodeID, record.EventID, record.EventType, record.RoomID, record.RetryCount) } return nil diff --git a/services/room-service/internal/room/service/pipeline.go b/services/room-service/internal/room/service/pipeline.go index 63936af7..008b72c0 100644 --- a/services/room-service/internal/room/service/pipeline.go +++ b/services/room-service/internal/room/service/pipeline.go @@ -12,6 +12,7 @@ import ( "hyapp/services/room-service/internal/room/outbox" "hyapp/services/room-service/internal/room/rank" "hyapp/services/room-service/internal/room/state" + "hyapp/services/room-service/internal/router" ) func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayable bool, mutate func(now time.Time, current *state.RoomState, localRank *rank.LocalRank) (mutationResult, []outbox.Record, error)) (mutationResult, error) { @@ -19,6 +20,10 @@ func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayabl // command meta 是幂等、路由、审计和权限判断的共同基础,缺一不可。 return mutationResult{}, xerr.New(xerr.InvalidArgument, "command meta is incomplete") } + if s.isDraining() { + // 下线中的节点只让已经进入执行链路的命令收尾,不再接收新的 Room Cell 命令。 + return mutationResult{}, xerr.New(xerr.Unavailable, "room service is draining") + } payload, seen, err := s.commandPayloadForIdempotency(ctx, cmd) if err != nil { @@ -35,7 +40,7 @@ func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayabl } // 确保当前节点持有房间 lease,并在没有内存 Cell 时完成恢复。 - roomCell, err := s.ensureCell(ctx, cmd.RoomID()) + roomCell, lease, err := s.ensureCell(ctx, cmd.RoomID()) if err != nil { return mutationResult{}, err } @@ -60,24 +65,26 @@ func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayabl if result.snapshot.GetVersion() != current.Version { // 版本变化代表本命令产生实际状态变更,需要持久化命令和事件。 - if err := s.repository.SaveCommand(ctx, CommandRecord{ - AppCode: appcode.FromContext(ctx), - RoomID: cmd.RoomID(), - RoomVersion: nextState.Version, - CommandID: cmd.ID(), - CommandType: cmd.Type(), - Payload: commandPayloadForRecord(payload, result), - Replayable: replayable, - CreatedAt: now, - }); err != nil { + if err := s.ensureLeaseStillOwned(ctx, cmd.RoomID(), lease); err != nil { return nil, err } - - if len(outboxRecords) > 0 { - // outbox 与 command log 共同构成恢复和房间外投递来源。 - if err := s.repository.SaveOutbox(ctx, outboxRecords); err != nil { - return nil, err - } + if err := s.repository.SaveMutation(ctx, MutationCommit{ + Command: CommandRecord{ + AppCode: appcode.FromContext(ctx), + RoomID: cmd.RoomID(), + RoomVersion: nextState.Version, + CommandID: cmd.ID(), + CommandType: cmd.Type(), + Payload: commandPayloadForRecord(payload, result), + Replayable: replayable, + OwnerNodeID: s.nodeID, + LeaseToken: lease.LeaseToken, + CreatedAt: now, + }, + OutboxRecords: outboxRecords, + RoomStatus: result.roomStatus, + }); err != nil { + return nil, err } // 持久化成功后再替换内存状态,避免内存提交领先于恢复来源。 @@ -88,15 +95,22 @@ func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayabl } else { // no-op 命令仍写入 command log,保证相同 command_id 重试可命中幂等, // 不同 payload 复用 command_id 会被后续入口拒绝为 CONFLICT。 - if err := s.repository.SaveCommand(ctx, CommandRecord{ - AppCode: appcode.FromContext(ctx), - RoomID: cmd.RoomID(), - RoomVersion: current.Version, - CommandID: cmd.ID(), - CommandType: cmd.Type(), - Payload: payload, - Replayable: false, - CreatedAt: now, + if err := s.ensureLeaseStillOwned(ctx, cmd.RoomID(), lease); err != nil { + return nil, err + } + if err := s.repository.SaveMutation(ctx, MutationCommit{ + Command: CommandRecord{ + AppCode: appcode.FromContext(ctx), + RoomID: cmd.RoomID(), + RoomVersion: current.Version, + CommandID: cmd.ID(), + CommandType: cmd.Type(), + Payload: payload, + Replayable: false, + OwnerNodeID: s.nodeID, + LeaseToken: lease.LeaseToken, + CreatedAt: now, + }, }); err != nil { return nil, err } @@ -124,12 +138,12 @@ func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayabl if result.applied && result.syncEvent != nil { // 同步腾讯云 IM 失败不回滚房间状态;outbox 后续负责补偿投递。 if err := s.syncPublisher.PublishRoomEvent(ctx, *result.syncEvent); err == nil { - // 同步投递成功后 best-effort 标记 published,避免补偿 worker 对同一 event_id 重复补投。 - markCtx, cancel := context.WithTimeout(context.Background(), defaultOutboxWorkerOptions().PublishTimeout) - markErr := s.repository.MarkOutboxPublished(markCtx, result.syncEvent.EventID) + // 同步投递成功后 best-effort 标记 delivered,避免补偿 worker 对同一 event_id 重复补投。 + markCtx, cancel := context.WithTimeout(appcode.WithContext(context.Background(), appcode.FromContext(ctx)), defaultOutboxWorkerOptions().PublishTimeout) + markErr := s.repository.MarkOutboxDelivered(markCtx, result.syncEvent.EventID) cancel() if markErr != nil { - log.Printf("worker=room_outbox node_id=%s event_id=%s room_id=%s status=mark_published_failed error=%q", s.nodeID, result.syncEvent.EventID, result.syncEvent.RoomID, trimOutboxError(markErr.Error())) + log.Printf("worker=room_outbox node_id=%s event_id=%s room_id=%s status=mark_delivered_failed error=%q", s.nodeID, result.syncEvent.EventID, result.syncEvent.RoomID, trimOutboxError(markErr.Error())) } } } @@ -171,3 +185,14 @@ func commandPayloadForRecord(defaultPayload []byte, result mutationResult) []byt } return defaultPayload } + +func (s *Service) ensureLeaseStillOwned(ctx context.Context, roomID string, lease router.Lease) error { + ok, err := s.directory.VerifyOwner(ctx, runtimeRoomKeyFromContext(ctx, roomID), s.nodeID, lease.LeaseToken, s.clock.Now()) + if err != nil { + return err + } + if !ok { + return xerr.New(xerr.Unavailable, "room lease is no longer owned by this node") + } + return nil +} diff --git a/services/room-service/internal/room/service/presence.go b/services/room-service/internal/room/service/presence.go index 09537c57..2a68253e 100644 --- a/services/room-service/internal/room/service/presence.go +++ b/services/room-service/internal/room/service/presence.go @@ -234,6 +234,14 @@ func (s *Service) SweepStalePresence(ctx context.Context) error { cutoffMs := now.Add(-s.presenceStaleAfter).UnixMilli() for _, roomRef := range s.loadedRoomRefs() { roomCtx := appcode.WithContext(ctx, roomRef.AppCode) + lease, owned, err := s.loadedRoomLease(roomCtx, roomRef, now) + if err != nil { + return err + } + if !owned { + continue + } + roomCell := s.loadCell(roomCtx, roomRef.RoomID) if roomCell == nil { continue @@ -243,8 +251,23 @@ func (s *Service) SweepStalePresence(ctx context.Context) error { if err != nil { return err } + owned, err = s.verifyLoadedRoomLease(roomCtx, roomRef, lease, s.clock.Now()) + if err != nil { + return err + } + if !owned { + continue + } for _, userID := range stalePresenceUserIDs(currentState, cutoffMs) { + owned, err = s.verifyLoadedRoomLease(roomCtx, roomRef, lease, s.clock.Now()) + if err != nil { + return err + } + if !owned { + break + } + cmd := command.LeaveRoom{ Base: command.Base{ RequestID: idgen.New("req_presence_stale"), diff --git a/services/room-service/internal/room/service/recovery.go b/services/room-service/internal/room/service/recovery.go index 06332679..fa3f0051 100644 --- a/services/room-service/internal/room/service/recovery.go +++ b/services/room-service/internal/room/service/recovery.go @@ -11,48 +11,53 @@ import ( "hyapp/services/room-service/internal/room/command" "hyapp/services/room-service/internal/room/rank" "hyapp/services/room-service/internal/room/state" + "hyapp/services/room-service/internal/router" ) // ensureCell 确保当前节点拥有房间执行权,并在本地缺少 Cell 时从 MySQL 恢复。 -func (s *Service) ensureCell(ctx context.Context, roomID string) (*cell.RoomCell, error) { +func (s *Service) ensureCell(ctx context.Context, roomID string) (*cell.RoomCell, router.Lease, error) { // 每次写命令先刷新或接管 lease,确保同一房间同一时刻只有一个执行节点。 lease, err := s.directory.EnsureOwner(ctx, runtimeRoomKeyFromContext(ctx, roomID), s.nodeID, s.clock.Now(), s.leaseTTL) if err != nil { - return nil, err + return nil, router.Lease{}, err } if lease.NodeID != s.nodeID { // 仍有其他有效 owner 时当前节点不能执行该房间命令。 - return nil, xerr.New(xerr.Conflict, fmt.Sprintf("room is owned by %s", lease.NodeID)) + return nil, router.Lease{}, xerr.New(xerr.Conflict, fmt.Sprintf("room is owned by %s", lease.NodeID)) } if roomCell := s.loadCell(ctx, roomID); roomCell != nil { // 本节点已经装载该房间,直接复用已有 Room Cell。 - return roomCell, nil + return roomCell, lease, nil + } + + if s.isDraining() { + return nil, router.Lease{}, xerr.New(xerr.Unavailable, "room service is draining") } // 没有内存 Cell 时从持久化恢复,支持 lease 过期后的新节点接管。 roomMeta, exists, err := s.repository.GetRoomMeta(ctx, roomID) if err != nil { - return nil, err + return nil, router.Lease{}, err } if !exists { // 没有 meta 说明房间从未创建,不能凭请求临时造状态。 - return nil, xerr.New(xerr.NotFound, "room not found") + return nil, router.Lease{}, xerr.New(xerr.NotFound, "room not found") } restoredState, err := s.recoverRoom(ctx, roomMeta) if err != nil { // 恢复失败时返回 unavailable,调用方应重试或等待节点修复,而不是返回 room not found。 - return nil, xerr.New(xerr.Unavailable, fmt.Sprintf("recover room failed: %v", err)) + return nil, router.Lease{}, xerr.New(xerr.Unavailable, fmt.Sprintf("recover room failed: %v", err)) } // 恢复完成后创建新的 Room Cell,并从恢复后的 GiftRank 重建 LocalRank 索引。 roomCell := cell.New(restoredState, rank.FromState(restoredState.GiftRank, s.rankLimit)) s.installCell(ctx, roomID, roomCell) - return roomCell, nil + return roomCell, lease, nil } // recoverRoom 按“最新快照 + 之后的可回放命令”重建 Room Cell 状态。 @@ -152,6 +157,13 @@ func replay(current *state.RoomState, cmd command.Command) error { current.ClearMicSession(index) } current.Version++ + case *command.CloseRoom: + current.Status = state.RoomStatusClosed + current.OnlineUsers = map[int64]*state.RoomUserState{} + for index := range current.MicSeats { + current.ClearMicSession(index) + } + current.Version++ case *command.MicUp: index := current.SeatIndex(typed.SeatNo) if index < 0 { diff --git a/services/room-service/internal/room/service/repository.go b/services/room-service/internal/room/service/repository.go index f983d495..5ccaa9fe 100644 --- a/services/room-service/internal/room/service/repository.go +++ b/services/room-service/internal/room/service/repository.go @@ -46,10 +46,24 @@ type CommandRecord struct { Payload []byte // Replayable 标记该命令是否参与恢复回放。 Replayable bool + // OwnerNodeID 是提交命令时持有房间 lease 的 room-service 节点。 + OwnerNodeID string + // LeaseToken 是提交命令前通过 Redis fencing 校验的 lease token。 + LeaseToken string // CreatedAt 是命令成功落盘时间。 CreatedAt time.Time } +// MutationCommit 表达一次 Room Cell 命令需要一起提交的持久化副作用。 +type MutationCommit struct { + // Command 是本次命令日志,所有成功命令都必须写入。 + Command CommandRecord + // OutboxRecords 是本次命令产生的房间外事件。 + OutboxRecords []outbox.Record + // RoomStatus 非空时同步更新 rooms 和 room_list_entries 的生命周期状态。 + RoomStatus string +} + // SnapshotRecord 对应 room_snapshots 中的一条最新快照。 type SnapshotRecord struct { // AppCode 是快照所属 App,恢复时必须和房间 meta 保持一致。 @@ -136,6 +150,8 @@ type Repository interface { GetCommand(ctx context.Context, roomID string, commandID string) (CommandRecord, bool, error) // SaveCommand 追加成功命令日志,关键命令恢复必须依赖它。 SaveCommand(ctx context.Context, record CommandRecord) error + // SaveMutation 在同一事务中提交命令日志、outbox 事件和可选房间生命周期状态。 + SaveMutation(ctx context.Context, commit MutationCommit) error // ListCommandsAfter 读取快照版本之后的命令,恢复时按版本顺序回放。 ListCommandsAfter(ctx context.Context, roomID string, roomVersion int64) ([]CommandRecord, error) // SaveSnapshot 保存最新房间快照,允许覆盖较低版本号快照但不能倒退。 @@ -146,9 +162,11 @@ type Repository interface { SaveOutbox(ctx context.Context, records []outbox.Record) error // ListPendingOutbox 扫描待补偿投递事件。 ListPendingOutbox(ctx context.Context, limit int) ([]outbox.Record, error) - // MarkOutboxPublished 标记事件已经投递成功。 - MarkOutboxPublished(ctx context.Context, eventID string) error - // MarkOutboxFailed 记录一次投递失败并保留 pending 状态等待重试。 + // ClaimPendingOutbox 抢占一批待投递事件,避免多 worker 同时投递同一批。 + ClaimPendingOutbox(ctx context.Context, workerID string, limit int, lockUntil time.Time) ([]outbox.Record, error) + // MarkOutboxDelivered 标记事件已经投递成功。 + MarkOutboxDelivered(ctx context.Context, eventID string) error + // MarkOutboxFailed 记录一次投递失败并转为 retryable 状态等待重试。 MarkOutboxFailed(ctx context.Context, eventID string, lastErr string) error // UpsertRoomListEntry 写入或更新房间列表读模型;失败不应破坏 Room Cell 已提交状态。 UpsertRoomListEntry(ctx context.Context, entry RoomListEntry) error diff --git a/services/room-service/internal/room/service/service.go b/services/room-service/internal/room/service/service.go index 36197a7a..7845200c 100644 --- a/services/room-service/internal/room/service/service.go +++ b/services/room-service/internal/room/service/service.go @@ -4,6 +4,7 @@ package service import ( "errors" "sync" + "sync/atomic" "time" roomv1 "hyapp.local/api/proto/room/v1" @@ -58,6 +59,8 @@ type Service struct { syncPublisher integration.RoomEventPublisher // outboxPublisher 是补偿 worker 对外部消费者的异步投递抽象。 outboxPublisher integration.OutboxPublisher + // draining 表示当前节点正在下线,只允许已经进入执行链路的命令收尾。 + draining atomic.Bool // mu 保护本进程内 room_id -> RoomCell 注册表。 mu sync.Mutex @@ -89,6 +92,8 @@ type mutationResult struct { commandPayload []byte // syncEvent 是需要同步推给腾讯云 IM 的低时延房间系统事件。 syncEvent *tencentim.RoomEvent + // roomStatus 非空时代表命令提交时需要同步更新 rooms 和列表投影生命周期状态。 + roomStatus string } // New 初始化 room-service 领域服务。 @@ -161,3 +166,15 @@ func (s *Service) HealthCheck() error { return nil } + +// MarkDraining 让领域服务停止接收新的 Room Cell 命令和新 lease 接管。 +func (s *Service) MarkDraining() { + if s == nil { + return + } + s.draining.Store(true) +} + +func (s *Service) isDraining() bool { + return s != nil && s.draining.Load() +} diff --git a/services/room-service/internal/room/service/service_test.go b/services/room-service/internal/room/service/service_test.go index a4d5fa9d..98ae9d4c 100644 --- a/services/room-service/internal/room/service/service_test.go +++ b/services/room-service/internal/room/service/service_test.go @@ -11,6 +11,7 @@ import ( roomeventsv1 "hyapp.local/api/proto/events/room/v1" roomv1 "hyapp.local/api/proto/room/v1" walletv1 "hyapp.local/api/proto/wallet/v1" + "hyapp/pkg/appcode" "hyapp/pkg/tencentim" "hyapp/pkg/xerr" "hyapp/services/room-service/internal/room/outbox" @@ -36,6 +37,24 @@ func (fakeWallet) DebitGift(_ context.Context, req *walletv1.DebitGiftRequest) ( }, nil } +type takeoverWallet struct { + roomID string + directory *router.MemoryDirectory + takeoverSvc *roomservice.Service +} + +func (w takeoverWallet) DebitGift(ctx context.Context, req *walletv1.DebitGiftRequest) (*walletv1.DebitGiftResponse, error) { + w.directory.ForceExpire(roomRouteKeyForTest(w.roomID)) + if _, err := w.takeoverSvc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(w.roomID, 3)}); err != nil { + return nil, err + } + return fakeWallet{}.DebitGift(ctx, req) +} + +func roomRouteKeyForTest(roomID string) string { + return appcode.Default + "\x00" + roomID +} + // fakeSyncPublisher 记录 room-service 同步推给腾讯云 IM 的房间事件。 type fakeSyncPublisher struct { // fail 为 true 时模拟腾讯云 IM PublishRoomEvent 失败。 @@ -152,6 +171,34 @@ func TestCreateRoomDefaultsOwnerAndHostFromActor(t *testing.T) { } } +func TestRoomRouteKeyAlwaysIncludesDefaultAppCode(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + directory := router.NewMemoryDirectory() + svc := newRoomService("node-a", 1, directory, repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}) + roomID := "room-route-default-app" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ + Meta: roomservice.NewRequestMeta(roomID, 1), + SeatCount: 4, + Mode: "social", + RoomName: "Route Room", + }); err != nil { + t.Fatalf("CreateRoom failed: %v", err) + } + + if _, exists, err := directory.Lookup(ctx, roomID); err != nil || exists { + t.Fatalf("raw room_id route key must not exist: exists=%v err=%v", exists, err) + } + lease, exists, err := directory.Lookup(ctx, roomRouteKeyForTest(roomID)) + if err != nil || !exists { + t.Fatalf("app-scoped route key should exist: exists=%v err=%v", exists, err) + } + if lease.NodeID != "node-a" { + t.Fatalf("route owner mismatch: %+v", lease) + } +} + func TestCreateRoomRejectsSecondRoomForSameOwner(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) @@ -569,6 +616,38 @@ func TestMicPublishingConfirmAndStaleEvents(t *testing.T) { } } +func TestAudienceCanChangeOwnMicSeat(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + svc := newRoomService("node-a", 1, router.NewMemoryDirectory(), repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}) + roomID := "room-self-change-mic" + + 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) + } + if _, err := svc.MicUp(ctx, &roomv1.MicUpRequest{Meta: roomservice.NewRequestMeta(roomID, 2), SeatNo: 1}); err != nil { + t.Fatalf("MicUp user2 failed: %v", err) + } + + changeResp, err := svc.ChangeMicSeat(ctx, &roomv1.ChangeMicSeatRequest{ + Meta: roomservice.NewRequestMeta(roomID, 2), + TargetUserId: 2, + SeatNo: 3, + }) + if err != nil { + t.Fatalf("audience should be able to change own mic seat: %v", err) + } + if from := findSeat(changeResp.GetRoom(), 1); from == nil || from.GetUserId() != 0 { + t.Fatalf("source seat should be empty after switch: %+v", from) + } + if to := findSeat(changeResp.GetRoom(), 3); to == nil || to.GetUserId() != 2 { + t.Fatalf("target seat should contain user2 after switch: %+v", to) + } +} + func TestApplyRTCEventConfirmsAudioAndClearsOnStopOrExit(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) @@ -648,6 +727,65 @@ func TestApplyRTCEventConfirmsAudioAndClearsOnStopOrExit(t *testing.T) { } } +func TestOldRTCRoomExitedDoesNotClearRejoinedUserOrNewMicSession(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-rtc-exit-replay" + + 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) + } + oldMic, err := svc.MicUp(ctx, &roomv1.MicUpRequest{Meta: roomservice.NewRequestMeta(roomID, 2), SeatNo: 1}) + if err != nil { + t.Fatalf("first MicUp failed: %v", err) + } + oldExitEventTime := usedClock.now.Add(time.Second).UnixMilli() + + usedClock.now = usedClock.now.Add(2 * time.Second) + if _, err := svc.LeaveRoom(ctx, &roomv1.LeaveRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("LeaveRoom failed: %v", err) + } + + usedClock.now = usedClock.now.Add(2 * time.Second) + if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("rejoin user2 failed: %v", err) + } + newMic, err := svc.MicUp(ctx, &roomv1.MicUpRequest{Meta: roomservice.NewRequestMeta(roomID, 2), SeatNo: 2}) + if err != nil { + t.Fatalf("second MicUp failed: %v", err) + } + if newMic.GetMicSessionId() == oldMic.GetMicSessionId() { + t.Fatalf("rejoined MicUp must create new session: old=%s new=%s", oldMic.GetMicSessionId(), newMic.GetMicSessionId()) + } + + exitResp, err := svc.ApplyRTCEvent(ctx, &roomv1.ApplyRTCEventRequest{ + Meta: roomservice.NewRequestMeta(roomID, 2), + TargetUserId: 2, + EventType: "room_exited", + EventTimeMs: oldExitEventTime, + Reason: "rtc_room_exited:old", + Source: "tencent_rtc_callback", + ExternalEventId: "rtc_evt_old_exit", + }) + if err != nil { + t.Fatalf("old room_exited should be ignored without error: %v", err) + } + if exitResp.GetResult().GetApplied() { + t.Fatalf("old room_exited should be a no-op: %+v", exitResp.GetResult()) + } + if user := findRoomUser(exitResp.GetRoom(), 2); user == nil { + t.Fatalf("old room_exited must not remove rejoined user") + } + if seat := findSeat(exitResp.GetRoom(), 2); seat == nil || seat.GetUserId() != 2 || seat.GetMicSessionId() != newMic.GetMicSessionId() { + t.Fatalf("old room_exited must not clear new mic session: seat=%+v new=%+v old=%+v", seat, newMic, oldMic) + } +} + func TestMicPublishTimeoutMicDownsPendingSession(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) @@ -667,6 +805,9 @@ func TestMicPublishTimeoutMicDownsPendingSession(t *testing.T) { t.Fatalf("MicUp failed: %v", err) } usedClock.now = time.UnixMilli(micResp.GetPublishDeadlineMs()) + if _, err := svc.RoomHeartbeat(ctx, &roomv1.RoomHeartbeatRequest{Meta: roomservice.NewRequestMeta(roomID, 1)}); err != nil { + t.Fatalf("RoomHeartbeat owner before mic timeout sweep failed: %v", err) + } if err := svc.SweepMicPublishTimeouts(ctx); err != nil { t.Fatalf("SweepMicPublishTimeouts failed: %v", err) } @@ -874,6 +1015,64 @@ func TestJoinRoomRejectsClosedRoom(t *testing.T) { } } +func TestCloseRoomClearsPresenceSeatsAndBlocksEntry(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + syncPublisher := &fakeSyncPublisher{} + svc := newRoomService("node-a", 1, router.NewMemoryDirectory(), repository, syncPublisher, &fakeOutboxPublisher{}) + roomID := "room-close-command" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 1), SeatCount: 4, Mode: "social", RoomName: "Close Room"}); err != nil { + t.Fatalf("CreateRoom failed: %v", err) + } + if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("JoinRoom failed: %v", err) + } + if _, err := svc.MicUp(ctx, &roomv1.MicUpRequest{Meta: roomservice.NewRequestMeta(roomID, 2), SeatNo: 1}); err != nil { + t.Fatalf("MicUp failed: %v", err) + } + + closeResp, err := svc.CloseRoom(ctx, &roomv1.CloseRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 1), Reason: "owner_closed"}) + if err != nil { + t.Fatalf("CloseRoom failed: %v", err) + } + if closeResp.GetRoom().GetStatus() != "closed" || len(closeResp.GetRoom().GetOnlineUsers()) != 0 { + t.Fatalf("closed room should clear presence: %+v", closeResp.GetRoom()) + } + if seat := findSeat(closeResp.GetRoom(), 1); seat == nil || seat.GetUserId() != 0 || seat.GetMicSessionId() != "" { + t.Fatalf("closed room should release seats: %+v", seat) + } + meta, exists, err := repository.GetRoomMeta(ctx, roomID) + if err != nil || !exists || meta.Status != "closed" { + t.Fatalf("room meta should be closed: exists=%v meta=%+v err=%v", exists, meta, err) + } + if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 3)}); !xerr.IsCode(err, xerr.RoomClosed) { + t.Fatalf("closed room should reject JoinRoom, got %v", err) + } + if !hasSyncEventType(syncPublisher.events, "room_closed") { + t.Fatalf("CloseRoom should publish room_closed event: %+v", syncPublisher.events) + } +} + +func TestDrainingRejectsNewRoomCommands(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + svc := newRoomService("node-a", 1, router.NewMemoryDirectory(), repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}) + roomID := "room-draining" + + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 1), SeatCount: 4, Mode: "social", RoomName: "Drain Room"}); err != nil { + t.Fatalf("CreateRoom failed: %v", err) + } + svc.MarkDraining() + + if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); !xerr.IsCode(err, xerr.Unavailable) { + t.Fatalf("draining service should reject new JoinRoom, got %v", err) + } + if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{Meta: roomservice.NewRequestMeta("room-draining-new", 3), SeatCount: 4, Mode: "social", RoomName: "New Room"}); !xerr.IsCode(err, xerr.Unavailable) { + t.Fatalf("draining service should reject new CreateRoom, got %v", err) + } +} + func TestCommandIDPayloadConflictIgnoresTraceFields(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) @@ -945,7 +1144,7 @@ func TestRoomManagementRecoveryReplay(t *testing.T) { t.Fatalf("UnbanUser failed: %v", err) } - directory.ForceExpire(roomID) + directory.ForceExpire(roomRouteKeyForTest(roomID)) serviceB := newRoomService("node-b", 100, directory, repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}) joinResp, err := serviceB.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 4)}) if err != nil { @@ -1129,7 +1328,7 @@ func TestRoomRecoveryAfterLeaseTakeover(t *testing.T) { } // 强制过期模拟 node-a 故障后 Redis lease 失效。 - directory.ForceExpire(roomID) + directory.ForceExpire(roomRouteKeyForTest(roomID)) // node-b 收到命令时应先接管 lease,再恢复 Room Cell,而不是返回 room not found。 serviceB := newRoomService("node-b", 2, directory, repository, &fakeSyncPublisher{}, outboxPublisher) @@ -1150,7 +1349,7 @@ func TestRoomRecoveryAfterLeaseTakeover(t *testing.T) { t.Fatalf("recovered rank mismatch: %+v", joinResp.GetRoom().GetGiftRank()) } - lease, exists, err := directory.Lookup(ctx, roomID) + lease, exists, err := directory.Lookup(ctx, roomRouteKeyForTest(roomID)) if err != nil || !exists { t.Fatalf("Lookup failed: %v exists=%v", err, exists) } @@ -1160,6 +1359,51 @@ func TestRoomRecoveryAfterLeaseTakeover(t *testing.T) { } } +func TestLeaseFencingRejectsOldOwnerAfterSlowWalletCommand(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + directory := router.NewMemoryDirectory() + syncPublisherA := &fakeSyncPublisher{} + outboxPublisher := &fakeOutboxPublisher{} + serviceB := newRoomService("node-b", 1, directory, repository, &fakeSyncPublisher{}, outboxPublisher) + serviceA := roomservice.New(roomservice.Config{ + NodeID: "node-a", + LeaseTTL: 10 * time.Second, + RankLimit: 20, + SnapshotEveryN: 1, + }, directory, repository, takeoverWallet{ + roomID: "room-lease-fencing", + directory: directory, + takeoverSvc: serviceB, + }, syncPublisherA, outboxPublisher) + + roomID := "room-lease-fencing" + if _, err := serviceA.CreateRoom(ctx, &roomv1.CreateRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 1), SeatCount: 4, Mode: "social", RoomName: "Fence Room"}); err != nil { + t.Fatalf("CreateRoom failed: %v", err) + } + if _, err := serviceA.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("JoinRoom failed: %v", err) + } + + _, err := serviceA.SendGift(ctx, &roomv1.SendGiftRequest{ + Meta: roomservice.NewRequestMeta(roomID, 2), + TargetUserId: 1, + GiftId: "rose", + GiftCount: 1, + }) + if !xerr.IsCode(err, xerr.Unavailable) { + t.Fatalf("old owner should fail fencing before room commit, got %v", err) + } + + joinResp, err := serviceB.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 4)}) + if err != nil { + t.Fatalf("new owner should keep serving room: %v", err) + } + if joinResp.GetRoom().GetHeat() != 0 { + t.Fatalf("fenced SendGift must not update room heat: %+v", joinResp.GetRoom()) + } +} + // TestGuardRecoveryReplaysCommandsAfterSnapshot 验证无内存 Cell 的守卫查询会补回快照后的 command log。 func TestGuardRecoveryReplaysCommandsAfterSnapshot(t *testing.T) { ctx := context.Background() @@ -1229,6 +1473,9 @@ func TestSweepStalePresenceRemovesUserAndReleasesSeat(t *testing.T) { } usedClock.now = usedClock.now.Add(40 * time.Second) + if _, err := svc.RoomHeartbeat(ctx, &roomv1.RoomHeartbeatRequest{Meta: roomservice.NewRequestMeta(roomID, 1)}); err != nil { + t.Fatalf("RoomHeartbeat owner before stale sweep failed: %v", err) + } if err := svc.SweepStalePresence(ctx); err != nil { t.Fatalf("SweepStalePresence failed: %v", err) } @@ -1253,6 +1500,78 @@ func TestSweepStalePresenceRemovesUserAndReleasesSeat(t *testing.T) { } } +func TestSweepStalePresenceSkipsRoomAfterLeaseTakeover(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + directory := router.NewMemoryDirectory() + usedClock := &mutableClock{now: time.UnixMilli(1_700_000_000_000)} + serviceA := newRoomServiceWithClock("node-a", 1, directory, repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}, usedClock, time.Minute) + serviceB := newRoomServiceWithClock("node-b", 1, directory, repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}, usedClock, time.Minute) + roomID := "room-stale-lease-takeover" + + if _, err := serviceA.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 := serviceA.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("JoinRoom user2 failed: %v", err) + } + + usedClock.now = usedClock.now.Add(2 * time.Minute) + directory.ForceExpire(roomRouteKeyForTest(roomID)) + if _, err := serviceB.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 3)}); err != nil { + t.Fatalf("JoinRoom takeover failed: %v", err) + } + if err := serviceA.SweepStalePresence(ctx); err != nil { + t.Fatalf("old owner stale sweep failed: %v", err) + } + + joinResp, err := serviceB.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 4)}) + if err != nil { + t.Fatalf("JoinRoom on current owner failed: %v", err) + } + if user := findRoomUser(joinResp.GetRoom(), 2); user == nil { + t.Fatalf("old owner stale sweep must not remove users after takeover: %+v", joinResp.GetRoom().GetOnlineUsers()) + } +} + +func TestSweepMicPublishTimeoutSkipsRoomAfterLeaseTakeover(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + directory := router.NewMemoryDirectory() + usedClock := &mutableClock{now: time.UnixMilli(1_700_000_000_000)} + serviceA := newRoomServiceWithClock("node-a", 1, directory, repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}, usedClock, time.Minute) + serviceB := newRoomServiceWithClock("node-b", 1, directory, repository, &fakeSyncPublisher{}, &fakeOutboxPublisher{}, usedClock, time.Minute) + roomID := "room-mic-timeout-lease-takeover" + + if _, err := serviceA.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 := serviceA.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 2)}); err != nil { + t.Fatalf("JoinRoom user2 failed: %v", err) + } + micResp, err := serviceA.MicUp(ctx, &roomv1.MicUpRequest{Meta: roomservice.NewRequestMeta(roomID, 2), SeatNo: 1}) + if err != nil { + t.Fatalf("MicUp failed: %v", err) + } + + usedClock.now = time.UnixMilli(micResp.GetPublishDeadlineMs()) + directory.ForceExpire(roomRouteKeyForTest(roomID)) + if _, err := serviceB.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 3)}); err != nil { + t.Fatalf("JoinRoom takeover failed: %v", err) + } + if err := serviceA.SweepMicPublishTimeouts(ctx); err != nil { + t.Fatalf("old owner mic timeout sweep failed: %v", err) + } + + joinResp, err := serviceB.JoinRoom(ctx, &roomv1.JoinRoomRequest{Meta: roomservice.NewRequestMeta(roomID, 4)}) + if err != nil { + t.Fatalf("JoinRoom on current owner failed: %v", err) + } + if seat := findSeat(joinResp.GetRoom(), 1); seat == nil || seat.GetUserId() != 2 || seat.GetMicSessionId() != micResp.GetMicSessionId() || seat.GetPublishState() != "pending_publish" { + t.Fatalf("old owner mic timeout sweep must not clear current owner's seat: seat=%+v mic=%+v", seat, micResp) + } +} + // TestRoomOutboxCompensationWhenSyncPublishFails 验证同步广播失败不回滚房间状态,outbox 可补偿。 func TestRoomOutboxCompensationWhenSyncPublishFails(t *testing.T) { ctx := context.Background() @@ -1311,11 +1630,11 @@ func TestRoomOutboxCompensationWhenSyncPublishFails(t *testing.T) { if remaining, err := repository.ListPendingOutbox(ctx, 100); err != nil { t.Fatalf("ListPendingOutbox after compensation failed: %v", err) } else if len(remaining) != 0 { - t.Fatalf("expected all pending outbox records to be marked published, got %d", len(remaining)) + t.Fatalf("expected all pending outbox records to be marked delivered, got %d", len(remaining)) } } -func TestOutboxWorkerRetriesFailedPublishAndLaterMarksPublished(t *testing.T) { +func TestOutboxWorkerRetriesFailedPublishAndLaterMarksDelivered(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) outboxPublisher := &fakeOutboxPublisher{failCount: 1, err: errors.New("temporary im failure")} @@ -1343,28 +1662,73 @@ func TestOutboxWorkerRetriesFailedPublishAndLaterMarksPublished(t *testing.T) { if !exists { t.Fatalf("outbox record missing after failure") } - if failed.Status != outbox.StatusPending || failed.RetryCount != 1 || !strings.Contains(failed.LastError, "temporary im failure") { - t.Fatalf("failed publish should remain pending with retry metadata: %+v", failed) + if failed.Status != outbox.StatusRetryable || failed.RetryCount != 1 || !strings.Contains(failed.LastError, "temporary im failure") { + t.Fatalf("failed publish should become retryable with retry metadata: %+v", failed) } if err := svc.ProcessPendingOutbox(ctx, options); err != nil { t.Fatalf("second ProcessPendingOutbox failed: %v", err) } - published, exists := repository.OutboxRecord(record.EventID) + delivered, exists := repository.OutboxRecord(record.EventID) if !exists { t.Fatalf("outbox record missing after success") } - if published.Status != outbox.StatusPublished || published.LastError != "" || len(outboxPublisher.envelopes) != 1 { - t.Fatalf("second publish should mark record published: record=%+v envelopes=%d", published, len(outboxPublisher.envelopes)) + if delivered.Status != outbox.StatusDelivered || delivered.LastError != "" || len(outboxPublisher.envelopes) != 1 { + t.Fatalf("second publish should mark record delivered: record=%+v envelopes=%d", delivered, len(outboxPublisher.envelopes)) } } -func TestSyncPublishSuccessMarksOutboxPublished(t *testing.T) { +func TestOutboxClaimPreventsDuplicateWorkersAndRetriesAfterFailure(t *testing.T) { + ctx := context.Background() + repository := mysqltest.NewRepository(t) + + record, err := outbox.Build("room-claim", "RoomGiftSent", 1, time.Now(), &roomeventsv1.RoomGiftSent{ + SenderUserId: 1, + TargetUserId: 2, + GiftId: "rose", + GiftCount: 1, + GiftValue: 10, + }) + if err != nil { + t.Fatalf("Build outbox failed: %v", err) + } + if err := repository.SaveOutbox(ctx, []outbox.Record{record}); err != nil { + t.Fatalf("SaveOutbox failed: %v", err) + } + + claimedA, err := repository.ClaimPendingOutbox(ctx, "worker-a", 10, time.Now().Add(time.Minute)) + if err != nil { + t.Fatalf("worker-a claim failed: %v", err) + } + if len(claimedA) != 1 || claimedA[0].Status != outbox.StatusDelivering || claimedA[0].WorkerID != "worker-a" { + t.Fatalf("worker-a should claim one delivering record: %+v", claimedA) + } + claimedB, err := repository.ClaimPendingOutbox(ctx, "worker-b", 10, time.Now().Add(time.Minute)) + if err != nil { + t.Fatalf("worker-b claim failed: %v", err) + } + if len(claimedB) != 0 { + t.Fatalf("worker-b should not claim worker-a locked record: %+v", claimedB) + } + + if err := repository.MarkOutboxFailed(ctx, record.EventID, "temporary failure"); err != nil { + t.Fatalf("MarkOutboxFailed failed: %v", err) + } + claimedRetry, err := repository.ClaimPendingOutbox(ctx, "worker-b", 10, time.Now().Add(time.Minute)) + if err != nil { + t.Fatalf("retry claim failed: %v", err) + } + if len(claimedRetry) != 1 || claimedRetry[0].Status != outbox.StatusDelivering || claimedRetry[0].RetryCount != 1 { + t.Fatalf("retryable record should be claimable again: %+v", claimedRetry) + } +} + +func TestSyncPublishSuccessMarksOutboxDelivered(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) syncPublisher := &fakeSyncPublisher{} svc := newRoomService("node-a", 1, router.NewMemoryDirectory(), repository, syncPublisher, &fakeOutboxPublisher{}) - roomID := "room-sync-published" + roomID := "room-sync-delivered" if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ Meta: roomservice.NewRequestMeta(roomID, 1), @@ -1388,8 +1752,8 @@ func TestSyncPublishSuccessMarksOutboxPublished(t *testing.T) { if !exists { t.Fatalf("sync event outbox record missing: %s", eventID) } - if record.Status != outbox.StatusPublished { - t.Fatalf("sync success should best-effort mark outbox published: %+v", record) + if record.Status != outbox.StatusDelivered { + t.Fatalf("sync success should best-effort mark outbox delivered: %+v", record) } } @@ -1472,3 +1836,13 @@ func hasSyncEventReason(events []tencentim.RoomEvent, reason string) bool { return false } + +func hasSyncEventType(events []tencentim.RoomEvent, eventType string) bool { + for _, event := range events { + if event.EventType == eventType { + return true + } + } + + return false +} diff --git a/services/room-service/internal/room/service/snapshot.go b/services/room-service/internal/room/service/snapshot.go index 520363b2..fd2967a9 100644 --- a/services/room-service/internal/room/service/snapshot.go +++ b/services/room-service/internal/room/service/snapshot.go @@ -33,6 +33,10 @@ func (s *Service) currentSnapshot(ctx context.Context, roomID string) (*roomv1.R // 恢复失败说明持久化状态不可用,不能让外部 IM 入口自行放行。 return nil, err } + if s.isDraining() { + // 下线期间守卫查询可以读取恢复后的快照,但不能再创建新的本地 Room Cell。 + return snapshotWithApp(ctx, restoredState.ToProto()), nil + } roomCell := cell.New(restoredState, rank.FromState(restoredState.GiftRank, s.rankLimit)) s.installCell(ctx, roomID, roomCell) diff --git a/services/room-service/internal/room/state/state.go b/services/room-service/internal/room/state/state.go index 012ef4f4..bd7fda5c 100644 --- a/services/room-service/internal/room/state/state.go +++ b/services/room-service/internal/room/state/state.go @@ -8,6 +8,15 @@ import ( ) const ( + // RoomStatusCreating 表示房间正在创建外部依赖,尚未对客户端开放。 + RoomStatusCreating = "creating" + // RoomStatusActive 表示房间可进入、可管理、可发麦位和礼物命令。 + RoomStatusActive = "active" + // RoomStatusClosing 表示房间正在收尾,不再接受新业务命令。 + RoomStatusClosing = "closing" + // RoomStatusClosed 表示房间已经关闭,guard 和进房都必须拒绝。 + RoomStatusClosed = "closed" + // MicPublishIdle 表示麦位没有正在确认或已确认的 RTC 发流会话。 MicPublishIdle = "idle" // MicPublishPending 表示业务上麦成功,但客户端/RTC 尚未确认音频发布成功。 @@ -109,7 +118,7 @@ func NewRoomState(roomID string, ownerUserID int64, hostUserID int64, seatCount OwnerUserID: ownerUserID, HostUserID: hostUserID, Mode: mode, - Status: "active", + Status: RoomStatusActive, ChatEnabled: true, MicSeats: seats, OnlineUsers: make(map[int64]*RoomUserState), diff --git a/services/room-service/internal/router/directory.go b/services/room-service/internal/router/directory.go index 22064a1d..5832df37 100644 --- a/services/room-service/internal/router/directory.go +++ b/services/room-service/internal/router/directory.go @@ -33,6 +33,8 @@ type Directory interface { Lookup(ctx context.Context, roomID string) (Lease, bool, error) // EnsureOwner 在无 owner、owner 过期或 owner 是当前节点时授予当前节点执行权。 EnsureOwner(ctx context.Context, roomID string, nodeID string, now time.Time, ttl time.Duration) (Lease, error) + // VerifyOwner 校验当前节点和 lease token 仍然持有执行权,不续租也不接管。 + VerifyOwner(ctx context.Context, roomID string, nodeID string, leaseToken string, now time.Time) (bool, error) // ForceExpire 只用于测试模拟租约过期。 ForceExpire(roomID string) } @@ -87,6 +89,19 @@ func (d *MemoryDirectory) EnsureOwner(_ context.Context, roomID string, nodeID s return next, nil } +// VerifyOwner 校验调用方手里的 lease token 仍是当前有效 owner。 +func (d *MemoryDirectory) VerifyOwner(_ context.Context, roomID string, nodeID string, leaseToken string, now time.Time) (bool, error) { + d.mu.Lock() + defer d.mu.Unlock() + + current, ok := d.leases[roomID] + if !ok { + return false, nil + } + + return current.NodeID == nodeID && current.LeaseToken == leaseToken && current.ValidAt(now), nil +} + // ForceExpire 只用于测试时模拟租约自然过期。 func (d *MemoryDirectory) ForceExpire(roomID string) { d.mu.Lock() diff --git a/services/room-service/internal/router/redis_directory.go b/services/room-service/internal/router/redis_directory.go index 348035d4..279914fa 100644 --- a/services/room-service/internal/router/redis_directory.go +++ b/services/room-service/internal/router/redis_directory.go @@ -38,6 +38,24 @@ end return current ` +const verifyOwnerScript = ` +local current = redis.call("GET", KEYS[1]) +if not current then + return 0 +end + +local ok, decoded = pcall(cjson.decode, current) +if not ok then + return 0 +end + +if decoded["node_id"] == ARGV[2] and decoded["lease_token"] == ARGV[3] and tonumber(decoded["expires_at_ms"]) > tonumber(ARGV[1]) then + return 1 +end + +return 0 +` + // RedisDirectory 用 Redis 保存 room_id 到执行节点的带 TTL 租约。 type RedisDirectory struct { // client 是 go-redis 客户端,连接生命周期由 app.App 关闭。 @@ -172,6 +190,22 @@ func (d *RedisDirectory) EnsureOwner(ctx context.Context, roomID string, nodeID return lease, nil } +// VerifyOwner 校验调用方持有的 lease token 仍是当前有效 owner。 +func (d *RedisDirectory) VerifyOwner(ctx context.Context, roomID string, nodeID string, leaseToken string, now time.Time) (bool, error) { + value, err := d.client.Eval(ctx, + verifyOwnerScript, + []string{routeKey(roomID)}, + strconv.FormatInt(now.UnixMilli(), 10), + nodeID, + leaseToken, + ).Int() + if err != nil { + return false, err + } + + return value == 1, nil +} + // ForceExpire 只服务测试,生产启动路径不会调用。 func (d *RedisDirectory) ForceExpire(roomID string) { // Redis 实现直接删除 key 来模拟 lease 过期,避免等待真实 TTL。 diff --git a/services/room-service/internal/storage/mysql/repository.go b/services/room-service/internal/storage/mysql/repository.go index d1de7441..36c31230 100644 --- a/services/room-service/internal/storage/mysql/repository.go +++ b/services/room-service/internal/storage/mysql/repository.go @@ -70,7 +70,7 @@ func (r *Repository) Migrate(ctx context.Context) error { // 这里保持与 deploy/mysql/initdb 的表结构一致,服务本地启动可自动建表。 statements := []string{ `CREATE TABLE IF NOT EXISTS rooms ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, room_id VARCHAR(64) NOT NULL, room_short_id VARCHAR(32) NOT NULL DEFAULT '', owner_user_id BIGINT NOT NULL, @@ -87,7 +87,7 @@ func (r *Repository) Migrate(ctx context.Context) error { KEY idx_rooms_region_status (app_code, visible_region_id, status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`, `CREATE TABLE IF NOT EXISTS room_list_entries ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, room_id VARCHAR(64) NOT NULL, room_short_id VARCHAR(32) NOT NULL DEFAULT '', visible_region_id BIGINT NOT NULL DEFAULT 0, @@ -111,7 +111,7 @@ func (r *Repository) Migrate(ctx context.Context) error { KEY idx_room_list_owner (app_code, owner_user_id, updated_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`, `CREATE TABLE IF NOT EXISTS room_snapshots ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, room_id VARCHAR(64) NOT NULL, room_version BIGINT NOT NULL, payload LONGBLOB NOT NULL, @@ -121,12 +121,14 @@ func (r *Repository) Migrate(ctx context.Context) error { INDEX idx_room_snapshots_version (app_code, room_id, room_version) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`, `CREATE TABLE IF NOT EXISTS room_command_log ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, room_id VARCHAR(64) NOT NULL, room_version BIGINT NOT NULL, command_id VARCHAR(128) NOT NULL, command_type VARCHAR(64) NOT NULL, + owner_node_id VARCHAR(128) NOT NULL DEFAULT '', + lease_token VARCHAR(128) NOT NULL DEFAULT '', payload LONGBLOB NOT NULL, replayable BOOLEAN NOT NULL, created_at TIMESTAMP(3) NOT NULL, @@ -134,19 +136,27 @@ func (r *Repository) Migrate(ctx context.Context) error { KEY idx_room_command_replay (app_code, room_id, room_version) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`, `CREATE TABLE IF NOT EXISTS room_outbox ( - app_code VARCHAR(32) NOT NULL DEFAULT 'lalu', + app_code VARCHAR(32) NOT NULL, event_id VARCHAR(128) NOT NULL, event_type VARCHAR(64) NOT NULL, room_id VARCHAR(64) NOT NULL, status VARCHAR(32) NOT NULL, + worker_id VARCHAR(128) NOT NULL DEFAULT '', + lock_until TIMESTAMP(3) NULL, envelope LONGBLOB NOT NULL, created_at TIMESTAMP(3) NOT NULL, retry_count INT NOT NULL DEFAULT 0, last_error TEXT NULL, updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (app_code, event_id), - KEY idx_room_outbox_pending (app_code, status, created_at) + KEY idx_room_outbox_pending (app_code, status, created_at), + KEY idx_room_outbox_claim (app_code, status, lock_until, created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`, + `ALTER TABLE rooms MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, + `ALTER TABLE room_list_entries MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, + `ALTER TABLE room_snapshots MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, + `ALTER TABLE room_command_log MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, + `ALTER TABLE room_outbox MODIFY COLUMN app_code VARCHAR(32) NOT NULL`, } for _, statement := range statements { @@ -232,7 +242,7 @@ func (r *Repository) GetRoomMetaByOwner(ctx context.Context, ownerUserID int64) func (r *Repository) GetCommand(ctx context.Context, roomID string, commandID string) (roomservice.CommandRecord, bool, error) { // 幂等检查只看 command log,只有成功提交过的命令才算 seen。 row := r.db.QueryRowContext(ctx, - `SELECT app_code, room_id, room_version, command_id, command_type, payload, replayable, created_at + `SELECT app_code, room_id, room_version, command_id, command_type, owner_node_id, lease_token, payload, replayable, created_at FROM room_command_log WHERE app_code = ? AND room_id = ? AND command_id = ? LIMIT 1`, @@ -242,7 +252,7 @@ func (r *Repository) GetCommand(ctx context.Context, roomID string, commandID st ) var record roomservice.CommandRecord - if err := row.Scan(&record.AppCode, &record.RoomID, &record.RoomVersion, &record.CommandID, &record.CommandType, &record.Payload, &record.Replayable, &record.CreatedAt); err != nil { + if err := row.Scan(&record.AppCode, &record.RoomID, &record.RoomVersion, &record.CommandID, &record.CommandType, &record.OwnerNodeID, &record.LeaseToken, &record.Payload, &record.Replayable, &record.CreatedAt); err != nil { if errors.Is(err, sql.ErrNoRows) { // 没有命令日志表示本命令尚未成功提交。 return roomservice.CommandRecord{}, false, nil @@ -259,14 +269,16 @@ func (r *Repository) SaveCommand(ctx context.Context, record roomservice.Command // ON DUPLICATE KEY 保证重复命令写入不会破坏已提交记录。 appCode := normalizedRecordAppCode(ctx, record.AppCode) _, err := r.db.ExecContext(ctx, - `INSERT INTO room_command_log (app_code, room_id, room_version, command_id, command_type, payload, replayable, created_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `INSERT INTO room_command_log (app_code, room_id, room_version, command_id, command_type, owner_node_id, lease_token, payload, replayable, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE command_id = command_id`, appCode, record.RoomID, record.RoomVersion, record.CommandID, record.CommandType, + record.OwnerNodeID, + record.LeaseToken, record.Payload, record.Replayable, record.CreatedAt, @@ -275,11 +287,96 @@ func (r *Repository) SaveCommand(ctx context.Context, record roomservice.Command return err } +// SaveMutation 在同一事务中提交命令日志、outbox 和可选房间状态。 +func (r *Repository) SaveMutation(ctx context.Context, commit roomservice.MutationCommit) error { + appCode := normalizedRecordAppCode(ctx, commit.Command.AppCode) + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return err + } + + if _, err := tx.ExecContext(ctx, + `INSERT INTO room_command_log (app_code, room_id, room_version, command_id, command_type, owner_node_id, lease_token, payload, replayable, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE command_id = command_id`, + appCode, + commit.Command.RoomID, + commit.Command.RoomVersion, + commit.Command.CommandID, + commit.Command.CommandType, + commit.Command.OwnerNodeID, + commit.Command.LeaseToken, + commit.Command.Payload, + commit.Command.Replayable, + commit.Command.CreatedAt, + ); err != nil { + _ = tx.Rollback() + return err + } + + for _, record := range commit.OutboxRecords { + record.AppCode = normalizedRecordAppCode(ctx, record.AppCode) + if record.Envelope != nil { + record.Envelope.AppCode = record.AppCode + } + envelopeBytes, err := proto.Marshal(record.Envelope) + if err != nil { + _ = tx.Rollback() + return err + } + if _, err := tx.ExecContext(ctx, + `INSERT INTO room_outbox (app_code, event_id, event_type, room_id, status, envelope, created_at, retry_count, last_error) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE event_id = event_id`, + record.AppCode, + record.EventID, + record.EventType, + record.RoomID, + record.Status, + envelopeBytes, + record.CreatedAt, + record.RetryCount, + nullableString(record.LastError), + ); err != nil { + _ = tx.Rollback() + return err + } + } + + if strings.TrimSpace(commit.RoomStatus) != "" { + if _, err := tx.ExecContext(ctx, + `UPDATE rooms + SET status = ? + WHERE app_code = ? AND room_id = ?`, + commit.RoomStatus, + appCode, + commit.Command.RoomID, + ); err != nil { + _ = tx.Rollback() + return err + } + if _, err := tx.ExecContext(ctx, + `UPDATE room_list_entries + SET status = ?, updated_at_ms = ? + WHERE app_code = ? AND room_id = ?`, + commit.RoomStatus, + commit.Command.CreatedAt.UnixMilli(), + appCode, + commit.Command.RoomID, + ); err != nil { + _ = tx.Rollback() + return err + } + } + + return tx.Commit() +} + // ListCommandsAfter 返回快照版本之后的可回放命令日志。 func (r *Repository) ListCommandsAfter(ctx context.Context, roomID string, roomVersion int64) ([]roomservice.CommandRecord, error) { // 恢复必须按 room_version 再按自增 id 排序,确保同版本异常数据也有稳定顺序。 rows, err := r.db.QueryContext(ctx, - `SELECT app_code, room_id, room_version, command_id, command_type, payload, replayable, created_at + `SELECT app_code, room_id, room_version, command_id, command_type, owner_node_id, lease_token, payload, replayable, created_at FROM room_command_log WHERE app_code = ? AND room_id = ? AND room_version > ? ORDER BY room_version ASC, id ASC`, @@ -296,7 +393,7 @@ func (r *Repository) ListCommandsAfter(ctx context.Context, roomID string, roomV for rows.Next() { // payload 保持原始字节,领域层根据 command_type 反序列化。 var record roomservice.CommandRecord - if err := rows.Scan(&record.AppCode, &record.RoomID, &record.RoomVersion, &record.CommandID, &record.CommandType, &record.Payload, &record.Replayable, &record.CreatedAt); err != nil { + if err := rows.Scan(&record.AppCode, &record.RoomID, &record.RoomVersion, &record.CommandID, &record.CommandType, &record.OwnerNodeID, &record.LeaseToken, &record.Payload, &record.Replayable, &record.CreatedAt); err != nil { return nil, err } @@ -414,12 +511,14 @@ func (r *Repository) ListPendingOutbox(ctx context.Context, limit int) ([]outbox // 按创建时间顺序扫描 pending,尽量保持事件投递顺序。 rows, err := r.db.QueryContext(ctx, - `SELECT app_code, event_id, event_type, room_id, status, envelope, created_at, retry_count, COALESCE(last_error, '') + `SELECT app_code, event_id, event_type, room_id, status, worker_id, lock_until, envelope, created_at, retry_count, COALESCE(last_error, '') FROM room_outbox - WHERE status = ? + WHERE app_code = ? AND status IN (?, ?) ORDER BY created_at ASC LIMIT ?`, + appcode.FromContext(ctx), outbox.StatusPending, + outbox.StatusRetryable, limit, ) if err != nil { @@ -432,9 +531,13 @@ func (r *Repository) ListPendingOutbox(ctx context.Context, limit int) ([]outbox // 每条 outbox 记录恢复 envelope,发布器只消费 protobuf 信封。 var envelopeBytes []byte var record outbox.Record - if err := rows.Scan(&record.AppCode, &record.EventID, &record.EventType, &record.RoomID, &record.Status, &envelopeBytes, &record.CreatedAt, &record.RetryCount, &record.LastError); err != nil { + var lockUntil sql.NullTime + if err := rows.Scan(&record.AppCode, &record.EventID, &record.EventType, &record.RoomID, &record.Status, &record.WorkerID, &lockUntil, &envelopeBytes, &record.CreatedAt, &record.RetryCount, &record.LastError); err != nil { return nil, err } + if lockUntil.Valid { + record.LockUntilMS = lockUntil.Time.UnixMilli() + } var envelope roomeventsv1.EventEnvelope if err := proto.Unmarshal(envelopeBytes, &envelope); err != nil { @@ -454,14 +557,118 @@ func (r *Repository) ListPendingOutbox(ctx context.Context, limit int) ([]outbox return records, nil } -// MarkOutboxPublished 标记事件投递成功。 -func (r *Repository) MarkOutboxPublished(ctx context.Context, eventID string) error { +// ClaimPendingOutbox 抢占一批待投递事件,避免多 worker 同时投递同一批。 +func (r *Repository) ClaimPendingOutbox(ctx context.Context, workerID string, limit int, lockUntil time.Time) ([]outbox.Record, error) { + if limit <= 0 { + limit = 100 + } + if strings.TrimSpace(workerID) == "" { + workerID = "room-outbox-worker" + } + + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + + now := time.Now().UTC() + rows, err := tx.QueryContext(ctx, + `SELECT app_code, event_id, event_type, room_id, status, worker_id, lock_until, envelope, created_at, retry_count, COALESCE(last_error, '') + FROM room_outbox + WHERE app_code = ? + AND ( + status IN (?, ?) + OR (status = ? AND lock_until IS NOT NULL AND lock_until <= ?) + ) + ORDER BY created_at ASC + LIMIT ? + FOR UPDATE SKIP LOCKED`, + appcode.FromContext(ctx), + outbox.StatusPending, + outbox.StatusRetryable, + outbox.StatusDelivering, + now, + limit, + ) + if err != nil { + _ = tx.Rollback() + return nil, err + } + + records := make([]outbox.Record, 0, limit) + eventIDs := make([]string, 0, limit) + for rows.Next() { + var envelopeBytes []byte + var record outbox.Record + var lockUntilValue sql.NullTime + if err := rows.Scan(&record.AppCode, &record.EventID, &record.EventType, &record.RoomID, &record.Status, &record.WorkerID, &lockUntilValue, &envelopeBytes, &record.CreatedAt, &record.RetryCount, &record.LastError); err != nil { + _ = rows.Close() + _ = tx.Rollback() + return nil, err + } + if lockUntilValue.Valid { + record.LockUntilMS = lockUntilValue.Time.UnixMilli() + } + + var envelope roomeventsv1.EventEnvelope + if err := proto.Unmarshal(envelopeBytes, &envelope); err != nil { + _ = rows.Close() + _ = tx.Rollback() + return nil, err + } + + record.Envelope = &envelope + record.Envelope.AppCode = normalizedRecordAppCode(ctx, record.AppCode) + records = append(records, record) + eventIDs = append(eventIDs, record.EventID) + } + if err := rows.Close(); err != nil { + _ = tx.Rollback() + return nil, err + } + if err := rows.Err(); err != nil { + _ = tx.Rollback() + return nil, err + } + + for _, eventID := range eventIDs { + if _, err := tx.ExecContext(ctx, + `UPDATE room_outbox + SET status = ?, worker_id = ?, lock_until = ? + WHERE app_code = ? AND event_id = ?`, + outbox.StatusDelivering, + workerID, + lockUntil, + appcode.FromContext(ctx), + eventID, + ); err != nil { + _ = tx.Rollback() + return nil, err + } + } + + if err := tx.Commit(); err != nil { + return nil, err + } + + for index := range records { + records[index].Status = outbox.StatusDelivering + records[index].WorkerID = workerID + records[index].LockUntilMS = lockUntil.UnixMilli() + } + + return records, nil +} + +// MarkOutboxDelivered 标记事件投递成功。 +func (r *Repository) MarkOutboxDelivered(ctx context.Context, eventID string) error { // 成功后清空 last_error,后续扫描不再返回该事件。 _, err := r.db.ExecContext(ctx, `UPDATE room_outbox - SET status = ?, last_error = NULL - WHERE event_id = ?`, - outbox.StatusPublished, + SET status = ?, worker_id = '', lock_until = NULL, last_error = NULL + WHERE app_code = ? AND event_id = ?`, + outbox.StatusDelivered, + appcode.FromContext(ctx), eventID, ) @@ -470,13 +677,14 @@ func (r *Repository) MarkOutboxPublished(ctx context.Context, eventID string) er // MarkOutboxFailed 标记事件投递失败并累计重试次数。 func (r *Repository) MarkOutboxFailed(ctx context.Context, eventID string, lastErr string) error { - // 失败仍保持 pending,worker 下一轮会继续扫描到该事件。 + // 失败转入 retryable,worker 下一轮可重新抢占。 _, err := r.db.ExecContext(ctx, `UPDATE room_outbox - SET status = ?, retry_count = retry_count + 1, last_error = ? - WHERE event_id = ?`, - outbox.StatusPending, + SET status = ?, worker_id = '', lock_until = NULL, retry_count = retry_count + 1, last_error = ? + WHERE app_code = ? AND event_id = ?`, + outbox.StatusRetryable, lastErr, + appcode.FromContext(ctx), eventID, ) diff --git a/services/room-service/internal/testutil/mysqltest/mysqltest.go b/services/room-service/internal/testutil/mysqltest/mysqltest.go index c5b117b9..b74f1833 100644 --- a/services/room-service/internal/testutil/mysqltest/mysqltest.go +++ b/services/room-service/internal/testutil/mysqltest/mysqltest.go @@ -63,24 +63,28 @@ func (r *Repository) SetRoomStatus(roomID string, status string) { } } -// OutboxRecord reads one outbox row, including published rows that normal scans skip. +// OutboxRecord reads one outbox row, including delivered rows that normal scans skip. func (r *Repository) OutboxRecord(eventID string) (outbox.Record, bool) { r.t.Helper() row := r.schema.DB.QueryRowContext(context.Background(), ` - SELECT app_code, event_id, event_type, room_id, status, envelope, created_at, retry_count, COALESCE(last_error, '') + SELECT app_code, event_id, event_type, room_id, status, worker_id, lock_until, envelope, created_at, retry_count, COALESCE(last_error, '') FROM room_outbox WHERE app_code = ? AND event_id = ? `, appcode.Default, eventID) var envelopeBytes []byte var record outbox.Record - if err := row.Scan(&record.AppCode, &record.EventID, &record.EventType, &record.RoomID, &record.Status, &envelopeBytes, &record.CreatedAt, &record.RetryCount, &record.LastError); err != nil { + var lockUntil sql.NullTime + if err := row.Scan(&record.AppCode, &record.EventID, &record.EventType, &record.RoomID, &record.Status, &record.WorkerID, &lockUntil, &envelopeBytes, &record.CreatedAt, &record.RetryCount, &record.LastError); err != nil { if err == sql.ErrNoRows { return outbox.Record{}, false } r.t.Fatalf("query room outbox record failed: %v", err) } + if lockUntil.Valid { + record.LockUntilMS = lockUntil.Time.UnixMilli() + } var envelope roomeventsv1.EventEnvelope if err := proto.Unmarshal(envelopeBytes, &envelope); err != nil { diff --git a/services/room-service/internal/transport/grpc/server.go b/services/room-service/internal/transport/grpc/server.go index d983957e..998ceba1 100644 --- a/services/room-service/internal/transport/grpc/server.go +++ b/services/room-service/internal/transport/grpc/server.go @@ -68,6 +68,13 @@ func (s *Server) LeaveRoom(ctx context.Context, req *roomv1.LeaveRoomRequest) (* return mapServiceResult(s.svc.LeaveRoom(ctx, req)) } +// CloseRoom 代理到领域服务。 +func (s *Server) CloseRoom(ctx context.Context, req *roomv1.CloseRoomRequest) (*roomv1.CloseRoomResponse, error) { + // CloseRoom 统一关闭房间生命周期、清理 presence/麦位并写出系统事件。 + ctx = contextWithMetaApp(ctx, req.GetMeta()) + return mapServiceResult(s.svc.CloseRoom(ctx, req)) +} + // MicUp 代理到领域服务。 func (s *Server) MicUp(ctx context.Context, req *roomv1.MicUpRequest) (*roomv1.MicUpResponse, error) { // 麦位修改由 Room Cell 串行执行,gRPC 层不做状态判断。