Merge branch 'test'
This commit is contained in:
commit
c53b710539
File diff suppressed because it is too large
Load Diff
@ -526,6 +526,8 @@ message RoomSnapshot {
|
||||
RoomRocketState rocket = 20;
|
||||
// ban_states 保存 ban 的过期边界;ban_user_ids 仍只服务简单集合判断。
|
||||
repeated RoomBanState ban_states = 21;
|
||||
// online_count 允许 lite 响应不携带 online_users 明细仍保留准确在线人数。
|
||||
int32 online_count = 22;
|
||||
}
|
||||
|
||||
// RoomBackgroundImage 是房间维度保存过的背景图素材。
|
||||
@ -656,6 +658,8 @@ message JoinRoomRequest {
|
||||
bool actor_is_robot = 7;
|
||||
// actor_display_profile 是进房用户展示资料快照,room-service 只透传到进房 IM/outbox,不写入 RoomState。
|
||||
RoomUserDisplayProfile actor_display_profile = 8;
|
||||
// response_mode=lite 只裁剪响应快照,不改变 Room Cell 命令提交、outbox 或 IM 事件语义。
|
||||
string response_mode = 9;
|
||||
}
|
||||
|
||||
// JoinRoomResponse 返回加入后的房间快照。
|
||||
@ -1189,6 +1193,18 @@ message ListRoomsRequest {
|
||||
bool all_visible_regions = 10;
|
||||
}
|
||||
|
||||
// ListRoomsByOwnersRequest 查询一组房主名下 active 房间。
|
||||
// owner_user_ids 必须由 gateway 根据上游业务归属注入,客户端不能直接提交任意房主集合。
|
||||
message ListRoomsByOwnersRequest {
|
||||
RequestMeta meta = 1;
|
||||
int64 viewer_user_id = 2;
|
||||
repeated int64 owner_user_ids = 3;
|
||||
string tab = 4;
|
||||
string cursor = 5;
|
||||
int32 limit = 6;
|
||||
string query = 7;
|
||||
}
|
||||
|
||||
// ListRoomFeedsRequest 查询 Mine 页 visited/friend/following/followed 房间流。
|
||||
// 它和公共房间发现列表分离,避免把用户关系流误建模成房间全集过滤。
|
||||
message ListRoomFeedsRequest {
|
||||
@ -1456,6 +1472,7 @@ service RoomQueryService {
|
||||
rpc AdminListRobotRooms(AdminListRobotRoomsRequest) returns (AdminListRobotRoomsResponse);
|
||||
rpc AdminFilterAvailableRoomRobots(AdminFilterAvailableRoomRobotsRequest) returns (AdminFilterAvailableRoomRobotsResponse);
|
||||
rpc ListRooms(ListRoomsRequest) returns (ListRoomsResponse);
|
||||
rpc ListRoomsByOwners(ListRoomsByOwnersRequest) returns (ListRoomsResponse);
|
||||
rpc ListRoomFeeds(ListRoomFeedsRequest) returns (ListRoomsResponse);
|
||||
rpc ListRoomGiftLeaderboard(ListRoomGiftLeaderboardRequest) returns (ListRoomGiftLeaderboardResponse);
|
||||
rpc GetMyRoom(GetMyRoomRequest) returns (GetMyRoomResponse);
|
||||
|
||||
@ -1570,6 +1570,7 @@ const (
|
||||
RoomQueryService_AdminListRobotRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminListRobotRooms"
|
||||
RoomQueryService_AdminFilterAvailableRoomRobots_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminFilterAvailableRoomRobots"
|
||||
RoomQueryService_ListRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRooms"
|
||||
RoomQueryService_ListRoomsByOwners_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRoomsByOwners"
|
||||
RoomQueryService_ListRoomFeeds_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRoomFeeds"
|
||||
RoomQueryService_ListRoomGiftLeaderboard_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRoomGiftLeaderboard"
|
||||
RoomQueryService_GetMyRoom_FullMethodName = "/hyapp.room.v1.RoomQueryService/GetMyRoom"
|
||||
@ -1596,6 +1597,7 @@ type RoomQueryServiceClient interface {
|
||||
AdminListRobotRooms(ctx context.Context, in *AdminListRobotRoomsRequest, opts ...grpc.CallOption) (*AdminListRobotRoomsResponse, error)
|
||||
AdminFilterAvailableRoomRobots(ctx context.Context, in *AdminFilterAvailableRoomRobotsRequest, opts ...grpc.CallOption) (*AdminFilterAvailableRoomRobotsResponse, error)
|
||||
ListRooms(ctx context.Context, in *ListRoomsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error)
|
||||
ListRoomsByOwners(ctx context.Context, in *ListRoomsByOwnersRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error)
|
||||
ListRoomFeeds(ctx context.Context, in *ListRoomFeedsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error)
|
||||
ListRoomGiftLeaderboard(ctx context.Context, in *ListRoomGiftLeaderboardRequest, opts ...grpc.CallOption) (*ListRoomGiftLeaderboardResponse, error)
|
||||
GetMyRoom(ctx context.Context, in *GetMyRoomRequest, opts ...grpc.CallOption) (*GetMyRoomResponse, error)
|
||||
@ -1705,6 +1707,16 @@ func (c *roomQueryServiceClient) ListRooms(ctx context.Context, in *ListRoomsReq
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *roomQueryServiceClient) ListRoomsByOwners(ctx context.Context, in *ListRoomsByOwnersRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListRoomsResponse)
|
||||
err := c.cc.Invoke(ctx, RoomQueryService_ListRoomsByOwners_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *roomQueryServiceClient) ListRoomFeeds(ctx context.Context, in *ListRoomFeedsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListRoomsResponse)
|
||||
@ -1810,6 +1822,7 @@ type RoomQueryServiceServer interface {
|
||||
AdminListRobotRooms(context.Context, *AdminListRobotRoomsRequest) (*AdminListRobotRoomsResponse, error)
|
||||
AdminFilterAvailableRoomRobots(context.Context, *AdminFilterAvailableRoomRobotsRequest) (*AdminFilterAvailableRoomRobotsResponse, error)
|
||||
ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error)
|
||||
ListRoomsByOwners(context.Context, *ListRoomsByOwnersRequest) (*ListRoomsResponse, error)
|
||||
ListRoomFeeds(context.Context, *ListRoomFeedsRequest) (*ListRoomsResponse, error)
|
||||
ListRoomGiftLeaderboard(context.Context, *ListRoomGiftLeaderboardRequest) (*ListRoomGiftLeaderboardResponse, error)
|
||||
GetMyRoom(context.Context, *GetMyRoomRequest) (*GetMyRoomResponse, error)
|
||||
@ -1856,6 +1869,9 @@ func (UnimplementedRoomQueryServiceServer) AdminFilterAvailableRoomRobots(contex
|
||||
func (UnimplementedRoomQueryServiceServer) ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRooms not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) ListRoomsByOwners(context.Context, *ListRoomsByOwnersRequest) (*ListRoomsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRoomsByOwners not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) ListRoomFeeds(context.Context, *ListRoomFeedsRequest) (*ListRoomsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRoomFeeds not implemented")
|
||||
}
|
||||
@ -2066,6 +2082,24 @@ func _RoomQueryService_ListRooms_Handler(srv interface{}, ctx context.Context, d
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _RoomQueryService_ListRoomsByOwners_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListRoomsByOwnersRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RoomQueryServiceServer).ListRoomsByOwners(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: RoomQueryService_ListRoomsByOwners_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RoomQueryServiceServer).ListRoomsByOwners(ctx, req.(*ListRoomsByOwnersRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _RoomQueryService_ListRoomFeeds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListRoomFeedsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -2271,6 +2305,10 @@ var RoomQueryService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ListRooms",
|
||||
Handler: _RoomQueryService_ListRooms_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListRoomsByOwners",
|
||||
Handler: _RoomQueryService_ListRoomsByOwners_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListRoomFeeds",
|
||||
Handler: _RoomQueryService_ListRoomFeeds_Handler,
|
||||
|
||||
@ -5266,6 +5266,136 @@ func (x *SetAgencyJoinEnabledResponse) GetAgency() *Agency {
|
||||
return nil
|
||||
}
|
||||
|
||||
type UpdateAgencyProfileRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
CommandId string `protobuf:"bytes,2,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"`
|
||||
OperatorUserId int64 `protobuf:"varint,3,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"`
|
||||
AgencyId int64 `protobuf:"varint,4,opt,name=agency_id,json=agencyId,proto3" json:"agency_id,omitempty"`
|
||||
Name *string `protobuf:"bytes,5,opt,name=name,proto3,oneof" json:"name,omitempty"`
|
||||
Avatar *string `protobuf:"bytes,6,opt,name=avatar,proto3,oneof" json:"avatar,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) Reset() {
|
||||
*x = UpdateAgencyProfileRequest{}
|
||||
mi := &file_proto_user_v1_host_proto_msgTypes[77]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateAgencyProfileRequest) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_host_proto_msgTypes[77]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UpdateAgencyProfileRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateAgencyProfileRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_host_proto_rawDescGZIP(), []int{77}
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) GetMeta() *RequestMeta {
|
||||
if x != nil {
|
||||
return x.Meta
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) GetCommandId() string {
|
||||
if x != nil {
|
||||
return x.CommandId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) GetOperatorUserId() int64 {
|
||||
if x != nil {
|
||||
return x.OperatorUserId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) GetAgencyId() int64 {
|
||||
if x != nil {
|
||||
return x.AgencyId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) GetName() string {
|
||||
if x != nil && x.Name != nil {
|
||||
return *x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileRequest) GetAvatar() string {
|
||||
if x != nil && x.Avatar != nil {
|
||||
return *x.Avatar
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UpdateAgencyProfileResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Agency *Agency `protobuf:"bytes,1,opt,name=agency,proto3" json:"agency,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileResponse) Reset() {
|
||||
*x = UpdateAgencyProfileResponse{}
|
||||
mi := &file_proto_user_v1_host_proto_msgTypes[78]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateAgencyProfileResponse) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateAgencyProfileResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_host_proto_msgTypes[78]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UpdateAgencyProfileResponse.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateAgencyProfileResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_host_proto_rawDescGZIP(), []int{78}
|
||||
}
|
||||
|
||||
func (x *UpdateAgencyProfileResponse) GetAgency() *Agency {
|
||||
if x != nil {
|
||||
return x.Agency
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_proto_user_v1_host_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_proto_user_v1_host_proto_rawDesc = []byte{
|
||||
@ -6128,226 +6258,254 @@ var file_proto_user_v1_host_proto_rawDesc = []byte{
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x06, 0x61, 0x67, 0x65,
|
||||
0x6e, 0x63, 0x79, 0x32, 0xd5, 0x12, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74,
|
||||
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63,
|
||||
0x68, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68,
|
||||
0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x54,
|
||||
0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x41,
|
||||
0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70,
|
||||
0x6c, 0x79, 0x54, 0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x78, 0x0a, 0x17, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x67, 0x65, 0x6e,
|
||||
0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65,
|
||||
0x76, 0x69, 0x65, 0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76,
|
||||
0x69, 0x65, 0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e,
|
||||
0x4b, 0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x24,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b,
|
||||
0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48,
|
||||
0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x49,
|
||||
0x6e, 0x76, 0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69,
|
||||
0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x44,
|
||||
0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x51, 0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x12,
|
||||
0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65,
|
||||
0x61, 0x64, 0x65, 0x72, 0x42, 0x44, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x6e, 0x63, 0x79, 0x22, 0xfc, 0x01, 0x0a, 0x1a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65,
|
||||
0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49,
|
||||
0x64, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73,
|
||||
0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65,
|
||||
0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x61,
|
||||
0x67, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08,
|
||||
0x61, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01,
|
||||
0x01, 0x12, 0x1b, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x09, 0x48, 0x01, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x88, 0x01, 0x01, 0x42, 0x07,
|
||||
0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x61, 0x76, 0x61, 0x74,
|
||||
0x61, 0x72, 0x22, 0x4c, 0x0a, 0x1b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e,
|
||||
0x63, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x2d, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x63, 0x79,
|
||||
0x32, 0xc3, 0x13, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x67, 0x65,
|
||||
0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61,
|
||||
0x72, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x41, 0x67, 0x65, 0x6e,
|
||||
0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x54,
|
||||
0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x78, 0x0a, 0x17, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41,
|
||||
0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65,
|
||||
0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77,
|
||||
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x4b, 0x69, 0x63,
|
||||
0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x24, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b,
|
||||
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x49, 0x6e, 0x76, 0x69,
|
||||
0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x41,
|
||||
0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76,
|
||||
0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x4b, 0x0a, 0x08, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x12, 0x1e, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e,
|
||||
0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e,
|
||||
0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51,
|
||||
0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76,
|
||||
0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49,
|
||||
0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x60, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65,
|
||||
0x72, 0x42, 0x44, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65,
|
||||
0x72, 0x42, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61,
|
||||
0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65,
|
||||
0x61, 0x64, 0x65, 0x72, 0x42, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x44, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44,
|
||||
0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x2a,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x63,
|
||||
0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42,
|
||||
0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x42,
|
||||
0x44, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44,
|
||||
0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f,
|
||||
0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6c,
|
||||
0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49,
|
||||
0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c,
|
||||
0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x15,
|
||||
0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c,
|
||||
0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x41, 0x67, 0x65,
|
||||
0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x42, 0x44, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49,
|
||||
0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52,
|
||||
0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e,
|
||||
0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x66, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69,
|
||||
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e,
|
||||
0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x50, 0x72, 0x6f,
|
||||
0x63, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e,
|
||||
0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x5d, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69,
|
||||
0x6c, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74,
|
||||
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x6f, 0x0a, 0x14, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50,
|
||||
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74,
|
||||
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x57, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
|
||||
0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x47, 0x65, 0x74,
|
||||
0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
|
||||
0x65, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50,
|
||||
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e,
|
||||
0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a,
|
||||
0x0e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12,
|
||||
0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f,
|
||||
0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14,
|
||||
0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73,
|
||||
0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f,
|
||||
0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a,
|
||||
0x0c, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x22, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
|
||||
0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69,
|
||||
0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x90, 0x01, 0x0a, 0x1f, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x35,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65,
|
||||
0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52,
|
||||
0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a,
|
||||
0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d,
|
||||
0x61, 0x72, 0x79, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53,
|
||||
0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
|
||||
0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x41,
|
||||
0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x17, 0x43, 0x68, 0x65, 0x63,
|
||||
0x6b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c,
|
||||
0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73,
|
||||
0x73, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73,
|
||||
0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d,
|
||||
0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79,
|
||||
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27,
|
||||
0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69,
|
||||
0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2a,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47,
|
||||
0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e,
|
||||
0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f,
|
||||
0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x90, 0x01, 0x0a, 0x1f, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69,
|
||||
0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x47, 0x65,
|
||||
0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79,
|
||||
0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d,
|
||||
0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73,
|
||||
0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e,
|
||||
0x63, 0x79, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x17, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75,
|
||||
0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79,
|
||||
0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x61,
|
||||
0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x61, 0x70,
|
||||
0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x63, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62,
|
||||
0x65, 0x72, 0x73, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x6d,
|
||||
0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41,
|
||||
0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63,
|
||||
0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
|
||||
0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb1, 0x08, 0x0a, 0x14,
|
||||
0x55, 0x73, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44,
|
||||
0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x4c,
|
||||
0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x12,
|
||||
0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x54, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
||||
0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12,
|
||||
0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74,
|
||||
0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb1, 0x08, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x72, 0x48,
|
||||
0x6f, 0x73, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x5d, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65,
|
||||
0x72, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44,
|
||||
0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b,
|
||||
0x0a, 0x08, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x53,
|
||||
0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e,
|
||||
0x65, 0x42, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x42, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x53,
|
||||
0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x44,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
|
||||
0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x63, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53,
|
||||
0x65, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x69, 0x6e,
|
||||
0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x69,
|
||||
0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
|
||||
0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x43, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x64,
|
||||
0x64, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x63,
|
||||
0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a,
|
||||
0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x21, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f,
|
||||
0x73, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65,
|
||||
0x6e, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f,
|
||||
0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
||||
0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f,
|
||||
0x0a, 0x14, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79,
|
||||
0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e,
|
||||
0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42,
|
||||
0x26, 0x5a, 0x24, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61,
|
||||
0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31,
|
||||
0x3b, 0x75, 0x73, 0x65, 0x72, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e,
|
||||
0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63,
|
||||
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41,
|
||||
0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a,
|
||||
0x12, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48,
|
||||
0x6f, 0x73, 0x74, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x41, 0x67, 0x65, 0x6e,
|
||||
0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64,
|
||||
0x6d, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73,
|
||||
0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x67, 0x65,
|
||||
0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65,
|
||||
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57,
|
||||
0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44,
|
||||
0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x53, 0x65, 0x74,
|
||||
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
||||
0x64, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
|
||||
0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x26, 0x5a, 0x24, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72,
|
||||
0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -6362,7 +6520,7 @@ func file_proto_user_v1_host_proto_rawDescGZIP() []byte {
|
||||
return file_proto_user_v1_host_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proto_user_v1_host_proto_msgTypes = make([]protoimpl.MessageInfo, 78)
|
||||
var file_proto_user_v1_host_proto_msgTypes = make([]protoimpl.MessageInfo, 80)
|
||||
var file_proto_user_v1_host_proto_goTypes = []any{
|
||||
(*HostProfile)(nil), // 0: hyapp.user.v1.HostProfile
|
||||
(*Agency)(nil), // 1: hyapp.user.v1.Agency
|
||||
@ -6441,162 +6599,168 @@ var file_proto_user_v1_host_proto_goTypes = []any{
|
||||
(*SetAgencyStatusResponse)(nil), // 74: hyapp.user.v1.SetAgencyStatusResponse
|
||||
(*SetAgencyJoinEnabledRequest)(nil), // 75: hyapp.user.v1.SetAgencyJoinEnabledRequest
|
||||
(*SetAgencyJoinEnabledResponse)(nil), // 76: hyapp.user.v1.SetAgencyJoinEnabledResponse
|
||||
nil, // 77: hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry
|
||||
(*RequestMeta)(nil), // 78: hyapp.user.v1.RequestMeta
|
||||
(*UpdateAgencyProfileRequest)(nil), // 77: hyapp.user.v1.UpdateAgencyProfileRequest
|
||||
(*UpdateAgencyProfileResponse)(nil), // 78: hyapp.user.v1.UpdateAgencyProfileResponse
|
||||
nil, // 79: hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry
|
||||
(*RequestMeta)(nil), // 80: hyapp.user.v1.RequestMeta
|
||||
}
|
||||
var file_proto_user_v1_host_proto_depIdxs = []int32{
|
||||
78, // 0: hyapp.user.v1.SearchAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 0: hyapp.user.v1.SearchAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 1: hyapp.user.v1.SearchAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency
|
||||
78, // 2: hyapp.user.v1.ApplyToAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 2: hyapp.user.v1.ApplyToAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
7, // 3: hyapp.user.v1.ApplyToAgencyResponse.application:type_name -> hyapp.user.v1.AgencyApplication
|
||||
78, // 4: hyapp.user.v1.ReviewAgencyApplicationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 4: hyapp.user.v1.ReviewAgencyApplicationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
7, // 5: hyapp.user.v1.ReviewAgencyApplicationResponse.application:type_name -> hyapp.user.v1.AgencyApplication
|
||||
0, // 6: hyapp.user.v1.ReviewAgencyApplicationResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
|
||||
6, // 7: hyapp.user.v1.ReviewAgencyApplicationResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
|
||||
78, // 8: hyapp.user.v1.KickAgencyHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 8: hyapp.user.v1.KickAgencyHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
6, // 9: hyapp.user.v1.KickAgencyHostResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
|
||||
0, // 10: hyapp.user.v1.KickAgencyHostResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
|
||||
78, // 11: hyapp.user.v1.InviteAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 11: hyapp.user.v1.InviteAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
8, // 12: hyapp.user.v1.InviteAgencyResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
|
||||
78, // 13: hyapp.user.v1.InviteBDRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 13: hyapp.user.v1.InviteBDRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
8, // 14: hyapp.user.v1.InviteBDResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
|
||||
78, // 15: hyapp.user.v1.InviteHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 15: hyapp.user.v1.InviteHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
8, // 16: hyapp.user.v1.InviteHostResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
|
||||
78, // 17: hyapp.user.v1.ListBDLeaderBDsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 17: hyapp.user.v1.ListBDLeaderBDsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
2, // 18: hyapp.user.v1.ListBDLeaderBDsResponse.bd_profiles:type_name -> hyapp.user.v1.BDProfile
|
||||
78, // 19: hyapp.user.v1.ListBDLeaderAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 19: hyapp.user.v1.ListBDLeaderAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 20: hyapp.user.v1.ListBDLeaderAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency
|
||||
78, // 21: hyapp.user.v1.ListBDAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 21: hyapp.user.v1.ListBDAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 22: hyapp.user.v1.ListBDAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency
|
||||
78, // 23: hyapp.user.v1.ListRoleInvitationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 23: hyapp.user.v1.ListRoleInvitationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
8, // 24: hyapp.user.v1.ListRoleInvitationsResponse.invitations:type_name -> hyapp.user.v1.RoleInvitation
|
||||
78, // 25: hyapp.user.v1.GetRoleInvitationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 25: hyapp.user.v1.GetRoleInvitationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
8, // 26: hyapp.user.v1.GetRoleInvitationResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
|
||||
78, // 27: hyapp.user.v1.ProcessRoleInvitationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 27: hyapp.user.v1.ProcessRoleInvitationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
8, // 28: hyapp.user.v1.ProcessRoleInvitationResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
|
||||
0, // 29: hyapp.user.v1.ProcessRoleInvitationResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
|
||||
1, // 30: hyapp.user.v1.ProcessRoleInvitationResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
6, // 31: hyapp.user.v1.ProcessRoleInvitationResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
|
||||
2, // 32: hyapp.user.v1.ProcessRoleInvitationResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
|
||||
78, // 33: hyapp.user.v1.GetHostProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 33: hyapp.user.v1.GetHostProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
0, // 34: hyapp.user.v1.GetHostProfileResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
|
||||
78, // 35: hyapp.user.v1.BatchGetHostProfilesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
77, // 36: hyapp.user.v1.BatchGetHostProfilesResponse.host_profiles:type_name -> hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry
|
||||
78, // 37: hyapp.user.v1.GetBDProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 35: hyapp.user.v1.BatchGetHostProfilesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
79, // 36: hyapp.user.v1.BatchGetHostProfilesResponse.host_profiles:type_name -> hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry
|
||||
80, // 37: hyapp.user.v1.GetBDProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
2, // 38: hyapp.user.v1.GetBDProfileResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
|
||||
78, // 39: hyapp.user.v1.GetCoinSellerProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 39: hyapp.user.v1.GetCoinSellerProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
3, // 40: hyapp.user.v1.GetCoinSellerProfileResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile
|
||||
78, // 41: hyapp.user.v1.ListActiveCoinSellersInMyRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 41: hyapp.user.v1.ListActiveCoinSellersInMyRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
4, // 42: hyapp.user.v1.ListActiveCoinSellersInMyRegionResponse.coin_sellers:type_name -> hyapp.user.v1.CoinSellerListItem
|
||||
78, // 43: hyapp.user.v1.GetUserRoleSummaryRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 43: hyapp.user.v1.GetUserRoleSummaryRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
5, // 44: hyapp.user.v1.GetUserRoleSummaryResponse.summary:type_name -> hyapp.user.v1.UserRoleSummary
|
||||
78, // 45: hyapp.user.v1.GetAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 45: hyapp.user.v1.GetAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 46: hyapp.user.v1.GetAgencyResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
78, // 47: hyapp.user.v1.CheckBusinessCapabilityRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
78, // 48: hyapp.user.v1.GetAgencyMembersRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 47: hyapp.user.v1.CheckBusinessCapabilityRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 48: hyapp.user.v1.GetAgencyMembersRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
6, // 49: hyapp.user.v1.GetAgencyMembersResponse.memberships:type_name -> hyapp.user.v1.AgencyMembership
|
||||
78, // 50: hyapp.user.v1.GetAgencyApplicationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 50: hyapp.user.v1.GetAgencyApplicationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
7, // 51: hyapp.user.v1.GetAgencyApplicationsResponse.applications:type_name -> hyapp.user.v1.AgencyApplication
|
||||
78, // 52: hyapp.user.v1.CreateBDLeaderRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 52: hyapp.user.v1.CreateBDLeaderRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
2, // 53: hyapp.user.v1.CreateBDLeaderResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
|
||||
78, // 54: hyapp.user.v1.CreateBDRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 54: hyapp.user.v1.CreateBDRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
2, // 55: hyapp.user.v1.CreateBDResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
|
||||
78, // 56: hyapp.user.v1.SetBDStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 56: hyapp.user.v1.SetBDStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
2, // 57: hyapp.user.v1.SetBDStatusResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
|
||||
78, // 58: hyapp.user.v1.CreateCoinSellerRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 58: hyapp.user.v1.CreateCoinSellerRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
3, // 59: hyapp.user.v1.CreateCoinSellerResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile
|
||||
78, // 60: hyapp.user.v1.SetCoinSellerStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 60: hyapp.user.v1.SetCoinSellerStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
3, // 61: hyapp.user.v1.SetCoinSellerStatusResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile
|
||||
78, // 62: hyapp.user.v1.CreateAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 62: hyapp.user.v1.CreateAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 63: hyapp.user.v1.CreateAgencyResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
0, // 64: hyapp.user.v1.CreateAgencyResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
|
||||
6, // 65: hyapp.user.v1.CreateAgencyResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
|
||||
78, // 66: hyapp.user.v1.AdminAddAgencyHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 66: hyapp.user.v1.AdminAddAgencyHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 67: hyapp.user.v1.AdminAddAgencyHostResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
0, // 68: hyapp.user.v1.AdminAddAgencyHostResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
|
||||
6, // 69: hyapp.user.v1.AdminAddAgencyHostResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
|
||||
78, // 70: hyapp.user.v1.CloseAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 70: hyapp.user.v1.CloseAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 71: hyapp.user.v1.CloseAgencyResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
78, // 72: hyapp.user.v1.DeleteAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 72: hyapp.user.v1.DeleteAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 73: hyapp.user.v1.DeleteAgencyResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
78, // 74: hyapp.user.v1.SetAgencyStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 74: hyapp.user.v1.SetAgencyStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 75: hyapp.user.v1.SetAgencyStatusResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
78, // 76: hyapp.user.v1.SetAgencyJoinEnabledRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
80, // 76: hyapp.user.v1.SetAgencyJoinEnabledRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 77: hyapp.user.v1.SetAgencyJoinEnabledResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
0, // 78: hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry.value:type_name -> hyapp.user.v1.HostProfile
|
||||
9, // 79: hyapp.user.v1.UserHostService.SearchAgencies:input_type -> hyapp.user.v1.SearchAgenciesRequest
|
||||
11, // 80: hyapp.user.v1.UserHostService.ApplyToAgency:input_type -> hyapp.user.v1.ApplyToAgencyRequest
|
||||
13, // 81: hyapp.user.v1.UserHostService.ReviewAgencyApplication:input_type -> hyapp.user.v1.ReviewAgencyApplicationRequest
|
||||
15, // 82: hyapp.user.v1.UserHostService.KickAgencyHost:input_type -> hyapp.user.v1.KickAgencyHostRequest
|
||||
17, // 83: hyapp.user.v1.UserHostService.InviteAgency:input_type -> hyapp.user.v1.InviteAgencyRequest
|
||||
19, // 84: hyapp.user.v1.UserHostService.InviteBD:input_type -> hyapp.user.v1.InviteBDRequest
|
||||
21, // 85: hyapp.user.v1.UserHostService.InviteHost:input_type -> hyapp.user.v1.InviteHostRequest
|
||||
23, // 86: hyapp.user.v1.UserHostService.ListBDLeaderBDs:input_type -> hyapp.user.v1.ListBDLeaderBDsRequest
|
||||
25, // 87: hyapp.user.v1.UserHostService.ListBDLeaderAgencies:input_type -> hyapp.user.v1.ListBDLeaderAgenciesRequest
|
||||
27, // 88: hyapp.user.v1.UserHostService.ListBDAgencies:input_type -> hyapp.user.v1.ListBDAgenciesRequest
|
||||
29, // 89: hyapp.user.v1.UserHostService.ListRoleInvitations:input_type -> hyapp.user.v1.ListRoleInvitationsRequest
|
||||
31, // 90: hyapp.user.v1.UserHostService.GetRoleInvitation:input_type -> hyapp.user.v1.GetRoleInvitationRequest
|
||||
33, // 91: hyapp.user.v1.UserHostService.ProcessRoleInvitation:input_type -> hyapp.user.v1.ProcessRoleInvitationRequest
|
||||
35, // 92: hyapp.user.v1.UserHostService.GetHostProfile:input_type -> hyapp.user.v1.GetHostProfileRequest
|
||||
37, // 93: hyapp.user.v1.UserHostService.BatchGetHostProfiles:input_type -> hyapp.user.v1.BatchGetHostProfilesRequest
|
||||
39, // 94: hyapp.user.v1.UserHostService.GetBDProfile:input_type -> hyapp.user.v1.GetBDProfileRequest
|
||||
41, // 95: hyapp.user.v1.UserHostService.GetCoinSellerProfile:input_type -> hyapp.user.v1.GetCoinSellerProfileRequest
|
||||
43, // 96: hyapp.user.v1.UserHostService.ListActiveCoinSellersInMyRegion:input_type -> hyapp.user.v1.ListActiveCoinSellersInMyRegionRequest
|
||||
45, // 97: hyapp.user.v1.UserHostService.GetUserRoleSummary:input_type -> hyapp.user.v1.GetUserRoleSummaryRequest
|
||||
47, // 98: hyapp.user.v1.UserHostService.GetAgency:input_type -> hyapp.user.v1.GetAgencyRequest
|
||||
49, // 99: hyapp.user.v1.UserHostService.CheckBusinessCapability:input_type -> hyapp.user.v1.CheckBusinessCapabilityRequest
|
||||
51, // 100: hyapp.user.v1.UserHostService.GetAgencyMembers:input_type -> hyapp.user.v1.GetAgencyMembersRequest
|
||||
53, // 101: hyapp.user.v1.UserHostService.GetAgencyApplications:input_type -> hyapp.user.v1.GetAgencyApplicationsRequest
|
||||
55, // 102: hyapp.user.v1.UserHostAdminService.CreateBDLeader:input_type -> hyapp.user.v1.CreateBDLeaderRequest
|
||||
57, // 103: hyapp.user.v1.UserHostAdminService.CreateBD:input_type -> hyapp.user.v1.CreateBDRequest
|
||||
59, // 104: hyapp.user.v1.UserHostAdminService.SetBDStatus:input_type -> hyapp.user.v1.SetBDStatusRequest
|
||||
61, // 105: hyapp.user.v1.UserHostAdminService.CreateCoinSeller:input_type -> hyapp.user.v1.CreateCoinSellerRequest
|
||||
63, // 106: hyapp.user.v1.UserHostAdminService.SetCoinSellerStatus:input_type -> hyapp.user.v1.SetCoinSellerStatusRequest
|
||||
65, // 107: hyapp.user.v1.UserHostAdminService.CreateAgency:input_type -> hyapp.user.v1.CreateAgencyRequest
|
||||
67, // 108: hyapp.user.v1.UserHostAdminService.AdminAddAgencyHost:input_type -> hyapp.user.v1.AdminAddAgencyHostRequest
|
||||
69, // 109: hyapp.user.v1.UserHostAdminService.CloseAgency:input_type -> hyapp.user.v1.CloseAgencyRequest
|
||||
71, // 110: hyapp.user.v1.UserHostAdminService.DeleteAgency:input_type -> hyapp.user.v1.DeleteAgencyRequest
|
||||
73, // 111: hyapp.user.v1.UserHostAdminService.SetAgencyStatus:input_type -> hyapp.user.v1.SetAgencyStatusRequest
|
||||
75, // 112: hyapp.user.v1.UserHostAdminService.SetAgencyJoinEnabled:input_type -> hyapp.user.v1.SetAgencyJoinEnabledRequest
|
||||
10, // 113: hyapp.user.v1.UserHostService.SearchAgencies:output_type -> hyapp.user.v1.SearchAgenciesResponse
|
||||
12, // 114: hyapp.user.v1.UserHostService.ApplyToAgency:output_type -> hyapp.user.v1.ApplyToAgencyResponse
|
||||
14, // 115: hyapp.user.v1.UserHostService.ReviewAgencyApplication:output_type -> hyapp.user.v1.ReviewAgencyApplicationResponse
|
||||
16, // 116: hyapp.user.v1.UserHostService.KickAgencyHost:output_type -> hyapp.user.v1.KickAgencyHostResponse
|
||||
18, // 117: hyapp.user.v1.UserHostService.InviteAgency:output_type -> hyapp.user.v1.InviteAgencyResponse
|
||||
20, // 118: hyapp.user.v1.UserHostService.InviteBD:output_type -> hyapp.user.v1.InviteBDResponse
|
||||
22, // 119: hyapp.user.v1.UserHostService.InviteHost:output_type -> hyapp.user.v1.InviteHostResponse
|
||||
24, // 120: hyapp.user.v1.UserHostService.ListBDLeaderBDs:output_type -> hyapp.user.v1.ListBDLeaderBDsResponse
|
||||
26, // 121: hyapp.user.v1.UserHostService.ListBDLeaderAgencies:output_type -> hyapp.user.v1.ListBDLeaderAgenciesResponse
|
||||
28, // 122: hyapp.user.v1.UserHostService.ListBDAgencies:output_type -> hyapp.user.v1.ListBDAgenciesResponse
|
||||
30, // 123: hyapp.user.v1.UserHostService.ListRoleInvitations:output_type -> hyapp.user.v1.ListRoleInvitationsResponse
|
||||
32, // 124: hyapp.user.v1.UserHostService.GetRoleInvitation:output_type -> hyapp.user.v1.GetRoleInvitationResponse
|
||||
34, // 125: hyapp.user.v1.UserHostService.ProcessRoleInvitation:output_type -> hyapp.user.v1.ProcessRoleInvitationResponse
|
||||
36, // 126: hyapp.user.v1.UserHostService.GetHostProfile:output_type -> hyapp.user.v1.GetHostProfileResponse
|
||||
38, // 127: hyapp.user.v1.UserHostService.BatchGetHostProfiles:output_type -> hyapp.user.v1.BatchGetHostProfilesResponse
|
||||
40, // 128: hyapp.user.v1.UserHostService.GetBDProfile:output_type -> hyapp.user.v1.GetBDProfileResponse
|
||||
42, // 129: hyapp.user.v1.UserHostService.GetCoinSellerProfile:output_type -> hyapp.user.v1.GetCoinSellerProfileResponse
|
||||
44, // 130: hyapp.user.v1.UserHostService.ListActiveCoinSellersInMyRegion:output_type -> hyapp.user.v1.ListActiveCoinSellersInMyRegionResponse
|
||||
46, // 131: hyapp.user.v1.UserHostService.GetUserRoleSummary:output_type -> hyapp.user.v1.GetUserRoleSummaryResponse
|
||||
48, // 132: hyapp.user.v1.UserHostService.GetAgency:output_type -> hyapp.user.v1.GetAgencyResponse
|
||||
50, // 133: hyapp.user.v1.UserHostService.CheckBusinessCapability:output_type -> hyapp.user.v1.CheckBusinessCapabilityResponse
|
||||
52, // 134: hyapp.user.v1.UserHostService.GetAgencyMembers:output_type -> hyapp.user.v1.GetAgencyMembersResponse
|
||||
54, // 135: hyapp.user.v1.UserHostService.GetAgencyApplications:output_type -> hyapp.user.v1.GetAgencyApplicationsResponse
|
||||
56, // 136: hyapp.user.v1.UserHostAdminService.CreateBDLeader:output_type -> hyapp.user.v1.CreateBDLeaderResponse
|
||||
58, // 137: hyapp.user.v1.UserHostAdminService.CreateBD:output_type -> hyapp.user.v1.CreateBDResponse
|
||||
60, // 138: hyapp.user.v1.UserHostAdminService.SetBDStatus:output_type -> hyapp.user.v1.SetBDStatusResponse
|
||||
62, // 139: hyapp.user.v1.UserHostAdminService.CreateCoinSeller:output_type -> hyapp.user.v1.CreateCoinSellerResponse
|
||||
64, // 140: hyapp.user.v1.UserHostAdminService.SetCoinSellerStatus:output_type -> hyapp.user.v1.SetCoinSellerStatusResponse
|
||||
66, // 141: hyapp.user.v1.UserHostAdminService.CreateAgency:output_type -> hyapp.user.v1.CreateAgencyResponse
|
||||
68, // 142: hyapp.user.v1.UserHostAdminService.AdminAddAgencyHost:output_type -> hyapp.user.v1.AdminAddAgencyHostResponse
|
||||
70, // 143: hyapp.user.v1.UserHostAdminService.CloseAgency:output_type -> hyapp.user.v1.CloseAgencyResponse
|
||||
72, // 144: hyapp.user.v1.UserHostAdminService.DeleteAgency:output_type -> hyapp.user.v1.DeleteAgencyResponse
|
||||
74, // 145: hyapp.user.v1.UserHostAdminService.SetAgencyStatus:output_type -> hyapp.user.v1.SetAgencyStatusResponse
|
||||
76, // 146: hyapp.user.v1.UserHostAdminService.SetAgencyJoinEnabled:output_type -> hyapp.user.v1.SetAgencyJoinEnabledResponse
|
||||
113, // [113:147] is the sub-list for method output_type
|
||||
79, // [79:113] is the sub-list for method input_type
|
||||
79, // [79:79] is the sub-list for extension type_name
|
||||
79, // [79:79] is the sub-list for extension extendee
|
||||
0, // [0:79] is the sub-list for field type_name
|
||||
80, // 78: hyapp.user.v1.UpdateAgencyProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
1, // 79: hyapp.user.v1.UpdateAgencyProfileResponse.agency:type_name -> hyapp.user.v1.Agency
|
||||
0, // 80: hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry.value:type_name -> hyapp.user.v1.HostProfile
|
||||
9, // 81: hyapp.user.v1.UserHostService.SearchAgencies:input_type -> hyapp.user.v1.SearchAgenciesRequest
|
||||
11, // 82: hyapp.user.v1.UserHostService.ApplyToAgency:input_type -> hyapp.user.v1.ApplyToAgencyRequest
|
||||
13, // 83: hyapp.user.v1.UserHostService.ReviewAgencyApplication:input_type -> hyapp.user.v1.ReviewAgencyApplicationRequest
|
||||
15, // 84: hyapp.user.v1.UserHostService.KickAgencyHost:input_type -> hyapp.user.v1.KickAgencyHostRequest
|
||||
17, // 85: hyapp.user.v1.UserHostService.InviteAgency:input_type -> hyapp.user.v1.InviteAgencyRequest
|
||||
19, // 86: hyapp.user.v1.UserHostService.InviteBD:input_type -> hyapp.user.v1.InviteBDRequest
|
||||
21, // 87: hyapp.user.v1.UserHostService.InviteHost:input_type -> hyapp.user.v1.InviteHostRequest
|
||||
23, // 88: hyapp.user.v1.UserHostService.ListBDLeaderBDs:input_type -> hyapp.user.v1.ListBDLeaderBDsRequest
|
||||
25, // 89: hyapp.user.v1.UserHostService.ListBDLeaderAgencies:input_type -> hyapp.user.v1.ListBDLeaderAgenciesRequest
|
||||
27, // 90: hyapp.user.v1.UserHostService.ListBDAgencies:input_type -> hyapp.user.v1.ListBDAgenciesRequest
|
||||
29, // 91: hyapp.user.v1.UserHostService.ListRoleInvitations:input_type -> hyapp.user.v1.ListRoleInvitationsRequest
|
||||
31, // 92: hyapp.user.v1.UserHostService.GetRoleInvitation:input_type -> hyapp.user.v1.GetRoleInvitationRequest
|
||||
33, // 93: hyapp.user.v1.UserHostService.ProcessRoleInvitation:input_type -> hyapp.user.v1.ProcessRoleInvitationRequest
|
||||
35, // 94: hyapp.user.v1.UserHostService.GetHostProfile:input_type -> hyapp.user.v1.GetHostProfileRequest
|
||||
37, // 95: hyapp.user.v1.UserHostService.BatchGetHostProfiles:input_type -> hyapp.user.v1.BatchGetHostProfilesRequest
|
||||
39, // 96: hyapp.user.v1.UserHostService.GetBDProfile:input_type -> hyapp.user.v1.GetBDProfileRequest
|
||||
41, // 97: hyapp.user.v1.UserHostService.GetCoinSellerProfile:input_type -> hyapp.user.v1.GetCoinSellerProfileRequest
|
||||
43, // 98: hyapp.user.v1.UserHostService.ListActiveCoinSellersInMyRegion:input_type -> hyapp.user.v1.ListActiveCoinSellersInMyRegionRequest
|
||||
45, // 99: hyapp.user.v1.UserHostService.GetUserRoleSummary:input_type -> hyapp.user.v1.GetUserRoleSummaryRequest
|
||||
47, // 100: hyapp.user.v1.UserHostService.GetAgency:input_type -> hyapp.user.v1.GetAgencyRequest
|
||||
49, // 101: hyapp.user.v1.UserHostService.CheckBusinessCapability:input_type -> hyapp.user.v1.CheckBusinessCapabilityRequest
|
||||
51, // 102: hyapp.user.v1.UserHostService.GetAgencyMembers:input_type -> hyapp.user.v1.GetAgencyMembersRequest
|
||||
53, // 103: hyapp.user.v1.UserHostService.GetAgencyApplications:input_type -> hyapp.user.v1.GetAgencyApplicationsRequest
|
||||
77, // 104: hyapp.user.v1.UserHostService.UpdateAgencyProfile:input_type -> hyapp.user.v1.UpdateAgencyProfileRequest
|
||||
55, // 105: hyapp.user.v1.UserHostAdminService.CreateBDLeader:input_type -> hyapp.user.v1.CreateBDLeaderRequest
|
||||
57, // 106: hyapp.user.v1.UserHostAdminService.CreateBD:input_type -> hyapp.user.v1.CreateBDRequest
|
||||
59, // 107: hyapp.user.v1.UserHostAdminService.SetBDStatus:input_type -> hyapp.user.v1.SetBDStatusRequest
|
||||
61, // 108: hyapp.user.v1.UserHostAdminService.CreateCoinSeller:input_type -> hyapp.user.v1.CreateCoinSellerRequest
|
||||
63, // 109: hyapp.user.v1.UserHostAdminService.SetCoinSellerStatus:input_type -> hyapp.user.v1.SetCoinSellerStatusRequest
|
||||
65, // 110: hyapp.user.v1.UserHostAdminService.CreateAgency:input_type -> hyapp.user.v1.CreateAgencyRequest
|
||||
67, // 111: hyapp.user.v1.UserHostAdminService.AdminAddAgencyHost:input_type -> hyapp.user.v1.AdminAddAgencyHostRequest
|
||||
69, // 112: hyapp.user.v1.UserHostAdminService.CloseAgency:input_type -> hyapp.user.v1.CloseAgencyRequest
|
||||
71, // 113: hyapp.user.v1.UserHostAdminService.DeleteAgency:input_type -> hyapp.user.v1.DeleteAgencyRequest
|
||||
73, // 114: hyapp.user.v1.UserHostAdminService.SetAgencyStatus:input_type -> hyapp.user.v1.SetAgencyStatusRequest
|
||||
75, // 115: hyapp.user.v1.UserHostAdminService.SetAgencyJoinEnabled:input_type -> hyapp.user.v1.SetAgencyJoinEnabledRequest
|
||||
10, // 116: hyapp.user.v1.UserHostService.SearchAgencies:output_type -> hyapp.user.v1.SearchAgenciesResponse
|
||||
12, // 117: hyapp.user.v1.UserHostService.ApplyToAgency:output_type -> hyapp.user.v1.ApplyToAgencyResponse
|
||||
14, // 118: hyapp.user.v1.UserHostService.ReviewAgencyApplication:output_type -> hyapp.user.v1.ReviewAgencyApplicationResponse
|
||||
16, // 119: hyapp.user.v1.UserHostService.KickAgencyHost:output_type -> hyapp.user.v1.KickAgencyHostResponse
|
||||
18, // 120: hyapp.user.v1.UserHostService.InviteAgency:output_type -> hyapp.user.v1.InviteAgencyResponse
|
||||
20, // 121: hyapp.user.v1.UserHostService.InviteBD:output_type -> hyapp.user.v1.InviteBDResponse
|
||||
22, // 122: hyapp.user.v1.UserHostService.InviteHost:output_type -> hyapp.user.v1.InviteHostResponse
|
||||
24, // 123: hyapp.user.v1.UserHostService.ListBDLeaderBDs:output_type -> hyapp.user.v1.ListBDLeaderBDsResponse
|
||||
26, // 124: hyapp.user.v1.UserHostService.ListBDLeaderAgencies:output_type -> hyapp.user.v1.ListBDLeaderAgenciesResponse
|
||||
28, // 125: hyapp.user.v1.UserHostService.ListBDAgencies:output_type -> hyapp.user.v1.ListBDAgenciesResponse
|
||||
30, // 126: hyapp.user.v1.UserHostService.ListRoleInvitations:output_type -> hyapp.user.v1.ListRoleInvitationsResponse
|
||||
32, // 127: hyapp.user.v1.UserHostService.GetRoleInvitation:output_type -> hyapp.user.v1.GetRoleInvitationResponse
|
||||
34, // 128: hyapp.user.v1.UserHostService.ProcessRoleInvitation:output_type -> hyapp.user.v1.ProcessRoleInvitationResponse
|
||||
36, // 129: hyapp.user.v1.UserHostService.GetHostProfile:output_type -> hyapp.user.v1.GetHostProfileResponse
|
||||
38, // 130: hyapp.user.v1.UserHostService.BatchGetHostProfiles:output_type -> hyapp.user.v1.BatchGetHostProfilesResponse
|
||||
40, // 131: hyapp.user.v1.UserHostService.GetBDProfile:output_type -> hyapp.user.v1.GetBDProfileResponse
|
||||
42, // 132: hyapp.user.v1.UserHostService.GetCoinSellerProfile:output_type -> hyapp.user.v1.GetCoinSellerProfileResponse
|
||||
44, // 133: hyapp.user.v1.UserHostService.ListActiveCoinSellersInMyRegion:output_type -> hyapp.user.v1.ListActiveCoinSellersInMyRegionResponse
|
||||
46, // 134: hyapp.user.v1.UserHostService.GetUserRoleSummary:output_type -> hyapp.user.v1.GetUserRoleSummaryResponse
|
||||
48, // 135: hyapp.user.v1.UserHostService.GetAgency:output_type -> hyapp.user.v1.GetAgencyResponse
|
||||
50, // 136: hyapp.user.v1.UserHostService.CheckBusinessCapability:output_type -> hyapp.user.v1.CheckBusinessCapabilityResponse
|
||||
52, // 137: hyapp.user.v1.UserHostService.GetAgencyMembers:output_type -> hyapp.user.v1.GetAgencyMembersResponse
|
||||
54, // 138: hyapp.user.v1.UserHostService.GetAgencyApplications:output_type -> hyapp.user.v1.GetAgencyApplicationsResponse
|
||||
78, // 139: hyapp.user.v1.UserHostService.UpdateAgencyProfile:output_type -> hyapp.user.v1.UpdateAgencyProfileResponse
|
||||
56, // 140: hyapp.user.v1.UserHostAdminService.CreateBDLeader:output_type -> hyapp.user.v1.CreateBDLeaderResponse
|
||||
58, // 141: hyapp.user.v1.UserHostAdminService.CreateBD:output_type -> hyapp.user.v1.CreateBDResponse
|
||||
60, // 142: hyapp.user.v1.UserHostAdminService.SetBDStatus:output_type -> hyapp.user.v1.SetBDStatusResponse
|
||||
62, // 143: hyapp.user.v1.UserHostAdminService.CreateCoinSeller:output_type -> hyapp.user.v1.CreateCoinSellerResponse
|
||||
64, // 144: hyapp.user.v1.UserHostAdminService.SetCoinSellerStatus:output_type -> hyapp.user.v1.SetCoinSellerStatusResponse
|
||||
66, // 145: hyapp.user.v1.UserHostAdminService.CreateAgency:output_type -> hyapp.user.v1.CreateAgencyResponse
|
||||
68, // 146: hyapp.user.v1.UserHostAdminService.AdminAddAgencyHost:output_type -> hyapp.user.v1.AdminAddAgencyHostResponse
|
||||
70, // 147: hyapp.user.v1.UserHostAdminService.CloseAgency:output_type -> hyapp.user.v1.CloseAgencyResponse
|
||||
72, // 148: hyapp.user.v1.UserHostAdminService.DeleteAgency:output_type -> hyapp.user.v1.DeleteAgencyResponse
|
||||
74, // 149: hyapp.user.v1.UserHostAdminService.SetAgencyStatus:output_type -> hyapp.user.v1.SetAgencyStatusResponse
|
||||
76, // 150: hyapp.user.v1.UserHostAdminService.SetAgencyJoinEnabled:output_type -> hyapp.user.v1.SetAgencyJoinEnabledResponse
|
||||
116, // [116:151] is the sub-list for method output_type
|
||||
81, // [81:116] is the sub-list for method input_type
|
||||
81, // [81:81] is the sub-list for extension type_name
|
||||
81, // [81:81] is the sub-list for extension extendee
|
||||
0, // [0:81] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proto_user_v1_host_proto_init() }
|
||||
@ -6605,13 +6769,14 @@ func file_proto_user_v1_host_proto_init() {
|
||||
return
|
||||
}
|
||||
file_proto_user_v1_user_proto_init()
|
||||
file_proto_user_v1_host_proto_msgTypes[77].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proto_user_v1_host_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 78,
|
||||
NumMessages: 80,
|
||||
NumExtensions: 0,
|
||||
NumServices: 2,
|
||||
},
|
||||
|
||||
@ -548,6 +548,19 @@ message SetAgencyJoinEnabledResponse {
|
||||
Agency agency = 1;
|
||||
}
|
||||
|
||||
message UpdateAgencyProfileRequest {
|
||||
RequestMeta meta = 1;
|
||||
string command_id = 2;
|
||||
int64 operator_user_id = 3;
|
||||
int64 agency_id = 4;
|
||||
optional string name = 5;
|
||||
optional string avatar = 6;
|
||||
}
|
||||
|
||||
message UpdateAgencyProfileResponse {
|
||||
Agency agency = 1;
|
||||
}
|
||||
|
||||
// UserHostService 是 user-service 内部 host domain 的 gRPC 面,不是独立微服务。
|
||||
service UserHostService {
|
||||
rpc SearchAgencies(SearchAgenciesRequest) returns (SearchAgenciesResponse);
|
||||
@ -573,6 +586,7 @@ service UserHostService {
|
||||
rpc CheckBusinessCapability(CheckBusinessCapabilityRequest) returns (CheckBusinessCapabilityResponse);
|
||||
rpc GetAgencyMembers(GetAgencyMembersRequest) returns (GetAgencyMembersResponse);
|
||||
rpc GetAgencyApplications(GetAgencyApplicationsRequest) returns (GetAgencyApplicationsResponse);
|
||||
rpc UpdateAgencyProfile(UpdateAgencyProfileRequest) returns (UpdateAgencyProfileResponse);
|
||||
}
|
||||
|
||||
// UserHostAdminService 是后台关系管理入口;公网 admin 鉴权由 admin-server 承担。
|
||||
|
||||
@ -42,6 +42,7 @@ const (
|
||||
UserHostService_CheckBusinessCapability_FullMethodName = "/hyapp.user.v1.UserHostService/CheckBusinessCapability"
|
||||
UserHostService_GetAgencyMembers_FullMethodName = "/hyapp.user.v1.UserHostService/GetAgencyMembers"
|
||||
UserHostService_GetAgencyApplications_FullMethodName = "/hyapp.user.v1.UserHostService/GetAgencyApplications"
|
||||
UserHostService_UpdateAgencyProfile_FullMethodName = "/hyapp.user.v1.UserHostService/UpdateAgencyProfile"
|
||||
)
|
||||
|
||||
// UserHostServiceClient is the client API for UserHostService service.
|
||||
@ -73,6 +74,7 @@ type UserHostServiceClient interface {
|
||||
CheckBusinessCapability(ctx context.Context, in *CheckBusinessCapabilityRequest, opts ...grpc.CallOption) (*CheckBusinessCapabilityResponse, error)
|
||||
GetAgencyMembers(ctx context.Context, in *GetAgencyMembersRequest, opts ...grpc.CallOption) (*GetAgencyMembersResponse, error)
|
||||
GetAgencyApplications(ctx context.Context, in *GetAgencyApplicationsRequest, opts ...grpc.CallOption) (*GetAgencyApplicationsResponse, error)
|
||||
UpdateAgencyProfile(ctx context.Context, in *UpdateAgencyProfileRequest, opts ...grpc.CallOption) (*UpdateAgencyProfileResponse, error)
|
||||
}
|
||||
|
||||
type userHostServiceClient struct {
|
||||
@ -313,6 +315,16 @@ func (c *userHostServiceClient) GetAgencyApplications(ctx context.Context, in *G
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userHostServiceClient) UpdateAgencyProfile(ctx context.Context, in *UpdateAgencyProfileRequest, opts ...grpc.CallOption) (*UpdateAgencyProfileResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UpdateAgencyProfileResponse)
|
||||
err := c.cc.Invoke(ctx, UserHostService_UpdateAgencyProfile_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// UserHostServiceServer is the server API for UserHostService service.
|
||||
// All implementations must embed UnimplementedUserHostServiceServer
|
||||
// for forward compatibility.
|
||||
@ -342,6 +354,7 @@ type UserHostServiceServer interface {
|
||||
CheckBusinessCapability(context.Context, *CheckBusinessCapabilityRequest) (*CheckBusinessCapabilityResponse, error)
|
||||
GetAgencyMembers(context.Context, *GetAgencyMembersRequest) (*GetAgencyMembersResponse, error)
|
||||
GetAgencyApplications(context.Context, *GetAgencyApplicationsRequest) (*GetAgencyApplicationsResponse, error)
|
||||
UpdateAgencyProfile(context.Context, *UpdateAgencyProfileRequest) (*UpdateAgencyProfileResponse, error)
|
||||
mustEmbedUnimplementedUserHostServiceServer()
|
||||
}
|
||||
|
||||
@ -421,6 +434,9 @@ func (UnimplementedUserHostServiceServer) GetAgencyMembers(context.Context, *Get
|
||||
func (UnimplementedUserHostServiceServer) GetAgencyApplications(context.Context, *GetAgencyApplicationsRequest) (*GetAgencyApplicationsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAgencyApplications not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) UpdateAgencyProfile(context.Context, *UpdateAgencyProfileRequest) (*UpdateAgencyProfileResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateAgencyProfile not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) mustEmbedUnimplementedUserHostServiceServer() {}
|
||||
func (UnimplementedUserHostServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
@ -856,6 +872,24 @@ func _UserHostService_GetAgencyApplications_Handler(srv interface{}, ctx context
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserHostService_UpdateAgencyProfile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateAgencyProfileRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserHostServiceServer).UpdateAgencyProfile(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserHostService_UpdateAgencyProfile_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserHostServiceServer).UpdateAgencyProfile(ctx, req.(*UpdateAgencyProfileRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// UserHostService_ServiceDesc is the grpc.ServiceDesc for UserHostService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -955,6 +989,10 @@ var UserHostService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "GetAgencyApplications",
|
||||
Handler: _UserHostService_GetAgencyApplications_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateAgencyProfile",
|
||||
Handler: _UserHostService_UpdateAgencyProfile_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "proto/user/v1/host.proto",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -691,6 +691,25 @@ message BatchGetUsersResponse {
|
||||
map<int64, User> users = 1;
|
||||
}
|
||||
|
||||
// RoomBasicUser 是房间首屏只需要的用户展示基础资料。
|
||||
message RoomBasicUser {
|
||||
int64 user_id = 1;
|
||||
string username = 2;
|
||||
string avatar = 3;
|
||||
string display_user_id = 4;
|
||||
}
|
||||
|
||||
// BatchGetRoomBasicUsersRequest 为房间进房 lite 首屏批量读取最小用户资料。
|
||||
message BatchGetRoomBasicUsersRequest {
|
||||
RequestMeta meta = 1;
|
||||
repeated int64 user_ids = 2;
|
||||
}
|
||||
|
||||
// BatchGetRoomBasicUsersResponse 返回按 user_id 索引的房间首屏基础资料。
|
||||
message BatchGetRoomBasicUsersResponse {
|
||||
map<int64, RoomBasicUser> users = 1;
|
||||
}
|
||||
|
||||
// ListUserIDsRequest 给低频后台 fanout/重算任务按 user_id 游标读取目标用户。
|
||||
message ListUserIDsRequest {
|
||||
RequestMeta meta = 1;
|
||||
@ -1324,6 +1343,7 @@ service UserService {
|
||||
rpc BusinessUserLookup(BusinessUserLookupRequest) returns (BusinessUserLookupResponse);
|
||||
rpc GetMyProfileStats(GetMyProfileStatsRequest) returns (GetMyProfileStatsResponse);
|
||||
rpc BatchGetUsers(BatchGetUsersRequest) returns (BatchGetUsersResponse);
|
||||
rpc BatchGetRoomBasicUsers(BatchGetRoomBasicUsersRequest) returns (BatchGetRoomBasicUsersResponse);
|
||||
rpc ListUserIDs(ListUserIDsRequest) returns (ListUserIDsResponse);
|
||||
rpc GetUserMicLifetimeStats(GetUserMicLifetimeStatsRequest) returns (GetUserMicLifetimeStatsResponse);
|
||||
rpc UpdateUserProfile(UpdateUserProfileRequest) returns (UpdateUserProfileResponse);
|
||||
|
||||
@ -24,6 +24,7 @@ const (
|
||||
UserService_BusinessUserLookup_FullMethodName = "/hyapp.user.v1.UserService/BusinessUserLookup"
|
||||
UserService_GetMyProfileStats_FullMethodName = "/hyapp.user.v1.UserService/GetMyProfileStats"
|
||||
UserService_BatchGetUsers_FullMethodName = "/hyapp.user.v1.UserService/BatchGetUsers"
|
||||
UserService_BatchGetRoomBasicUsers_FullMethodName = "/hyapp.user.v1.UserService/BatchGetRoomBasicUsers"
|
||||
UserService_ListUserIDs_FullMethodName = "/hyapp.user.v1.UserService/ListUserIDs"
|
||||
UserService_GetUserMicLifetimeStats_FullMethodName = "/hyapp.user.v1.UserService/GetUserMicLifetimeStats"
|
||||
UserService_UpdateUserProfile_FullMethodName = "/hyapp.user.v1.UserService/UpdateUserProfile"
|
||||
@ -52,6 +53,7 @@ type UserServiceClient interface {
|
||||
BusinessUserLookup(ctx context.Context, in *BusinessUserLookupRequest, opts ...grpc.CallOption) (*BusinessUserLookupResponse, error)
|
||||
GetMyProfileStats(ctx context.Context, in *GetMyProfileStatsRequest, opts ...grpc.CallOption) (*GetMyProfileStatsResponse, error)
|
||||
BatchGetUsers(ctx context.Context, in *BatchGetUsersRequest, opts ...grpc.CallOption) (*BatchGetUsersResponse, error)
|
||||
BatchGetRoomBasicUsers(ctx context.Context, in *BatchGetRoomBasicUsersRequest, opts ...grpc.CallOption) (*BatchGetRoomBasicUsersResponse, error)
|
||||
ListUserIDs(ctx context.Context, in *ListUserIDsRequest, opts ...grpc.CallOption) (*ListUserIDsResponse, error)
|
||||
GetUserMicLifetimeStats(ctx context.Context, in *GetUserMicLifetimeStatsRequest, opts ...grpc.CallOption) (*GetUserMicLifetimeStatsResponse, error)
|
||||
UpdateUserProfile(ctx context.Context, in *UpdateUserProfileRequest, opts ...grpc.CallOption) (*UpdateUserProfileResponse, error)
|
||||
@ -127,6 +129,16 @@ func (c *userServiceClient) BatchGetUsers(ctx context.Context, in *BatchGetUsers
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) BatchGetRoomBasicUsers(ctx context.Context, in *BatchGetRoomBasicUsersRequest, opts ...grpc.CallOption) (*BatchGetRoomBasicUsersResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(BatchGetRoomBasicUsersResponse)
|
||||
err := c.cc.Invoke(ctx, UserService_BatchGetRoomBasicUsers_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) ListUserIDs(ctx context.Context, in *ListUserIDsRequest, opts ...grpc.CallOption) (*ListUserIDsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListUserIDsResponse)
|
||||
@ -288,6 +300,7 @@ type UserServiceServer interface {
|
||||
BusinessUserLookup(context.Context, *BusinessUserLookupRequest) (*BusinessUserLookupResponse, error)
|
||||
GetMyProfileStats(context.Context, *GetMyProfileStatsRequest) (*GetMyProfileStatsResponse, error)
|
||||
BatchGetUsers(context.Context, *BatchGetUsersRequest) (*BatchGetUsersResponse, error)
|
||||
BatchGetRoomBasicUsers(context.Context, *BatchGetRoomBasicUsersRequest) (*BatchGetRoomBasicUsersResponse, error)
|
||||
ListUserIDs(context.Context, *ListUserIDsRequest) (*ListUserIDsResponse, error)
|
||||
GetUserMicLifetimeStats(context.Context, *GetUserMicLifetimeStatsRequest) (*GetUserMicLifetimeStatsResponse, error)
|
||||
UpdateUserProfile(context.Context, *UpdateUserProfileRequest) (*UpdateUserProfileResponse, error)
|
||||
@ -328,6 +341,9 @@ func (UnimplementedUserServiceServer) GetMyProfileStats(context.Context, *GetMyP
|
||||
func (UnimplementedUserServiceServer) BatchGetUsers(context.Context, *BatchGetUsersRequest) (*BatchGetUsersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BatchGetUsers not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) BatchGetRoomBasicUsers(context.Context, *BatchGetRoomBasicUsersRequest) (*BatchGetRoomBasicUsersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BatchGetRoomBasicUsers not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) ListUserIDs(context.Context, *ListUserIDsRequest) (*ListUserIDsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListUserIDs not implemented")
|
||||
}
|
||||
@ -484,6 +500,24 @@ func _UserService_BatchGetUsers_Handler(srv interface{}, ctx context.Context, de
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_BatchGetRoomBasicUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(BatchGetRoomBasicUsersRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserServiceServer).BatchGetRoomBasicUsers(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserService_BatchGetRoomBasicUsers_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserServiceServer).BatchGetRoomBasicUsers(ctx, req.(*BatchGetRoomBasicUsersRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_ListUserIDs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListUserIDsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -781,6 +815,10 @@ var UserService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "BatchGetUsers",
|
||||
Handler: _UserService_BatchGetUsers_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "BatchGetRoomBasicUsers",
|
||||
Handler: _UserService_BatchGetRoomBasicUsers_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListUserIDs",
|
||||
Handler: _UserService_ListUserIDs_Handler,
|
||||
|
||||
296
docs/flutter对接/Agency资料与房间Flutter对接.md
Normal file
296
docs/flutter对接/Agency资料与房间Flutter对接.md
Normal file
@ -0,0 +1,296 @@
|
||||
# Agency 资料与房间 Flutter 对接
|
||||
|
||||
## 基础约定
|
||||
|
||||
本地开发地址:
|
||||
|
||||
```text
|
||||
http://127.0.0.1:13000
|
||||
```
|
||||
|
||||
所有接口都是登录接口,需要带登录 token。
|
||||
|
||||
请求头:
|
||||
|
||||
| Header | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `Authorization` | 是 | `Bearer <access_token>`。 |
|
||||
| `X-App-Code` | 否 | App 编码,默认 `lalu`;登录态接口最终以 token 内 app_code 为准。 |
|
||||
|
||||
成功和失败都使用统一 envelope:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_xxx",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
客户端分支只判断 `code`,排查问题记录 `request_id`。
|
||||
|
||||
## 1. 查询用户所属 Agency 资料
|
||||
|
||||
地址:
|
||||
|
||||
```http
|
||||
GET /api/v1/agencies/profile
|
||||
```
|
||||
|
||||
参数:
|
||||
|
||||
| 参数 | 位置 | 必填 | 类型 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `user_id` | query | 是 | string/int64 | 被查看的 host 用户 ID。 |
|
||||
|
||||
示例:
|
||||
|
||||
```http
|
||||
GET /api/v1/agencies/profile?user_id=10001
|
||||
Authorization: Bearer <access_token>
|
||||
X-App-Code: lalu
|
||||
```
|
||||
|
||||
返回值:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_abc",
|
||||
"data": {
|
||||
"agency": {
|
||||
"agency_id": "7001",
|
||||
"owner_user_id": "99",
|
||||
"region_id": 30,
|
||||
"parent_bd_user_id": "501",
|
||||
"name": "Yumi Star Agency",
|
||||
"avatar": "https://cdn.example/agency.png",
|
||||
"host_count": 20,
|
||||
"status": "active",
|
||||
"join_enabled": true,
|
||||
"created_by_user_id": "1",
|
||||
"created_at_ms": 1710000000000,
|
||||
"updated_at_ms": 1710000001000
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
没有 active host 身份,或没有 active agency 归属时:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_abc",
|
||||
"data": {
|
||||
"agency": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `agency_id` | Agency ID,字符串。 |
|
||||
| `owner_user_id` | Agency 会长用户 ID,字符串。 |
|
||||
| `name` | Agency 自己的名称,不再读 owner 用户昵称。 |
|
||||
| `avatar` | Agency 自己的头像,不再读 owner 用户头像。 |
|
||||
| `host_count` | 当前 active host 数量。 |
|
||||
| `status` | 当前只展示 `active`。 |
|
||||
| `join_enabled` | 是否允许用户申请加入。 |
|
||||
| `created_at_ms` / `updated_at_ms` | Unix epoch milliseconds。 |
|
||||
|
||||
## 2. 查询 Agency 下所有 host 的房间
|
||||
|
||||
地址:
|
||||
|
||||
```http
|
||||
GET /api/v1/agencies/rooms
|
||||
```
|
||||
|
||||
参数:
|
||||
|
||||
| 参数 | 位置 | 必填 | 类型 | 默认 | 说明 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `user_id` | query | 是 | string/int64 | 无 | 被查看的 host 用户 ID。 |
|
||||
| `limit` | query | 否 | int | 20 | 每页数量,最大 50。 |
|
||||
| `cursor` | query | 否 | string | 空 | 下一页 cursor。 |
|
||||
| `tab` | query | 否 | string | `hot` | `hot` 或 `new`。 |
|
||||
| `query` | query | 否 | string | 空 | 搜索房间标题、房间 ID 或短号。 |
|
||||
|
||||
示例:
|
||||
|
||||
```http
|
||||
GET /api/v1/agencies/rooms?user_id=10001&tab=hot&limit=20
|
||||
Authorization: Bearer <access_token>
|
||||
X-App-Code: lalu
|
||||
```
|
||||
|
||||
返回值:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_abc",
|
||||
"data": {
|
||||
"agency_id": "7001",
|
||||
"rooms": [
|
||||
{
|
||||
"room_id": "room_101",
|
||||
"im_group_id": "room_101",
|
||||
"owner_user_id": "101",
|
||||
"title": "Agency Room",
|
||||
"cover_url": "https://cdn.example/room.png",
|
||||
"mode": "voice",
|
||||
"status": "active",
|
||||
"locked": false,
|
||||
"heat": 88,
|
||||
"online_count": 12,
|
||||
"seat_count": 8,
|
||||
"occupied_seat_count": 3,
|
||||
"visible_region_id": 30,
|
||||
"app_code": "lalu",
|
||||
"room_short_id": "M20",
|
||||
"country_code": "AE",
|
||||
"country_flag": "🇦🇪"
|
||||
}
|
||||
],
|
||||
"next_cursor": "cursor_xxx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
没有 active host 身份,或没有 active agency 归属时:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_abc",
|
||||
"data": {
|
||||
"agency_id": "",
|
||||
"rooms": [],
|
||||
"next_cursor": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `agency_id` | 当前查询到的 Agency ID;无归属时为空字符串。 |
|
||||
| `rooms` | Agency 下所有 active host 的 active 房间。 |
|
||||
| `next_cursor` | 下一页 cursor;为空表示没有下一页。 |
|
||||
| `room_id` | 房间 ID。 |
|
||||
| `im_group_id` | 腾讯云 IM 房间群 ID,进群使用这个字段。 |
|
||||
| `owner_user_id` | 房主用户 ID,字符串。 |
|
||||
| `title` | 房间名。 |
|
||||
| `cover_url` | 房间封面。 |
|
||||
| `locked` | 是否锁房。 |
|
||||
| `heat` | 房间热度。 |
|
||||
| `online_count` | 在线人数。 |
|
||||
| `seat_count` | 麦位数量。 |
|
||||
| `occupied_seat_count` | 已占用麦位数量。 |
|
||||
| `room_short_id` | 房间短号。 |
|
||||
| `country_code` / `country_flag` | 房主国家展示字段。 |
|
||||
|
||||
## 3. 修改 Agency 资料
|
||||
|
||||
地址:
|
||||
|
||||
```http
|
||||
POST /api/v1/agencies/profile/update
|
||||
```
|
||||
|
||||
权限:
|
||||
|
||||
只有当前登录用户是 active Agency owner 时可以修改。普通 host、Agency 成员、BD、非 active owner 都不能修改。
|
||||
|
||||
参数:
|
||||
|
||||
| 参数 | 位置 | 必填 | 类型 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `command_id` | body | 是 | string | 客户端生成的幂等 ID。 |
|
||||
| `name` | body | 否 | string | 新 Agency 名称。 |
|
||||
| `avatar` | body | 否 | string | 新 Agency 头像 URL。 |
|
||||
|
||||
`name` 和 `avatar` 至少传一个;传了就不能是空字符串。修改 Agency 资料不会修改 owner 用户昵称和头像。
|
||||
|
||||
示例:
|
||||
|
||||
```http
|
||||
POST /api/v1/agencies/profile/update
|
||||
Authorization: Bearer <access_token>
|
||||
X-App-Code: lalu
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"command_id": "cmd_agency_profile_001",
|
||||
"name": "New Agency Name",
|
||||
"avatar": "https://cdn.example/new-agency.png"
|
||||
}
|
||||
```
|
||||
|
||||
返回值:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_abc",
|
||||
"data": {
|
||||
"agency": {
|
||||
"agency_id": "7001",
|
||||
"owner_user_id": "42",
|
||||
"region_id": 30,
|
||||
"name": "New Agency Name",
|
||||
"avatar": "https://cdn.example/new-agency.png",
|
||||
"host_count": 20,
|
||||
"status": "active",
|
||||
"join_enabled": true,
|
||||
"created_at_ms": 1710000000000,
|
||||
"updated_at_ms": 1710000005000
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
失败返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "INVALID_ARGUMENT",
|
||||
"message": "invalid argument",
|
||||
"request_id": "req_abc"
|
||||
}
|
||||
```
|
||||
|
||||
| HTTP 状态码 | `code` | 处理方式 |
|
||||
| --- | --- | --- |
|
||||
| `400` | `INVALID_ARGUMENT` | 参数错误,例如 `user_id` 非法、`tab` 非法、`limit` 非法、缺少 `command_id`、`name/avatar` 都没传或传空。 |
|
||||
| `401` | `UNAUTHORIZED` | token 缺失、无效或过期,重新登录。 |
|
||||
| `403` | `PROFILE_REQUIRED` | 用户资料未完成,跳转资料补全。 |
|
||||
| `403` | `PERMISSION_DENIED` | 修改接口中当前用户不是 active Agency owner,不允许修改。 |
|
||||
| `404` | `NOT_FOUND` | 修改接口中 Agency 事实不存在;刷新当前用户身份后再进入页面。 |
|
||||
| `409` | `CONFLICT` | `command_id` 与已有不同命令冲突;重新生成新的 `command_id` 再提交。 |
|
||||
| `502` | `UPSTREAM_ERROR` | 服务暂不可用,可以提示稍后重试。 |
|
||||
|
||||
客户端处理规则:
|
||||
|
||||
1. 查询资料时,`agency == null` 是正常空状态,不弹错误。
|
||||
2. 查询房间时,`rooms == []` 是正常空列表,不弹错误。
|
||||
3. 修改资料成功后,用返回的 `data.agency` 刷新页面,不要用 owner 用户资料覆盖。
|
||||
4. 修改失败时保留本地未保存状态,让用户可以重试。
|
||||
5. 所有失败日志记录 `request_id`。
|
||||
|
||||
## 相关 IM
|
||||
|
||||
无。Agency 资料修改和 Agency 房间列表不会下发新的 IM;房间卡片里的 `im_group_id` 只用于进入房间时加入腾讯云 IM 房间群。
|
||||
282
docs/flutter对接/进房接口Flutter对接.md
Normal file
282
docs/flutter对接/进房接口Flutter对接.md
Normal file
@ -0,0 +1,282 @@
|
||||
# 进房接口 Flutter 对接
|
||||
|
||||
## 接口地址
|
||||
|
||||
```http
|
||||
POST /api/v1/rooms/join
|
||||
Authorization: Bearer <access_token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
新版本进房默认使用 `response_mode=lite`。`full` 仍保留给旧客户端兼容,不建议新 Flutter 首屏使用。
|
||||
|
||||
## 参数
|
||||
|
||||
Body:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `room_id` | string | 是 | 房间 ID。 |
|
||||
| `command_id` | string | 是 | 本次进房命令 ID。同一次点击超时重试复用同一个值,下一次重新进房换新值。 |
|
||||
| `role` | string | 否 | 不传默认 `audience`。房主身份由服务端按房间 owner 判断,客户端不要靠传 `owner` 获取权限。 |
|
||||
| `password` | string | 否 | 密码房传房间密码,非密码房不传或传空。 |
|
||||
| `response_mode` | string | 是 | 新版固定传 `lite`。可选值:`lite` / `full`。 |
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"room_id": "lalu_abc123",
|
||||
"command_id": "cmd_join_room_lalu_abc123_10001_1778000001000",
|
||||
"role": "audience",
|
||||
"password": "",
|
||||
"response_mode": "lite"
|
||||
}
|
||||
```
|
||||
|
||||
也支持 query 参数:
|
||||
|
||||
```http
|
||||
POST /api/v1/rooms/join?response_mode=lite
|
||||
```
|
||||
|
||||
Flutter 建议放在 body 里,避免调用层漏拼 query。
|
||||
|
||||
## 返回值
|
||||
|
||||
统一外壳:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_xxx",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
成功返回示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_xxx",
|
||||
"data": {
|
||||
"result": {
|
||||
"applied": true,
|
||||
"room_version": 8,
|
||||
"server_time_ms": 1778000001123
|
||||
},
|
||||
"room": {
|
||||
"room_id": "lalu_abc123",
|
||||
"im_group_id": "lalu_abc123",
|
||||
"room_short_id": "10001",
|
||||
"title": "Live Room",
|
||||
"cover_url": "https://cdn.example/room.png",
|
||||
"background_url": "https://cdn.example/bg.png",
|
||||
"description": "welcome",
|
||||
"owner_user_id": "10001",
|
||||
"mode": "voice",
|
||||
"status": "active",
|
||||
"chat_enabled": true,
|
||||
"locked": false,
|
||||
"heat": 88,
|
||||
"online_count": 200,
|
||||
"seat_count": 10,
|
||||
"occupied_seat_count": 2,
|
||||
"visible_region_id": 1001,
|
||||
"version": 8
|
||||
},
|
||||
"viewer": {
|
||||
"user_id": "10001",
|
||||
"role": "audience",
|
||||
"joined_at_ms": 1778000001000,
|
||||
"last_seen_at_ms": 1778000001100
|
||||
},
|
||||
"seats": [
|
||||
{
|
||||
"seat_no": 1,
|
||||
"user_id": "10002",
|
||||
"locked": false,
|
||||
"publish_state": "publishing",
|
||||
"mic_session_id": "mic_10002",
|
||||
"publish_deadline_ms": 1778000030000,
|
||||
"mic_muted": false,
|
||||
"seat_status": "publishing",
|
||||
"mic_heartbeat_at_ms": 1778000000000,
|
||||
"gift_value": 0
|
||||
},
|
||||
{
|
||||
"seat_no": 2,
|
||||
"locked": false,
|
||||
"mic_muted": false,
|
||||
"gift_value": 0
|
||||
}
|
||||
],
|
||||
"profiles": [
|
||||
{
|
||||
"user_id": "10001",
|
||||
"username": "host",
|
||||
"avatar": "https://cdn.example/avatar.png",
|
||||
"display_user_id": "10001"
|
||||
},
|
||||
{
|
||||
"user_id": "10002",
|
||||
"username": "speaker",
|
||||
"avatar": "https://cdn.example/avatar2.png",
|
||||
"display_user_id": "10002"
|
||||
}
|
||||
],
|
||||
"im": {
|
||||
"group_id": "lalu_abc123",
|
||||
"need_join_group": true
|
||||
},
|
||||
"rtc": {
|
||||
"need_token": true,
|
||||
"available": true,
|
||||
"token": {
|
||||
"sdk_app_id": 1400000000,
|
||||
"user_id": "10001",
|
||||
"rtc_user_id": "10001",
|
||||
"user_sig": "xxx",
|
||||
"expire_at_ms": 1778007200000,
|
||||
"room_id": "lalu_abc123",
|
||||
"rtc_room_id": "lalu_abc123",
|
||||
"rtc_room_id_type": "string",
|
||||
"str_room_id": "lalu_abc123",
|
||||
"app_scene": "voice_chat_room",
|
||||
"role": "user"
|
||||
}
|
||||
},
|
||||
"server_time_ms": 1778000001123
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `data.result.applied` | 本次进房是否真正写入。重复 `command_id` 重试可能为 `false`。 |
|
||||
| `data.result.room_version` | 房间版本,用于客户端状态更新判断。 |
|
||||
| `data.room.room_id` | 房间 ID。 |
|
||||
| `data.room.im_group_id` | 腾讯 IM 房间群 ID。当前通常等于 `room_id`,客户端仍以返回值为准。 |
|
||||
| `data.room.online_count` | 房间在线人数。`lite` 不返回在线用户明细,只返回人数。 |
|
||||
| `data.room.seat_count` | 麦位总数。 |
|
||||
| `data.room.occupied_seat_count` | 已占用麦位数。 |
|
||||
| `data.viewer` | 当前登录用户在房间内的 presence。 |
|
||||
| `data.viewer.role` | 当前用户房间角色,房主会由服务端返回 `owner`。 |
|
||||
| `data.seats` | 首屏麦位状态。 |
|
||||
| `data.seats[].user_id` | 麦上用户 ID;空麦不返回该字段。 |
|
||||
| `data.seats[].publish_state` | 麦上发流状态,常见值:`pending_publish` / `publishing`。 |
|
||||
| `data.seats[].mic_session_id` | 麦位发流会话 ID。麦上心跳、发流确认需要使用它。 |
|
||||
| `data.seats[].seat_status` | 麦位展示状态,常见值:`empty` / `locked` / `occupied` / `publishing` / `muted`。 |
|
||||
| `data.profiles` | 首屏基础资料,只包含房主、当前用户、麦上用户。 |
|
||||
| `data.profiles[].username` | 昵称。 |
|
||||
| `data.profiles[].avatar` | 头像。 |
|
||||
| `data.profiles[].display_user_id` | 展示 ID。 |
|
||||
| `data.im.group_id` | Flutter 调腾讯 IM `joinGroup` 使用的群 ID。 |
|
||||
| `data.im.need_join_group` | 为 `true` 时需要加入腾讯 IM 群。 |
|
||||
| `data.rtc.available` | 是否拿到 RTC 票据。 |
|
||||
| `data.rtc.token` | RTC 进房票据。`available=false` 时可能为空。 |
|
||||
| `data.rtc.reason` | RTC 不可用原因。业务进房成功时,RTC 不可用不代表进房失败。 |
|
||||
| `data.server_time_ms` | 服务端时间,UTC epoch milliseconds。 |
|
||||
|
||||
`lite` 不返回这些内容:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `contribution_rank` | 贡献榜不在进房首屏主包返回。 |
|
||||
| `profiles[].avatar_frame` | 头像框后置拉。 |
|
||||
| `profiles[].profile_card` | 资料卡后置拉。 |
|
||||
| `profiles[].vehicle` | 座驾后置拉。 |
|
||||
| `profiles[].mic_seat_animation` | 麦位动画后置拉。 |
|
||||
| `profiles[].badges` | 等级/成就徽章后置拉。 |
|
||||
| `profiles[].vip` | VIP 展示后置拉。 |
|
||||
|
||||
## 相关 IM
|
||||
|
||||
进房成功后 Flutter 执行:
|
||||
|
||||
```text
|
||||
1. POST /api/v1/rooms/join,body 传 response_mode=lite
|
||||
2. 如果 data.im.need_join_group=true,调用腾讯 IM joinGroup(data.im.group_id)
|
||||
3. joinGroup 成功或已在群内,都按进房 IM 成功处理
|
||||
4. 页面开始房间 heartbeat
|
||||
5. 如果 data.rtc.available=true,用 data.rtc.token 进入 RTC
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
| 项 | 说明 |
|
||||
| --- | --- |
|
||||
| IM 登录 | 进房接口不返回 IM UserSig。Flutter 仍然通过 `GET /api/v1/im/usersig` 获取并登录腾讯 IM。 |
|
||||
| IM 入群 | 必须先 `JoinRoom` 成功,再调腾讯 IM `joinGroup`。不要先入 IM 群。 |
|
||||
| 入房广播 | 服务端会发 `RoomUserJoined` 房间事件。Flutter 按现有房间 IM 事件逻辑展示入房飘窗。 |
|
||||
| 重复进房 | 用户重新打开房间页或重连时,服务端仍会给展示用入房事件,Flutter 正常展示即可。 |
|
||||
| 入场座驾 | `lite` 进房不携带座驾快照。座驾、头像框、资料卡、麦位动画等展示资料在进房 UI 出来后异步补齐。 |
|
||||
|
||||
## 后置资料接口
|
||||
|
||||
进房首屏出来后,再按需要异步拉展示资料:
|
||||
|
||||
```http
|
||||
GET /api/v1/users/room-display-profiles:batch?user_ids=10001,10002
|
||||
Authorization: Bearer <access_token>
|
||||
```
|
||||
|
||||
参数:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `user_ids` | string | 是 | 逗号分隔的用户 ID。也支持多个 `user_id=10001&user_id=10002`。 |
|
||||
|
||||
返回值:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "ok",
|
||||
"request_id": "req_xxx",
|
||||
"data": {
|
||||
"profiles": [
|
||||
{
|
||||
"user_id": "10001",
|
||||
"username": "host",
|
||||
"avatar": "https://cdn.example/avatar.png",
|
||||
"display_user_id": "10001",
|
||||
"avatar_frame": {},
|
||||
"profile_card": {},
|
||||
"vehicle": {},
|
||||
"mic_seat_animation": {},
|
||||
"badges": [],
|
||||
"vip": {},
|
||||
"level": {},
|
||||
"level_badges": {},
|
||||
"charm": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当前用户自己的装扮也可以后置拉:
|
||||
|
||||
```http
|
||||
GET /api/v1/appearance
|
||||
GET /api/v1/users/me/appearance
|
||||
```
|
||||
|
||||
## 常见错误
|
||||
|
||||
| code | HTTP | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `INVALID_JSON` | 400 | 请求体不是合法 JSON。 |
|
||||
| `INVALID_ARGUMENT` | 400 | 参数错误,例如 `response_mode` 不是 `lite` 或 `full`。 |
|
||||
| `UNAUTHORIZED` | 401 | 未登录或 token 无效。 |
|
||||
| `PROFILE_REQUIRED` | 403 | 用户资料未补全。 |
|
||||
| `PERMISSION_DENIED` | 403 | 密码错误、被踢/被禁等权限问题。 |
|
||||
| `ROOM_CLOSED` | 409 | 房间已关闭;非房主不能进入。 |
|
||||
| `NOT_FOUND` | 404 | 房间不存在。 |
|
||||
| `UPSTREAM_ERROR` | 502 | 上游服务异常。 |
|
||||
@ -634,6 +634,7 @@ type Agency struct {
|
||||
RegionID int64 `json:"regionId"`
|
||||
ParentBDUserID int64 `json:"parentBdUserId,string"`
|
||||
Name string `json:"name"`
|
||||
Avatar string `json:"avatar"`
|
||||
Status string `json:"status"`
|
||||
JoinEnabled bool `json:"joinEnabled"`
|
||||
MaxHosts int32 `json:"maxHosts"`
|
||||
@ -960,6 +961,7 @@ func fromProtoAgency(agency *userv1.Agency) *Agency {
|
||||
RegionID: agency.GetRegionId(),
|
||||
ParentBDUserID: agency.GetParentBdUserId(),
|
||||
Name: agency.GetName(),
|
||||
Avatar: agency.GetAvatar(),
|
||||
Status: agency.GetStatus(),
|
||||
JoinEnabled: agency.GetJoinEnabled(),
|
||||
MaxHosts: agency.GetMaxHosts(),
|
||||
|
||||
@ -213,7 +213,7 @@ type createAgencyRequest struct {
|
||||
CommandID string `json:"commandId" binding:"required"`
|
||||
OwnerUserID flexibleInt64 `json:"ownerUserId" binding:"required"`
|
||||
ParentBDUserID flexibleInt64 `json:"parentBdUserId"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Name string `json:"name"`
|
||||
JoinEnabled *bool `json:"joinEnabled" binding:"required"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
@ -301,6 +301,10 @@ func (s *Service) LaunchGame(ctx context.Context, command LaunchCommand) (Launch
|
||||
}
|
||||
token = "gt_" + randomHex(24)
|
||||
}
|
||||
if strings.EqualFold(game.AdapterType, gamedomain.AdapterZGameV1) {
|
||||
// ZGame 文档要求 js_code 是客户服务器派发的短期凭证;不能把 App access token 泄漏到三方 H5 URL。
|
||||
token = "gt_" + randomHex(24)
|
||||
}
|
||||
sessionTTL := s.config.LaunchSessionTTL
|
||||
// 三方游戏会在 H5 运行期间持续回调 token;厂商适配器可以把默认 15 分钟启动 TTL 拉长。
|
||||
if strings.EqualFold(game.AdapterType, gamedomain.AdapterYomiV4) {
|
||||
@ -995,16 +999,15 @@ func buildLaunchURL(game gamedomain.LaunchableGame, session gamedomain.LaunchSes
|
||||
return parsed.String(), nil
|
||||
}
|
||||
if strings.EqualFold(game.AdapterType, gamedomain.AdapterZGameV1) {
|
||||
// ZGame 客户端通过 ThirdPlatformBridge.login 拿 js_code;为避免 App 发版,远程桥接脚本直接从启动配置读取同一个短期 token。
|
||||
// laluparty 是厂商文档约定通道;H5 通过 App 注入的 ThirdPlatformBridge 取用户信息和 login js_code。
|
||||
// 启动 URL 仍带 open_id/js_code,供 App Bridge 复用同一份短期凭证,避免客户端再发起一次派码请求。
|
||||
config := zgameConfigFromPlatform(game)
|
||||
openID := externalUserID(session, config.UIDMode)
|
||||
query.Set("openId", openID)
|
||||
query.Set("channelName", "laluparty")
|
||||
query.Set("open_id", openID)
|
||||
query.Set("userId", openID)
|
||||
query.Set("uid", openID)
|
||||
query.Set("code", token)
|
||||
query.Set("openId", openID)
|
||||
query.Set("js_code", token)
|
||||
query.Set("session", token)
|
||||
query.Set("jscode", token)
|
||||
query.Set("gameId", strings.TrimSpace(session.ProviderGameID))
|
||||
query.Set("game_id", strings.TrimSpace(session.ProviderGameID))
|
||||
callbackBase := config.CallbackBaseValue()
|
||||
|
||||
@ -630,14 +630,19 @@ func TestLaunchGameBuildsZGameURL(t *testing.T) {
|
||||
if parsed.Scheme+"://"+parsed.Host+parsed.Path != "https://zgame.example/h5/1001" {
|
||||
t.Fatalf("zgame launch url must use per-game configured url: %s", result.LaunchURL)
|
||||
}
|
||||
jsCode := parsed.Query().Get("js_code")
|
||||
if jsCode == "" || !strings.HasPrefix(jsCode, "gt_") || jsCode == token {
|
||||
t.Fatalf("zgame launch must expose a scoped js_code instead of app token: %q", jsCode)
|
||||
}
|
||||
if repo.session.LaunchTokenHash != stableHash(jsCode) {
|
||||
t.Fatalf("zgame launch session must be bound to scoped js_code")
|
||||
}
|
||||
expected := map[string]string{
|
||||
"channelName": "laluparty",
|
||||
"openId": "420001",
|
||||
"open_id": "420001",
|
||||
"userId": "420001",
|
||||
"uid": "420001",
|
||||
"code": token,
|
||||
"js_code": token,
|
||||
"session": token,
|
||||
"js_code": jsCode,
|
||||
"jscode": jsCode,
|
||||
"gameId": "1001",
|
||||
"game_id": "1001",
|
||||
"callbackBase": "https://api.example.test/api/v1/zgame/callback",
|
||||
@ -657,6 +662,11 @@ func TestLaunchGameBuildsZGameURL(t *testing.T) {
|
||||
t.Fatalf("zgame launch query %s mismatch: got %q want %q url=%s", key, got, want, result.LaunchURL)
|
||||
}
|
||||
}
|
||||
for _, key := range []string{"token", "code", "session", "cv", "channel_name"} {
|
||||
if got := parsed.Query().Get(key); got != "" {
|
||||
t.Fatalf("zgame launch query must not expose %s=%q url=%s", key, got, result.LaunchURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLaunchGameRequiresBaishunLaunchURL(t *testing.T) {
|
||||
|
||||
@ -59,6 +59,10 @@ func zgameConfigFromPlatform(value any) zgameAdapterConfig {
|
||||
var config zgameAdapterConfig
|
||||
_ = json.Unmarshal([]byte(strings.TrimSpace(raw)), &config)
|
||||
config.UIDMode = strings.ToLower(strings.TrimSpace(config.UIDMode))
|
||||
if config.UIDMode == "" {
|
||||
// laluparty 游戏侧展示和签名都用短号作为 open_id;历史配置未写 uid_mode 时按文档默认走 display_user_id。
|
||||
config.UIDMode = "display_user_id"
|
||||
}
|
||||
config.DefaultLang = strings.TrimSpace(config.DefaultLang)
|
||||
config.LaunchURLTemplate = strings.TrimSpace(config.LaunchURLTemplate)
|
||||
config.CallbackBase = strings.TrimSpace(firstNonEmpty(config.CallbackBase, config.CallbackBaseAlias))
|
||||
@ -159,7 +163,7 @@ func (s *Service) handleZGameLogin(ctx context.Context, app string, config zgame
|
||||
if err != nil {
|
||||
return zgameAdapterError(zgameCodeFromError(err), zgameMessageFromError(err), true, "")
|
||||
}
|
||||
raw, contentType := zgameJSON(zgameCodeOK, "success", zgameLoginData(session, config, jsCode, snapshot, s.now()))
|
||||
raw, contentType := zgameJSON(zgameCodeOK, "success", zgameLoginData(session, config, openID, jsCode, snapshot, s.now()))
|
||||
return raw, contentType, strconv.Itoa(zgameCodeOK), true, "", nil
|
||||
}
|
||||
|
||||
@ -339,7 +343,7 @@ func (s *Service) validZGameSession(ctx context.Context, app string, platformCod
|
||||
if token == "" {
|
||||
return gamedomain.LaunchSession{}, xerr.New(xerr.Unauthorized, "session invalid")
|
||||
}
|
||||
// 当前 ZGame 不要求 App 原生生成一次性 jscode;优先消费 App access token,远程桥接脚本即可免发版接入。
|
||||
// 新版启动链路使用服务端短期 js_code;保留 JWT 兼容旧测试链接,避免已打开的 H5 立即失效。
|
||||
if strings.Count(token, ".") == 2 {
|
||||
if session, err := s.appSessionFromAccessToken(app, token); err == nil {
|
||||
return session, nil
|
||||
@ -377,8 +381,11 @@ func zgameSignatureValid(openID string, session string, signature string, secret
|
||||
return subtle.ConstantTimeCompare([]byte(strings.ToLower(signature)), []byte(expected)) == 1
|
||||
}
|
||||
|
||||
func zgameLoginData(session gamedomain.LaunchSession, config zgameAdapterConfig, token string, snapshot yomiUserSnapshot, now time.Time) map[string]any {
|
||||
openID := externalUserID(session, config.UIDMode)
|
||||
func zgameLoginData(session gamedomain.LaunchSession, config zgameAdapterConfig, requestedOpenID string, token string, snapshot yomiUserSnapshot, now time.Time) map[string]any {
|
||||
openID := strings.TrimSpace(requestedOpenID)
|
||||
if openID == "" {
|
||||
openID = externalUserID(session, config.UIDMode)
|
||||
}
|
||||
return map[string]any{
|
||||
"session": token,
|
||||
"session_expired": zgameSessionTTLMS(session, now),
|
||||
|
||||
@ -45,6 +45,7 @@ type RoomGuardClient interface {
|
||||
// RoomQueryClient 抽象 gateway 对 room-service 读模型查询的依赖。
|
||||
type RoomQueryClient interface {
|
||||
ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (*roomv1.ListRoomsResponse, error)
|
||||
ListRoomsByOwners(ctx context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error)
|
||||
ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error)
|
||||
ListRoomGiftLeaderboard(ctx context.Context, req *roomv1.ListRoomGiftLeaderboardRequest) (*roomv1.ListRoomGiftLeaderboardResponse, error)
|
||||
GetMyRoom(ctx context.Context, req *roomv1.GetMyRoomRequest) (*roomv1.GetMyRoomResponse, error)
|
||||
@ -197,6 +198,10 @@ func (c *grpcRoomQueryClient) ListRooms(ctx context.Context, req *roomv1.ListRoo
|
||||
return c.client.ListRooms(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcRoomQueryClient) ListRoomsByOwners(ctx context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
return c.client.ListRoomsByOwners(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcRoomQueryClient) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
return c.client.ListRoomFeeds(ctx, req)
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ type UserProfileClient interface {
|
||||
BusinessUserLookup(ctx context.Context, req *userv1.BusinessUserLookupRequest) (*userv1.BusinessUserLookupResponse, error)
|
||||
GetMyProfileStats(ctx context.Context, req *userv1.GetMyProfileStatsRequest) (*userv1.GetMyProfileStatsResponse, error)
|
||||
BatchGetUsers(ctx context.Context, req *userv1.BatchGetUsersRequest) (*userv1.BatchGetUsersResponse, error)
|
||||
BatchGetRoomBasicUsers(ctx context.Context, req *userv1.BatchGetRoomBasicUsersRequest) (*userv1.BatchGetRoomBasicUsersResponse, error)
|
||||
CompleteOnboarding(ctx context.Context, req *userv1.CompleteOnboardingRequest) (*userv1.CompleteOnboardingResponse, error)
|
||||
UpdateUserProfile(ctx context.Context, req *userv1.UpdateUserProfileRequest) (*userv1.UpdateUserProfileResponse, error)
|
||||
UpdateUserProfileBackground(ctx context.Context, req *userv1.UpdateUserProfileBackgroundRequest) (*userv1.UpdateUserProfileBackgroundResponse, error)
|
||||
@ -121,6 +122,7 @@ type UserHostClient interface {
|
||||
ListActiveCoinSellersInMyRegion(ctx context.Context, req *userv1.ListActiveCoinSellersInMyRegionRequest) (*userv1.ListActiveCoinSellersInMyRegionResponse, error)
|
||||
GetUserRoleSummary(ctx context.Context, req *userv1.GetUserRoleSummaryRequest) (*userv1.GetUserRoleSummaryResponse, error)
|
||||
GetAgency(ctx context.Context, req *userv1.GetAgencyRequest) (*userv1.GetAgencyResponse, error)
|
||||
UpdateAgencyProfile(ctx context.Context, req *userv1.UpdateAgencyProfileRequest) (*userv1.UpdateAgencyProfileResponse, error)
|
||||
CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error)
|
||||
GetAgencyMembers(ctx context.Context, req *userv1.GetAgencyMembersRequest) (*userv1.GetAgencyMembersResponse, error)
|
||||
GetAgencyApplications(ctx context.Context, req *userv1.GetAgencyApplicationsRequest) (*userv1.GetAgencyApplicationsResponse, error)
|
||||
@ -354,6 +356,10 @@ func (c *grpcUserProfileClient) BatchGetUsers(ctx context.Context, req *userv1.B
|
||||
return c.client.BatchGetUsers(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserProfileClient) BatchGetRoomBasicUsers(ctx context.Context, req *userv1.BatchGetRoomBasicUsersRequest) (*userv1.BatchGetRoomBasicUsersResponse, error) {
|
||||
return c.client.BatchGetRoomBasicUsers(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserProfileClient) CompleteOnboarding(ctx context.Context, req *userv1.CompleteOnboardingRequest) (*userv1.CompleteOnboardingResponse, error) {
|
||||
return c.client.CompleteOnboarding(ctx, req)
|
||||
}
|
||||
@ -570,6 +576,10 @@ func (c *grpcUserHostClient) GetAgency(ctx context.Context, req *userv1.GetAgenc
|
||||
return c.client.GetAgency(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserHostClient) UpdateAgencyProfile(ctx context.Context, req *userv1.UpdateAgencyProfileRequest) (*userv1.UpdateAgencyProfileResponse, error) {
|
||||
return c.client.UpdateAgencyProfile(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserHostClient) CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) {
|
||||
return c.client.CheckBusinessCapability(ctx, req)
|
||||
}
|
||||
|
||||
@ -113,6 +113,10 @@ func (f *fakeInviteActivityUserProfileClient) BatchGetUsers(_ context.Context, r
|
||||
return &userv1.BatchGetUsersResponse{Users: f.users}, nil
|
||||
}
|
||||
|
||||
func (f *fakeInviteActivityUserProfileClient) BatchGetRoomBasicUsers(context.Context, *userv1.BatchGetRoomBasicUsersRequest) (*userv1.BatchGetRoomBasicUsersResponse, error) {
|
||||
return &userv1.BatchGetRoomBasicUsersResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeInviteActivityUserProfileClient) GetUser(context.Context, *userv1.GetUserRequest) (*userv1.GetUserResponse, error) {
|
||||
return &userv1.GetUserResponse{}, nil
|
||||
}
|
||||
|
||||
@ -183,6 +183,10 @@ func (f *fakeUserLeaderboardRoomQueryClient) ListRooms(context.Context, *roomv1.
|
||||
return &roomv1.ListRoomsResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserLeaderboardRoomQueryClient) ListRoomsByOwners(context.Context, *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
return &roomv1.ListRoomsResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserLeaderboardRoomQueryClient) ListRoomFeeds(context.Context, *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
return &roomv1.ListRoomsResponse{}, nil
|
||||
}
|
||||
|
||||
@ -83,6 +83,9 @@ type UserHandlers struct {
|
||||
GetMyRoleSummary http.HandlerFunc
|
||||
SearchHostAgencies http.HandlerFunc
|
||||
ApplyToHostAgency http.HandlerFunc
|
||||
GetAgencyProfile http.HandlerFunc
|
||||
ListAgencyRooms http.HandlerFunc
|
||||
UpdateAgencyProfile http.HandlerFunc
|
||||
GetHostCenterAgency http.HandlerFunc
|
||||
GetHostCenterPlatformPolicy http.HandlerFunc
|
||||
GetAgencyCenterOverview http.HandlerFunc
|
||||
@ -436,6 +439,9 @@ func (r routes) registerUserRoutes() {
|
||||
r.profile("/users/me/role-summary", "", h.GetMyRoleSummary)
|
||||
r.profile("/host/agencies/search", http.MethodGet, h.SearchHostAgencies)
|
||||
r.profile("/host/agency-applications", http.MethodPost, h.ApplyToHostAgency)
|
||||
r.profile("/agencies/profile", http.MethodGet, h.GetAgencyProfile)
|
||||
r.profile("/agencies/rooms", http.MethodGet, h.ListAgencyRooms)
|
||||
r.profile("/agencies/profile/update", http.MethodPost, h.UpdateAgencyProfile)
|
||||
r.profile("/host-center/agency", http.MethodGet, h.GetHostCenterAgency)
|
||||
r.profile("/host-center/platform-policy", http.MethodGet, h.GetHostCenterPlatformPolicy)
|
||||
r.profile("/agency-center/overview", http.MethodGet, h.GetAgencyCenterOverview)
|
||||
|
||||
@ -319,6 +319,8 @@ type fakeUserProfileClient struct {
|
||||
lastStats *userv1.GetMyProfileStatsRequest
|
||||
lastBatch *userv1.BatchGetUsersRequest
|
||||
batchRequests []*userv1.BatchGetUsersRequest
|
||||
lastRoomBasicBatch *userv1.BatchGetRoomBasicUsersRequest
|
||||
roomBasicRequests []*userv1.BatchGetRoomBasicUsersRequest
|
||||
getRequests []*userv1.GetUserRequest
|
||||
lastComplete *userv1.CompleteOnboardingRequest
|
||||
lastUpdate *userv1.UpdateUserProfileRequest
|
||||
@ -379,6 +381,7 @@ type fakeUserIdentityClient struct {
|
||||
|
||||
type fakeRoomQueryClient struct {
|
||||
lastList *roomv1.ListRoomsRequest
|
||||
lastListOwners *roomv1.ListRoomsByOwnersRequest
|
||||
lastFeeds *roomv1.ListRoomFeedsRequest
|
||||
lastMyRoom *roomv1.GetMyRoomRequest
|
||||
lastCurrent *roomv1.GetCurrentRoomRequest
|
||||
@ -388,6 +391,7 @@ type fakeRoomQueryClient struct {
|
||||
lastOnline *roomv1.ListRoomOnlineUsersRequest
|
||||
lastBannedUsers *roomv1.ListRoomBannedUsersRequest
|
||||
resp *roomv1.ListRoomsResponse
|
||||
ownersResp *roomv1.ListRoomsResponse
|
||||
feedsResp *roomv1.ListRoomsResponse
|
||||
myRoomResp *roomv1.GetMyRoomResponse
|
||||
currentResp *roomv1.GetCurrentRoomResponse
|
||||
@ -397,6 +401,7 @@ type fakeRoomQueryClient struct {
|
||||
onlineResp *roomv1.ListRoomOnlineUsersResponse
|
||||
bannedUsersResp *roomv1.ListRoomBannedUsersResponse
|
||||
err error
|
||||
ownersErr error
|
||||
feedsErr error
|
||||
myRoomErr error
|
||||
currentErr error
|
||||
@ -507,6 +512,9 @@ type fakeUserHostClient struct {
|
||||
lastGetAgency *userv1.GetAgencyRequest
|
||||
getAgencyResp *userv1.GetAgencyResponse
|
||||
getAgencyErr error
|
||||
lastUpdateAgency *userv1.UpdateAgencyProfileRequest
|
||||
updateAgencyResp *userv1.UpdateAgencyProfileResponse
|
||||
updateAgencyErr error
|
||||
lastMembers *userv1.GetAgencyMembersRequest
|
||||
membersResp *userv1.GetAgencyMembersResponse
|
||||
membersErr error
|
||||
@ -977,6 +985,32 @@ func (f *fakeUserProfileClient) BatchGetUsers(_ context.Context, req *userv1.Bat
|
||||
return &userv1.BatchGetUsersResponse{Users: users}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserProfileClient) BatchGetRoomBasicUsers(_ context.Context, req *userv1.BatchGetRoomBasicUsersRequest) (*userv1.BatchGetRoomBasicUsersResponse, error) {
|
||||
f.lastRoomBasicBatch = req
|
||||
f.roomBasicRequests = append(f.roomBasicRequests, req)
|
||||
users := make(map[int64]*userv1.RoomBasicUser, len(req.GetUserIds()))
|
||||
for _, userID := range req.GetUserIds() {
|
||||
if f.usersByID != nil {
|
||||
if user, ok := f.usersByID[userID]; ok {
|
||||
users[userID] = &userv1.RoomBasicUser{
|
||||
UserId: user.GetUserId(),
|
||||
Username: user.GetUsername(),
|
||||
Avatar: user.GetAvatar(),
|
||||
DisplayUserId: user.GetDisplayUserId(),
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
users[userID] = &userv1.RoomBasicUser{
|
||||
UserId: userID,
|
||||
Username: "user-" + strconv.FormatInt(userID, 10),
|
||||
Avatar: "https://cdn.example/avatar.png",
|
||||
DisplayUserId: strconv.FormatInt(100000+userID, 10),
|
||||
}
|
||||
}
|
||||
return &userv1.BatchGetRoomBasicUsersResponse{Users: users}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserProfileClient) CompleteOnboarding(_ context.Context, req *userv1.CompleteOnboardingRequest) (*userv1.CompleteOnboardingResponse, error) {
|
||||
f.lastComplete = req
|
||||
if f.completeErr != nil {
|
||||
@ -1205,6 +1239,17 @@ func (f *fakeRoomQueryClient) ListRooms(_ context.Context, req *roomv1.ListRooms
|
||||
return &roomv1.ListRoomsResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeRoomQueryClient) ListRoomsByOwners(_ context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
f.lastListOwners = req
|
||||
if f.ownersErr != nil {
|
||||
return nil, f.ownersErr
|
||||
}
|
||||
if f.ownersResp != nil {
|
||||
return f.ownersResp, nil
|
||||
}
|
||||
return &roomv1.ListRoomsResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeRoomQueryClient) ListRoomFeeds(_ context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
f.lastFeeds = req
|
||||
if f.feedsErr != nil {
|
||||
@ -1751,6 +1796,23 @@ func (f *fakeUserHostClient) GetAgency(_ context.Context, req *userv1.GetAgencyR
|
||||
return &userv1.GetAgencyResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserHostClient) UpdateAgencyProfile(_ context.Context, req *userv1.UpdateAgencyProfileRequest) (*userv1.UpdateAgencyProfileResponse, error) {
|
||||
f.lastUpdateAgency = req
|
||||
if f.updateAgencyErr != nil {
|
||||
return nil, f.updateAgencyErr
|
||||
}
|
||||
if f.updateAgencyResp != nil {
|
||||
return f.updateAgencyResp, nil
|
||||
}
|
||||
return &userv1.UpdateAgencyProfileResponse{Agency: &userv1.Agency{
|
||||
AgencyId: req.GetAgencyId(),
|
||||
OwnerUserId: req.GetOperatorUserId(),
|
||||
Name: req.GetName(),
|
||||
Avatar: req.GetAvatar(),
|
||||
Status: "active",
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserHostClient) CheckBusinessCapability(_ context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) {
|
||||
f.lastCapability = req
|
||||
f.capabilities = append(f.capabilities, req.GetCapability())
|
||||
@ -3281,6 +3343,96 @@ func TestJoinRoomReturnsInitialDataWithIMGroupRTCTokenAndProfiles(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoinRoomLiteReturnsFirstScreenFieldsWithoutDisplayHydration(t *testing.T) {
|
||||
roomClient := &fakeRoomClient{joinResp: &roomv1.JoinRoomResponse{
|
||||
Result: &roomv1.CommandResult{Applied: true, RoomVersion: 8, ServerTimeMs: 1_700_000_010_123},
|
||||
User: &roomv1.RoomUser{UserId: 42, Role: "audience", JoinedAtMs: 1_700_000_010_000, LastSeenAtMs: 1_700_000_010_100},
|
||||
Room: &roomv1.RoomSnapshot{
|
||||
RoomId: "room_lite",
|
||||
OwnerUserId: 101,
|
||||
Mode: "voice",
|
||||
Status: "active",
|
||||
ChatEnabled: true,
|
||||
MicSeats: []*roomv1.SeatState{{SeatNo: 1, UserId: 102, PublishState: "publishing"}, {SeatNo: 2, Locked: true}},
|
||||
GiftRank: []*roomv1.RankItem{{UserId: 301, Score: 900, GiftValue: 900}},
|
||||
RoomExt: map[string]string{"title": "Lite Room", "cover_url": "https://cdn.example/lite.png"},
|
||||
Heat: 88,
|
||||
Version: 8,
|
||||
RoomShortId: "100102",
|
||||
OnlineCount: 200,
|
||||
Locked: true,
|
||||
},
|
||||
}}
|
||||
walletClient := &fakeWalletClient{batchEquippedResp: &walletv1.BatchGetUserEquippedResourcesResponse{}}
|
||||
profileClient := &fakeUserProfileClient{}
|
||||
handler := NewHandlerWithConfig(roomClient, nil, nil, nil, TencentIMConfig{}, profileClient)
|
||||
handler.SetWalletClient(walletClient)
|
||||
handler.SetTencentRTC(TencentRTCConfig{
|
||||
Enabled: true,
|
||||
SDKAppID: 1400000000,
|
||||
SecretKey: "secret",
|
||||
UserSigTTL: 2 * time.Hour,
|
||||
RoomIDType: "string",
|
||||
AppScene: "voice_chat_room",
|
||||
})
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/rooms/join", bytes.NewReader([]byte(`{"room_id":"room_lite","command_id":"cmd-join-lite","role":"audience","response_mode":"lite"}`)))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-join-lite")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if roomClient.lastJoin == nil || roomClient.lastJoin.GetResponseMode() != "lite" || roomClient.lastJoin.GetEntryVehicle() != nil {
|
||||
t.Fatalf("lite join must pass response_mode and skip entry vehicle: %+v", roomClient.lastJoin)
|
||||
}
|
||||
if len(walletClient.batchEquippedRequests) != 0 {
|
||||
t.Fatalf("lite join must not query wallet appearance or vehicle resources: %+v", walletClient.batchEquippedRequests)
|
||||
}
|
||||
if len(profileClient.batchRequests) != 0 {
|
||||
t.Fatalf("lite join must not call full BatchGetUsers: %+v", profileClient.batchRequests)
|
||||
}
|
||||
if profileClient.lastRoomBasicBatch == nil || strings.Join(int64SliceToStrings(profileClient.lastRoomBasicBatch.GetUserIds()), ",") != "101,42,102" {
|
||||
t.Fatalf("lite join must batch only owner/viewer/mic basic users: %+v", profileClient.lastRoomBasicBatch)
|
||||
}
|
||||
|
||||
var response httpkit.ResponseEnvelope
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("decode lite join response failed: %v", err)
|
||||
}
|
||||
data := response.Data.(map[string]any)
|
||||
if _, exists := data["contribution_rank"]; exists {
|
||||
t.Fatalf("lite join must not include contribution rank: %+v", data["contribution_rank"])
|
||||
}
|
||||
room := data["room"].(map[string]any)
|
||||
if room["room_id"] != "room_lite" || room["online_count"].(float64) != 200 {
|
||||
t.Fatalf("lite join must keep core room fields and online_count: %+v", room)
|
||||
}
|
||||
profiles := data["profiles"].([]any)
|
||||
if len(profiles) != 3 {
|
||||
t.Fatalf("lite join must include basic profiles for owner/viewer/mic only: %+v", profiles)
|
||||
}
|
||||
viewerProfile := map[string]any{}
|
||||
for _, item := range profiles {
|
||||
profile := item.(map[string]any)
|
||||
if profile["user_id"] == "42" {
|
||||
viewerProfile = profile
|
||||
}
|
||||
if profile["user_id"] == "301" {
|
||||
t.Fatalf("lite join must not hydrate contribution-rank users: %+v", profiles)
|
||||
}
|
||||
}
|
||||
if viewerProfile["username"] != "user-42" || viewerProfile["avatar"] == "" || viewerProfile["display_user_id"] == "" {
|
||||
t.Fatalf("lite profile must carry only basic display fields: %+v", viewerProfile)
|
||||
}
|
||||
if _, exists := viewerProfile["avatar_frame"]; exists {
|
||||
t.Fatalf("lite profile must not carry appearance fields: %+v", viewerProfile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRoomsUsesUserRegionFromUserService(t *testing.T) {
|
||||
profileClient := &fakeUserProfileClient{regionID: 1001}
|
||||
regionClient := &fakeUserRegionClient{resp: &userv1.RegionResponse{Region: &userv1.Region{
|
||||
@ -5474,6 +5626,7 @@ func TestHostCenterAgencyUsesCurrentHostAgencyAndOwnerProfile(t *testing.T) {
|
||||
OwnerUserId: 99,
|
||||
RegionId: 30,
|
||||
Name: "Yumi Star Agency",
|
||||
Avatar: "https://cdn.example/agency.png",
|
||||
Status: "active",
|
||||
}},
|
||||
}
|
||||
@ -5508,11 +5661,198 @@ func TestHostCenterAgencyUsesCurrentHostAgencyAndOwnerProfile(t *testing.T) {
|
||||
}
|
||||
data := response.Data.(map[string]any)
|
||||
agency := data["agency"].(map[string]any)
|
||||
if agency["agency_id"] != "7001" || agency["short_id"] != "163003" || agency["avatar"] != "https://cdn.example/agency-owner.png" || agency["name"] != "Yumi Star Agency" {
|
||||
if agency["agency_id"] != "7001" || agency["short_id"] != "163003" || agency["avatar"] != "https://cdn.example/agency.png" || agency["name"] != "Yumi Star Agency" {
|
||||
t.Fatalf("host center agency response mismatch: %+v", agency)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAgencyProfileReturnsIndependentAgencyAvatar(t *testing.T) {
|
||||
hostClient := &fakeUserHostClient{
|
||||
hostProfile: &userv1.HostProfile{UserId: 88, Status: "active", RegionId: 30, CurrentAgencyId: 7001},
|
||||
getAgencyResp: &userv1.GetAgencyResponse{Agency: &userv1.Agency{
|
||||
AgencyId: 7001,
|
||||
OwnerUserId: 99,
|
||||
RegionId: 30,
|
||||
Name: "Independent Agency",
|
||||
Avatar: "https://cdn.example/agency-avatar.png",
|
||||
HostCount: 3,
|
||||
Status: "active",
|
||||
JoinEnabled: true,
|
||||
}},
|
||||
}
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
|
||||
handler.SetUserHostClient(hostClient)
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/agencies/profile?user_id=88", nil)
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-agency-profile")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if hostClient.lastHost == nil || hostClient.lastHost.GetUserId() != 88 || hostClient.lastGetAgency == nil || hostClient.lastGetAgency.GetAgencyId() != 7001 {
|
||||
t.Fatalf("agency profile upstream requests mismatch: host=%+v agency=%+v", hostClient.lastHost, hostClient.lastGetAgency)
|
||||
}
|
||||
var response httpkit.ResponseEnvelope
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("decode response failed: %v", err)
|
||||
}
|
||||
data := response.Data.(map[string]any)
|
||||
agency := data["agency"].(map[string]any)
|
||||
if agency["agency_id"] != "7001" || agency["owner_user_id"] != "99" || agency["name"] != "Independent Agency" || agency["avatar"] != "https://cdn.example/agency-avatar.png" || agency["host_count"] != float64(3) {
|
||||
t.Fatalf("agency profile response mismatch: %+v", agency)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAgencyProfileReturnsNullWhenTargetNotActiveHost(t *testing.T) {
|
||||
hostClient := &fakeUserHostClient{hostProfile: &userv1.HostProfile{UserId: 88, Status: "inactive", RegionId: 30, CurrentAgencyId: 7001}}
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
|
||||
handler.SetUserHostClient(hostClient)
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/agencies/profile?user_id=88", nil)
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-agency-profile-empty")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if hostClient.lastGetAgency != nil {
|
||||
t.Fatalf("inactive host must not fetch agency: %+v", hostClient.lastGetAgency)
|
||||
}
|
||||
var response httpkit.ResponseEnvelope
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("decode response failed: %v", err)
|
||||
}
|
||||
data := response.Data.(map[string]any)
|
||||
if data["agency"] != nil {
|
||||
t.Fatalf("inactive host must return null agency: %+v", data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAgencyRoomsUsesActiveAgencyHosts(t *testing.T) {
|
||||
hostClient := &fakeUserHostClient{
|
||||
hostProfile: &userv1.HostProfile{UserId: 88, Status: "active", RegionId: 30, CurrentAgencyId: 7001},
|
||||
getAgencyResp: &userv1.GetAgencyResponse{Agency: &userv1.Agency{
|
||||
AgencyId: 7001,
|
||||
OwnerUserId: 99,
|
||||
RegionId: 30,
|
||||
Name: "Independent Agency",
|
||||
Avatar: "https://cdn.example/agency-avatar.png",
|
||||
Status: "active",
|
||||
}},
|
||||
membersResp: &userv1.GetAgencyMembersResponse{Memberships: []*userv1.AgencyMembership{
|
||||
{MembershipId: 1, AgencyId: 7001, HostUserId: 101, Status: "active"},
|
||||
{MembershipId: 2, AgencyId: 7001, HostUserId: 102, Status: "inactive"},
|
||||
{MembershipId: 3, AgencyId: 7001, HostUserId: 99, Status: "active"},
|
||||
}},
|
||||
}
|
||||
roomClient := &fakeRoomQueryClient{ownersResp: &roomv1.ListRoomsResponse{
|
||||
Rooms: []*roomv1.RoomListItem{{
|
||||
RoomId: "room-101",
|
||||
OwnerUserId: 101,
|
||||
Title: "Agency Room",
|
||||
CoverUrl: "https://cdn.example/room.png",
|
||||
Mode: "voice",
|
||||
Status: "active",
|
||||
Heat: 88,
|
||||
OnlineCount: 12,
|
||||
SeatCount: 8,
|
||||
OccupiedSeatCount: 3,
|
||||
RoomShortId: "M20",
|
||||
CountryCode: "AE",
|
||||
}},
|
||||
NextCursor: "next-owner-room",
|
||||
}}
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
|
||||
handler.SetUserHostClient(hostClient)
|
||||
handler.SetRoomQueryClient(roomClient)
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/agencies/rooms?user_id=88&tab=new&limit=120&cursor=cursor-1&query=karaoke", nil)
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-agency-rooms")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if hostClient.lastMembers == nil || hostClient.lastMembers.GetAgencyId() != 7001 || hostClient.lastMembers.GetStatus() != "active" {
|
||||
t.Fatalf("agency members request mismatch: %+v", hostClient.lastMembers)
|
||||
}
|
||||
if roomClient.lastListOwners == nil {
|
||||
t.Fatal("agency rooms must call ListRoomsByOwners")
|
||||
}
|
||||
ownerIDs := roomClient.lastListOwners.GetOwnerUserIds()
|
||||
if len(ownerIDs) != 2 || ownerIDs[0] != 99 || ownerIDs[1] != 101 {
|
||||
t.Fatalf("owner ids mismatch: got %v request=%+v", roomClient.lastListOwners.GetOwnerUserIds(), roomClient.lastListOwners)
|
||||
}
|
||||
if roomClient.lastListOwners.GetViewerUserId() != 42 || roomClient.lastListOwners.GetTab() != "new" || roomClient.lastListOwners.GetLimit() != 50 || roomClient.lastListOwners.GetCursor() != "cursor-1" || roomClient.lastListOwners.GetQuery() != "karaoke" {
|
||||
t.Fatalf("agency rooms request mismatch: %+v", roomClient.lastListOwners)
|
||||
}
|
||||
var response httpkit.ResponseEnvelope
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("decode response failed: %v", err)
|
||||
}
|
||||
data := response.Data.(map[string]any)
|
||||
rooms := data["rooms"].([]any)
|
||||
first := rooms[0].(map[string]any)
|
||||
if data["agency_id"] != "7001" || data["next_cursor"] != "next-owner-room" || first["room_id"] != "room-101" || first["owner_user_id"] != "101" || first["country_flag"] != "🇦🇪" {
|
||||
t.Fatalf("agency rooms response mismatch: %+v", response)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateAgencyProfileForwardsOwnerCommand(t *testing.T) {
|
||||
hostClient := &fakeUserHostClient{
|
||||
roleSummary: &userv1.UserRoleSummary{UserId: 42, IsAgency: true, AgencyId: 7001},
|
||||
getAgencyResp: &userv1.GetAgencyResponse{Agency: &userv1.Agency{AgencyId: 7001, OwnerUserId: 42, RegionId: 30, Name: "Old Agency", Avatar: "https://cdn.example/old.png", Status: "active"}},
|
||||
updateAgencyResp: &userv1.UpdateAgencyProfileResponse{Agency: &userv1.Agency{
|
||||
AgencyId: 7001,
|
||||
OwnerUserId: 42,
|
||||
RegionId: 30,
|
||||
Name: "New Agency",
|
||||
Avatar: "https://cdn.example/new.png",
|
||||
Status: "active",
|
||||
}},
|
||||
}
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
|
||||
handler.SetUserHostClient(hostClient)
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/agencies/profile/update", bytes.NewReader([]byte(`{"command_id":"cmd-agency-profile","name":" New Agency ","avatar":" https://cdn.example/new.png "}`)))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-agency-profile-update")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if hostClient.lastUpdateAgency == nil ||
|
||||
hostClient.lastUpdateAgency.GetCommandId() != "cmd-agency-profile" ||
|
||||
hostClient.lastUpdateAgency.GetOperatorUserId() != 42 ||
|
||||
hostClient.lastUpdateAgency.GetAgencyId() != 7001 ||
|
||||
hostClient.lastUpdateAgency.GetName() != "New Agency" ||
|
||||
hostClient.lastUpdateAgency.GetAvatar() != "https://cdn.example/new.png" {
|
||||
t.Fatalf("update agency profile request mismatch: %+v", hostClient.lastUpdateAgency)
|
||||
}
|
||||
var response httpkit.ResponseEnvelope
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("decode response failed: %v", err)
|
||||
}
|
||||
data := response.Data.(map[string]any)
|
||||
agency := data["agency"].(map[string]any)
|
||||
if agency["agency_id"] != "7001" || agency["name"] != "New Agency" || agency["avatar"] != "https://cdn.example/new.png" {
|
||||
t.Fatalf("update agency profile response mismatch: %+v", agency)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostCenterPlatformPolicyUsesCurrentHostRegion(t *testing.T) {
|
||||
hostClient := &fakeUserHostClient{hostProfile: &userv1.HostProfile{
|
||||
UserId: 42,
|
||||
|
||||
@ -37,6 +37,10 @@ const (
|
||||
// 机器人房标记来自 room-service RoomExt;gateway 只用它决定首屏资料是否补机器人头像昵称。
|
||||
roomExtRobotRoomKey = "robot_room"
|
||||
roomExtRobotUserIDsKey = "robot_user_ids"
|
||||
|
||||
// JoinRoom 默认保持历史完整包;lite 只保留进房首屏必要字段,把装扮/榜单等增强展示后移。
|
||||
joinRoomResponseModeFull = "full"
|
||||
joinRoomResponseModeLite = "lite"
|
||||
)
|
||||
|
||||
type flexibleInt64 int64
|
||||
@ -1092,15 +1096,21 @@ func trimOptionalString(value *string) {
|
||||
// joinRoom 把进房 HTTP JSON 请求转换为 room-service JoinRoom 命令,并组装房间首屏初始化包。
|
||||
func (h *Handler) joinRoom(writer http.ResponseWriter, request *http.Request) {
|
||||
var body struct {
|
||||
RoomID string `json:"room_id"`
|
||||
CommandID string `json:"command_id"`
|
||||
Role string `json:"role"`
|
||||
Password string `json:"password"`
|
||||
RoomID string `json:"room_id"`
|
||||
CommandID string `json:"command_id"`
|
||||
Role string `json:"role"`
|
||||
Password string `json:"password"`
|
||||
ResponseMode string `json:"response_mode"`
|
||||
}
|
||||
|
||||
if !httpkit.Decode(writer, request, &body) {
|
||||
return
|
||||
}
|
||||
responseMode, ok := joinRoomResponseMode(request, body.ResponseMode)
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid response_mode")
|
||||
return
|
||||
}
|
||||
actorSnapshot, err := h.resolveRoomActorJoinSnapshot(request)
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
@ -1115,16 +1125,42 @@ func (h *Handler) joinRoom(writer http.ResponseWriter, request *http.Request) {
|
||||
ActorRegionId: actorSnapshot.regionID,
|
||||
ActorDisplayProfile: actorSnapshot.displayProfile,
|
||||
// 座驾快照在进房命令提交前生成;room-service 只保存快照,不回查 wallet。
|
||||
EntryVehicle: h.joinRoomEntryVehicleSnapshot(request),
|
||||
EntryVehicle: h.joinRoomEntryVehicleSnapshot(request, responseMode),
|
||||
ResponseMode: responseMode,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
if responseMode == joinRoomResponseModeLite {
|
||||
httpkit.WriteOK(writer, request, h.joinRoomInitialLiteData(request, body.RoomID, resp))
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, h.joinRoomInitialData(request, body.RoomID, resp))
|
||||
}
|
||||
|
||||
func (h *Handler) joinRoomEntryVehicleSnapshot(request *http.Request) *roomv1.RoomEntryVehicleSnapshot {
|
||||
func joinRoomResponseMode(request *http.Request, bodyMode string) (string, bool) {
|
||||
mode := strings.TrimSpace(bodyMode)
|
||||
if mode == "" {
|
||||
mode = strings.TrimSpace(request.URL.Query().Get("response_mode"))
|
||||
}
|
||||
if mode == "" {
|
||||
return joinRoomResponseModeFull, true
|
||||
}
|
||||
mode = strings.ToLower(mode)
|
||||
switch mode {
|
||||
case joinRoomResponseModeFull, joinRoomResponseModeLite:
|
||||
return mode, true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) joinRoomEntryVehicleSnapshot(request *http.Request, responseMode string) *roomv1.RoomEntryVehicleSnapshot {
|
||||
if responseMode == joinRoomResponseModeLite {
|
||||
// lite 进房只提交 presence 必需事实;座驾属于入场展示增强,后续由资料/装扮接口补齐。
|
||||
return nil
|
||||
}
|
||||
if h.walletClient == nil {
|
||||
// 座驾只影响进房展示,不应该因为 wallet 暂不可用阻断 JoinRoom。
|
||||
return nil
|
||||
@ -1198,6 +1234,30 @@ func (h *Handler) joinRoomInitialData(request *http.Request, requestedRoomID str
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) joinRoomInitialLiteData(request *http.Request, requestedRoomID string, resp *roomv1.JoinRoomResponse) joinRoomLiteData {
|
||||
if resp == nil {
|
||||
return joinRoomLiteData{}
|
||||
}
|
||||
viewerUserID := auth.UserIDFromContext(request.Context())
|
||||
snapshot := resp.GetRoom()
|
||||
roomID := snapshot.GetRoomId()
|
||||
if roomID == "" {
|
||||
// lite 和完整包共用同一兜底,避免异常上游只回 result 时客户端拿不到 IM/RTC 房间 ID。
|
||||
roomID = strings.TrimSpace(requestedRoomID)
|
||||
}
|
||||
|
||||
return joinRoomLiteData{
|
||||
Result: commandResultDataFromProto(resp.GetResult()),
|
||||
Room: roomInitialRoomDataFromSnapshot(snapshot, roomID),
|
||||
Viewer: roomViewerDataFromProto(resp.GetUser(), viewerUserID),
|
||||
Seats: roomSeatDataFromSnapshot(snapshot),
|
||||
Profiles: h.roomInitialBasicProfiles(request, snapshot, viewerUserID),
|
||||
IM: roomIMData{GroupID: roomIMGroupID(roomID), NeedJoinGroup: true},
|
||||
RTC: h.joinRoomRTCData(roomID, viewerUserID),
|
||||
ServerTimeMS: resp.GetResult().GetServerTimeMs(),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) joinRoomRTCData(roomID string, viewerUserID int64) roomRTCData {
|
||||
rtc := roomRTCData{NeedToken: true}
|
||||
token, err := h.generateTencentRTCToken(viewerUserID, roomID)
|
||||
@ -1219,6 +1279,50 @@ func (h *Handler) roomInitialProfiles(request *http.Request, snapshot *roomv1.Ro
|
||||
return h.roomDisplayProfiles(request, userIDs)
|
||||
}
|
||||
|
||||
func (h *Handler) roomInitialBasicProfiles(request *http.Request, snapshot *roomv1.RoomSnapshot, viewerUserID int64) []roomBasicProfileData {
|
||||
userIDs := roomInitialBasicProfileUserIDs(snapshot, viewerUserID)
|
||||
profileMap := h.roomBasicProfileMap(request, userIDs)
|
||||
profiles := make([]roomBasicProfileData, 0, len(userIDs))
|
||||
for _, userID := range userIDs {
|
||||
if profile, ok := profileMap[userID]; ok {
|
||||
profiles = append(profiles, profile)
|
||||
}
|
||||
}
|
||||
return profiles
|
||||
}
|
||||
|
||||
func (h *Handler) roomBasicProfileMap(request *http.Request, userIDs []int64) map[int64]roomBasicProfileData {
|
||||
if h.userProfileClient == nil {
|
||||
return nil
|
||||
}
|
||||
userIDs = uniquePositiveUserIDs(userIDs)
|
||||
if len(userIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
resp, err := h.userProfileClient.BatchGetRoomBasicUsers(request.Context(), &userv1.BatchGetRoomBasicUsersRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
UserIds: userIDs,
|
||||
})
|
||||
if err != nil {
|
||||
// lite 首屏资料是展示兜底,失败不能回滚已经成功的进房 presence。
|
||||
return nil
|
||||
}
|
||||
profiles := make(map[int64]roomBasicProfileData, len(resp.GetUsers()))
|
||||
for _, userID := range userIDs {
|
||||
user := resp.GetUsers()[userID]
|
||||
if user == nil {
|
||||
continue
|
||||
}
|
||||
profiles[userID] = roomBasicProfileData{
|
||||
UserID: formatOptionalUserID(user.GetUserId()),
|
||||
Username: strings.TrimSpace(user.GetUsername()),
|
||||
Avatar: strings.TrimSpace(user.GetAvatar()),
|
||||
DisplayUserID: strings.TrimSpace(user.GetDisplayUserId()),
|
||||
}
|
||||
}
|
||||
return profiles
|
||||
}
|
||||
|
||||
// roomHeartbeat 把客户端显式心跳转换为 room-service presence refresh 命令。
|
||||
func (h *Handler) roomHeartbeat(writer http.ResponseWriter, request *http.Request) {
|
||||
var body struct {
|
||||
|
||||
@ -273,6 +273,10 @@ func (c *shareRoomQueryClient) ListRooms(context.Context, *roomv1.ListRoomsReque
|
||||
return &roomv1.ListRoomsResponse{}, nil
|
||||
}
|
||||
|
||||
func (c *shareRoomQueryClient) ListRoomsByOwners(context.Context, *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
return &roomv1.ListRoomsResponse{}, nil
|
||||
}
|
||||
|
||||
func (c *shareRoomQueryClient) ListRoomFeeds(context.Context, *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
return &roomv1.ListRoomsResponse{}, nil
|
||||
}
|
||||
|
||||
@ -73,6 +73,17 @@ type joinRoomData struct {
|
||||
ServerTimeMS int64 `json:"server_time_ms"`
|
||||
}
|
||||
|
||||
type joinRoomLiteData struct {
|
||||
Result roomCommandResultData `json:"result"`
|
||||
Room roomInitialData `json:"room"`
|
||||
Viewer roomViewerData `json:"viewer"`
|
||||
Seats []roomSeatData `json:"seats"`
|
||||
Profiles []roomBasicProfileData `json:"profiles"`
|
||||
IM roomIMData `json:"im"`
|
||||
RTC roomRTCData `json:"rtc"`
|
||||
ServerTimeMS int64 `json:"server_time_ms"`
|
||||
}
|
||||
|
||||
type roomDetailData struct {
|
||||
Room roomInitialData `json:"room"`
|
||||
Viewer roomViewerData `json:"viewer"`
|
||||
@ -176,6 +187,13 @@ type roomDisplayProfileData struct {
|
||||
Charm int64 `json:"charm"`
|
||||
}
|
||||
|
||||
type roomBasicProfileData struct {
|
||||
UserID string `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
Avatar string `json:"avatar"`
|
||||
DisplayUserID string `json:"display_user_id"`
|
||||
}
|
||||
|
||||
type roomGiftPanelData struct {
|
||||
CoinBalance int64 `json:"coin_balance"`
|
||||
Recipients []roomGiftRecipientData `json:"recipients"`
|
||||
@ -797,6 +815,11 @@ func roomInitialRoomDataFromSnapshot(snapshot *roomv1.RoomSnapshot, roomID strin
|
||||
roomShortID = ext["room_short_id"]
|
||||
}
|
||||
seatCount, occupiedSeatCount := roomSeatCounts(snapshot)
|
||||
onlineCount := snapshot.GetOnlineCount()
|
||||
if onlineCount <= 0 && len(snapshot.GetOnlineUsers()) > 0 {
|
||||
// 老快照或非 lite 上游可能还没有 online_count 字段;此时用明细长度保持兼容。
|
||||
onlineCount = int32(len(snapshot.GetOnlineUsers()))
|
||||
}
|
||||
return roomInitialData{
|
||||
RoomID: roomID,
|
||||
IMGroupID: roomIMGroupID(roomID),
|
||||
@ -811,7 +834,7 @@ func roomInitialRoomDataFromSnapshot(snapshot *roomv1.RoomSnapshot, roomID strin
|
||||
ChatEnabled: snapshot.GetChatEnabled(),
|
||||
Locked: snapshot.GetLocked(),
|
||||
Heat: snapshot.GetHeat(),
|
||||
OnlineCount: int32(len(snapshot.GetOnlineUsers())),
|
||||
OnlineCount: onlineCount,
|
||||
SeatCount: seatCount,
|
||||
OccupiedSeatCount: occupiedSeatCount,
|
||||
VisibleRegionID: snapshot.GetVisibleRegionId(),
|
||||
@ -967,6 +990,25 @@ func roomInitialProfileUserIDs(snapshot *roomv1.RoomSnapshot, viewerUserID int64
|
||||
return userIDs
|
||||
}
|
||||
|
||||
func roomInitialBasicProfileUserIDs(snapshot *roomv1.RoomSnapshot, viewerUserID int64) []int64 {
|
||||
seen := map[int64]bool{}
|
||||
userIDs := make([]int64, 0, len(snapshot.GetMicSeats())+2)
|
||||
add := func(userID int64) {
|
||||
if userID <= 0 || seen[userID] {
|
||||
return
|
||||
}
|
||||
seen[userID] = true
|
||||
userIDs = append(userIDs, userID)
|
||||
}
|
||||
|
||||
add(snapshot.GetOwnerUserId())
|
||||
add(viewerUserID)
|
||||
for _, seat := range snapshot.GetMicSeats() {
|
||||
add(seat.GetUserId())
|
||||
}
|
||||
return userIDs
|
||||
}
|
||||
|
||||
func roomOnlineUserDataFromProto(resp *roomv1.ListRoomOnlineUsersResponse, profiles map[int64]roomDisplayProfileData) roomOnlineUsersData {
|
||||
if resp == nil {
|
||||
return roomOnlineUsersData{}
|
||||
|
||||
@ -66,6 +66,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler {
|
||||
UserCPClient: h.userCPClient,
|
||||
UserCountryClient: h.userCountryClient,
|
||||
UserHostClient: h.userHostClient,
|
||||
RoomQueryClient: h.roomQueryClient,
|
||||
WalletClient: h.walletClient,
|
||||
GrowthLevelClient: h.growthLevelClient,
|
||||
AchievementClient: h.achievementClient,
|
||||
|
||||
@ -0,0 +1,348 @@
|
||||
package userapi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"hyapp/pkg/imgroup"
|
||||
"hyapp/services/gateway-service/internal/auth"
|
||||
"hyapp/services/gateway-service/internal/transport/http/httpkit"
|
||||
|
||||
roomv1 "hyapp.local/api/proto/room/v1"
|
||||
userv1 "hyapp.local/api/proto/user/v1"
|
||||
)
|
||||
|
||||
const maxAgencyRoomListLimit = 50
|
||||
|
||||
type agencyRoomsData struct {
|
||||
AgencyID string `json:"agency_id"`
|
||||
Rooms []agencyRoomItemData `json:"rooms"`
|
||||
NextCursor string `json:"next_cursor"`
|
||||
}
|
||||
|
||||
type agencyRoomItemData struct {
|
||||
RoomID string `json:"room_id"`
|
||||
IMGroupID string `json:"im_group_id"`
|
||||
OwnerUserID string `json:"owner_user_id,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
CoverURL string `json:"cover_url,omitempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Locked bool `json:"locked"`
|
||||
Heat int64 `json:"heat"`
|
||||
OnlineCount int32 `json:"online_count"`
|
||||
SeatCount int32 `json:"seat_count"`
|
||||
OccupiedSeatCount int32 `json:"occupied_seat_count"`
|
||||
VisibleRegionID int64 `json:"visible_region_id,omitempty"`
|
||||
AppCode string `json:"app_code,omitempty"`
|
||||
RoomShortID string `json:"room_short_id,omitempty"`
|
||||
CountryCode string `json:"country_code,omitempty"`
|
||||
CountryFlag string `json:"country_flag,omitempty"`
|
||||
}
|
||||
|
||||
func (h *Handler) getAgencyProfile(writer http.ResponseWriter, request *http.Request) {
|
||||
targetUserID, ok := positiveInt64Query(request, "user_id")
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
agency, found, err := h.resolveAgencyForTargetHost(request, targetUserID)
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
httpkit.WriteOK(writer, request, map[string]any{"agency": nil})
|
||||
return
|
||||
}
|
||||
|
||||
httpkit.WriteOK(writer, request, map[string]any{"agency": hostAgencyFromProto(agency)})
|
||||
}
|
||||
|
||||
func (h *Handler) listAgencyRooms(writer http.ResponseWriter, request *http.Request) {
|
||||
targetUserID, ok := positiveInt64Query(request, "user_id")
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
limit, ok := parseAgencyRoomListLimit(request.URL.Query().Get("limit"))
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
tab, ok := parseAgencyRoomListTab(request.URL.Query().Get("tab"))
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
if h.roomQueryClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
|
||||
agency, found, err := h.resolveAgencyForTargetHost(request, targetUserID)
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
httpkit.WriteOK(writer, request, agencyRoomsData{Rooms: []agencyRoomItemData{}})
|
||||
return
|
||||
}
|
||||
|
||||
ownerUserIDs, err := h.activeAgencyHostUserIDs(request, agency)
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
if len(ownerUserIDs) == 0 {
|
||||
httpkit.WriteOK(writer, request, agencyRoomsData{AgencyID: int64String(agency.GetAgencyId()), Rooms: []agencyRoomItemData{}})
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.roomQueryClient.ListRoomsByOwners(request.Context(), &roomv1.ListRoomsByOwnersRequest{
|
||||
Meta: httpkit.RoomMeta(request, "", ""),
|
||||
ViewerUserId: auth.UserIDFromContext(request.Context()),
|
||||
OwnerUserIds: ownerUserIDs,
|
||||
Tab: tab,
|
||||
Cursor: strings.TrimSpace(request.URL.Query().Get("cursor")),
|
||||
Limit: limit,
|
||||
Query: agencyRoomListQuery(request),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
httpkit.WriteOK(writer, request, agencyRoomsData{
|
||||
AgencyID: int64String(agency.GetAgencyId()),
|
||||
Rooms: agencyRoomItemsFromProto(resp.GetRooms()),
|
||||
NextCursor: resp.GetNextCursor(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) updateAgencyProfile(writer http.ResponseWriter, request *http.Request) {
|
||||
agency, ok := h.resolveCurrentOwnerAgency(writer, request)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
CommandID string `json:"command_id"`
|
||||
CommandIDAlt string `json:"commandId"`
|
||||
Name *string `json:"name"`
|
||||
Avatar *string `json:"avatar"`
|
||||
}
|
||||
if !httpkit.Decode(writer, request, &body) {
|
||||
return
|
||||
}
|
||||
commandID := strings.TrimSpace(body.CommandID)
|
||||
if commandID == "" {
|
||||
commandID = strings.TrimSpace(body.CommandIDAlt)
|
||||
}
|
||||
name := trimmedOptionalString(body.Name)
|
||||
avatar := trimmedOptionalString(body.Avatar)
|
||||
if commandID == "" || (name == nil && avatar == nil) || optionalStringIsEmpty(name) || optionalStringIsEmpty(avatar) {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.userHostClient.UpdateAgencyProfile(request.Context(), &userv1.UpdateAgencyProfileRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
CommandId: commandID,
|
||||
OperatorUserId: auth.UserIDFromContext(request.Context()),
|
||||
AgencyId: agency.GetAgencyId(),
|
||||
Name: name,
|
||||
Avatar: avatar,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{"agency": hostAgencyFromProto(resp.GetAgency())})
|
||||
}
|
||||
|
||||
func (h *Handler) resolveAgencyForTargetHost(request *http.Request, targetUserID int64) (*userv1.Agency, bool, error) {
|
||||
if h.userHostClient == nil {
|
||||
return nil, false, status.Error(codes.Unavailable, "user host client unavailable")
|
||||
}
|
||||
|
||||
profileResp, err := h.userHostClient.GetHostProfile(request.Context(), &userv1.GetHostProfileRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
UserId: targetUserID,
|
||||
})
|
||||
if status.Code(err) == codes.NotFound {
|
||||
return nil, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
profile := profileResp.GetHostProfile()
|
||||
// 这两个公开查询看的是“被查询用户作为 active host 当前所属 agency”。非 host、停用 host、
|
||||
// 或没有 active agency 归属都按空结果处理,避免向客户端暴露中间态/历史关系。
|
||||
if profile == nil || profile.GetStatus() != agencyStatusActive || profile.GetCurrentAgencyId() <= 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
agencyResp, err := h.userHostClient.GetAgency(request.Context(), &userv1.GetAgencyRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
AgencyId: profile.GetCurrentAgencyId(),
|
||||
})
|
||||
if status.Code(err) == codes.NotFound {
|
||||
return nil, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
agency := agencyResp.GetAgency()
|
||||
if agency == nil || agency.GetAgencyId() != profile.GetCurrentAgencyId() || agency.GetStatus() != agencyStatusActive {
|
||||
return nil, false, nil
|
||||
}
|
||||
return agency, true, nil
|
||||
}
|
||||
|
||||
func (h *Handler) activeAgencyHostUserIDs(request *http.Request, agency *userv1.Agency) ([]int64, error) {
|
||||
resp, err := h.userHostClient.GetAgencyMembers(request.Context(), &userv1.GetAgencyMembersRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
AgencyId: agency.GetAgencyId(),
|
||||
Status: membershipStatusActive,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
seen := make(map[int64]struct{}, len(resp.GetMemberships())+1)
|
||||
ownerUserIDs := make([]int64, 0, len(resp.GetMemberships())+1)
|
||||
appendOwner := func(userID int64) {
|
||||
if userID <= 0 {
|
||||
return
|
||||
}
|
||||
if _, exists := seen[userID]; exists {
|
||||
return
|
||||
}
|
||||
seen[userID] = struct{}{}
|
||||
ownerUserIDs = append(ownerUserIDs, userID)
|
||||
}
|
||||
|
||||
// Agency owner 自动拥有 owner membership;即使历史数据缺 owner membership,也要把 owner 的 active 房间纳入组织房间列表。
|
||||
appendOwner(agency.GetOwnerUserId())
|
||||
for _, membership := range resp.GetMemberships() {
|
||||
if membership.GetStatus() == membershipStatusActive {
|
||||
appendOwner(membership.GetHostUserId())
|
||||
}
|
||||
}
|
||||
return ownerUserIDs, nil
|
||||
}
|
||||
|
||||
func agencyRoomItemsFromProto(rooms []*roomv1.RoomListItem) []agencyRoomItemData {
|
||||
items := make([]agencyRoomItemData, 0, len(rooms))
|
||||
for _, room := range rooms {
|
||||
items = append(items, agencyRoomItemFromProto(room))
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func agencyRoomItemFromProto(room *roomv1.RoomListItem) agencyRoomItemData {
|
||||
if room == nil {
|
||||
return agencyRoomItemData{}
|
||||
}
|
||||
roomID := room.GetRoomId()
|
||||
return agencyRoomItemData{
|
||||
RoomID: roomID,
|
||||
IMGroupID: agencyRoomIMGroupID(roomID),
|
||||
OwnerUserID: int64String(room.GetOwnerUserId()),
|
||||
Title: room.GetTitle(),
|
||||
CoverURL: room.GetCoverUrl(),
|
||||
Mode: room.GetMode(),
|
||||
Status: room.GetStatus(),
|
||||
Locked: room.GetLocked(),
|
||||
Heat: room.GetHeat(),
|
||||
OnlineCount: room.GetOnlineCount(),
|
||||
SeatCount: room.GetSeatCount(),
|
||||
OccupiedSeatCount: room.GetOccupiedSeatCount(),
|
||||
VisibleRegionID: room.GetVisibleRegionId(),
|
||||
AppCode: room.GetAppCode(),
|
||||
RoomShortID: room.GetRoomShortId(),
|
||||
CountryCode: room.GetCountryCode(),
|
||||
CountryFlag: agencyRoomCountryFlag(room.GetCountryCode()),
|
||||
}
|
||||
}
|
||||
|
||||
func positiveInt64Query(request *http.Request, name string) (int64, bool) {
|
||||
raw := strings.TrimSpace(request.URL.Query().Get(name))
|
||||
value, err := strconv.ParseInt(raw, 10, 64)
|
||||
return value, err == nil && value > 0
|
||||
}
|
||||
|
||||
func parseAgencyRoomListLimit(raw string) (int32, bool) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return 0, true
|
||||
}
|
||||
value, err := strconv.ParseInt(raw, 10, 32)
|
||||
if err != nil || value <= 0 {
|
||||
return 0, false
|
||||
}
|
||||
if value > maxAgencyRoomListLimit {
|
||||
value = maxAgencyRoomListLimit
|
||||
}
|
||||
return int32(value), true
|
||||
}
|
||||
|
||||
func parseAgencyRoomListTab(raw string) (string, bool) {
|
||||
switch strings.ToLower(strings.TrimSpace(raw)) {
|
||||
case "", "hot":
|
||||
return "hot", true
|
||||
case "new":
|
||||
return "new", true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func agencyRoomListQuery(request *http.Request) string {
|
||||
if query := strings.TrimSpace(request.URL.Query().Get("query")); query != "" {
|
||||
return query
|
||||
}
|
||||
return strings.TrimSpace(request.URL.Query().Get("q"))
|
||||
}
|
||||
|
||||
func trimmedOptionalString(value *string) *string {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
trimmed := strings.TrimSpace(*value)
|
||||
return &trimmed
|
||||
}
|
||||
|
||||
func optionalStringIsEmpty(value *string) bool {
|
||||
return value != nil && *value == ""
|
||||
}
|
||||
|
||||
func agencyRoomIMGroupID(roomID string) string {
|
||||
groupID, err := imgroup.RoomGroupID(roomID)
|
||||
if err != nil {
|
||||
return roomID
|
||||
}
|
||||
return groupID
|
||||
}
|
||||
|
||||
func agencyRoomCountryFlag(country string) string {
|
||||
country = strings.ToUpper(strings.TrimSpace(country))
|
||||
if len(country) != 2 {
|
||||
return ""
|
||||
}
|
||||
runes := []rune(country)
|
||||
for _, value := range runes {
|
||||
if value < 'A' || value > 'Z' {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
const regionalIndicatorA = 0x1F1E6
|
||||
return string([]rune{
|
||||
regionalIndicatorA + (runes[0] - 'A'),
|
||||
regionalIndicatorA + (runes[1] - 'A'),
|
||||
})
|
||||
}
|
||||
@ -17,6 +17,7 @@ type Handler struct {
|
||||
userCPClient client.UserCPClient
|
||||
userCountryClient client.UserCountryQueryClient
|
||||
userHostClient client.UserHostClient
|
||||
roomQueryClient client.RoomQueryClient
|
||||
walletClient client.WalletClient
|
||||
growthLevelClient client.GrowthLevelClient
|
||||
achievementClient client.AchievementClient
|
||||
@ -31,6 +32,7 @@ type Config struct {
|
||||
UserCPClient client.UserCPClient
|
||||
UserCountryClient client.UserCountryQueryClient
|
||||
UserHostClient client.UserHostClient
|
||||
RoomQueryClient client.RoomQueryClient
|
||||
WalletClient client.WalletClient
|
||||
GrowthLevelClient client.GrowthLevelClient
|
||||
AchievementClient client.AchievementClient
|
||||
@ -46,6 +48,7 @@ func New(config Config) *Handler {
|
||||
userCPClient: config.UserCPClient,
|
||||
userCountryClient: config.UserCountryClient,
|
||||
userHostClient: config.UserHostClient,
|
||||
roomQueryClient: config.RoomQueryClient,
|
||||
walletClient: config.WalletClient,
|
||||
growthLevelClient: config.GrowthLevelClient,
|
||||
achievementClient: config.AchievementClient,
|
||||
@ -66,6 +69,9 @@ func (h *Handler) UserHandlers() httproutes.UserHandlers {
|
||||
GetMyRoleSummary: h.getMyRoleSummary,
|
||||
SearchHostAgencies: h.searchHostAgencies,
|
||||
ApplyToHostAgency: h.applyToHostAgency,
|
||||
GetAgencyProfile: h.getAgencyProfile,
|
||||
ListAgencyRooms: h.listAgencyRooms,
|
||||
UpdateAgencyProfile: h.updateAgencyProfile,
|
||||
GetHostCenterAgency: h.getHostCenterAgency,
|
||||
GetHostCenterPlatformPolicy: h.getHostCenterPlatformPolicy,
|
||||
GetAgencyCenterOverview: h.getAgencyCenterOverview,
|
||||
|
||||
@ -59,9 +59,6 @@ func (h *Handler) getHostCenterAgency(writer http.ResponseWriter, request *http.
|
||||
if owner.DisplayUserID != "" {
|
||||
data.ShortID = owner.DisplayUserID
|
||||
}
|
||||
if owner.Avatar != "" {
|
||||
data.Avatar = owner.Avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/logx"
|
||||
"hyapp/pkg/xerr"
|
||||
"hyapp/services/room-service/internal/room/command"
|
||||
"hyapp/services/room-service/internal/room/state"
|
||||
)
|
||||
|
||||
@ -109,6 +110,49 @@ func (s *Service) projectRoomPresenceBestEffort(ctx context.Context, snapshot *r
|
||||
}
|
||||
}
|
||||
|
||||
// projectRoomPresenceForCommandBestEffort 按命令类型选择最小投影;Join/Leave 热路径不能再重写整房间在线集合。
|
||||
func (s *Service) projectRoomPresenceForCommandBestEffort(ctx context.Context, cmd command.Command, snapshot *roomv1.RoomSnapshot, joinedUser *roomv1.RoomUser) {
|
||||
switch cmd.Type() {
|
||||
case (command.JoinRoom{}).Type():
|
||||
s.upsertJoinedRoomPresenceBestEffort(ctx, snapshot, cmd.ActorUserID(), joinedUser)
|
||||
case (command.LeaveRoom{}).Type():
|
||||
s.markLeftRoomPresenceBestEffort(ctx, snapshot, cmd.ActorUserID())
|
||||
default:
|
||||
// Kick/Close/SystemEvict/Mic 变更仍先保留全量投影,确保复杂状态收敛不因本次 Join/Leave 优化改变语义。
|
||||
s.projectRoomPresenceBestEffort(ctx, snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) upsertJoinedRoomPresenceBestEffort(ctx context.Context, snapshot *roomv1.RoomSnapshot, userID int64, joinedUser *roomv1.RoomUser) {
|
||||
projection := roomPresenceProjectionForUser(snapshot, userID, joinedUser, s.clock.Now().UnixMilli())
|
||||
if projection.RoomID == "" || projection.UserID <= 0 {
|
||||
return
|
||||
}
|
||||
if err := s.repository.UpsertRoomUserPresence(ctx, projection); err != nil {
|
||||
logx.Error(ctx, "room_presence_join_project_failed", err,
|
||||
slog.String("component", "room_presence_projector"),
|
||||
slog.String("room_id", projection.RoomID),
|
||||
slog.Int64("user_id", projection.UserID),
|
||||
slog.Int64("room_version", projection.RoomVersion),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) markLeftRoomPresenceBestEffort(ctx context.Context, snapshot *roomv1.RoomSnapshot, userID int64) {
|
||||
projection := roomPresenceLeaveProjection(snapshot, userID, s.clock.Now().UnixMilli())
|
||||
if projection.RoomID == "" || projection.UserID <= 0 {
|
||||
return
|
||||
}
|
||||
if err := s.repository.MarkRoomUserPresenceLeft(ctx, projection); err != nil {
|
||||
logx.Error(ctx, "room_presence_leave_project_failed", err,
|
||||
slog.String("component", "room_presence_projector"),
|
||||
slog.String("room_id", projection.RoomID),
|
||||
slog.Int64("user_id", projection.UserID),
|
||||
slog.Int64("room_version", projection.RoomVersion),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// roomPresenceProjectionFromSnapshot 把 Room Cell 快照压缩成用户当前房间读模型。
|
||||
// 读模型只保存恢复入口需要的字段,不复制完整 RoomState,也不作为权限权威来源。
|
||||
func roomPresenceProjectionFromSnapshot(snapshot *roomv1.RoomSnapshot, updatedAtMS int64) RoomPresenceSnapshot {
|
||||
@ -161,6 +205,53 @@ func roomPresenceProjectionFromSnapshot(snapshot *roomv1.RoomSnapshot, updatedAt
|
||||
}
|
||||
}
|
||||
|
||||
func roomPresenceProjectionForUser(snapshot *roomv1.RoomSnapshot, userID int64, user *roomv1.RoomUser, updatedAtMS int64) RoomPresence {
|
||||
if snapshot == nil || snapshot.GetRoomId() == "" || snapshot.GetStatus() != state.RoomStatusActive || userID <= 0 {
|
||||
return RoomPresence{}
|
||||
}
|
||||
if user == nil || user.GetUserId() != userID {
|
||||
user = findProtoUser(snapshot, userID)
|
||||
}
|
||||
if user == nil || user.GetUserId() <= 0 {
|
||||
return RoomPresence{}
|
||||
}
|
||||
entry := RoomPresence{
|
||||
AppCode: snapshot.GetAppCode(),
|
||||
UserID: user.GetUserId(),
|
||||
RoomID: snapshot.GetRoomId(),
|
||||
Role: user.GetRole(),
|
||||
RoomVersion: snapshot.GetVersion(),
|
||||
Status: roomPresenceStatusActive,
|
||||
JoinedAtMS: user.GetJoinedAtMs(),
|
||||
LastSeenAtMS: user.GetLastSeenAtMs(),
|
||||
UpdatedAtMS: updatedAtMS,
|
||||
}
|
||||
for _, seat := range snapshot.GetMicSeats() {
|
||||
if seat.GetUserId() != user.GetUserId() {
|
||||
continue
|
||||
}
|
||||
// JoinRoom 可能是重连到已在麦用户;单用户投影仍要保留麦上发流状态。
|
||||
entry.PublishState = seat.GetPublishState()
|
||||
entry.MicSessionID = seat.GetMicSessionId()
|
||||
break
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
func roomPresenceLeaveProjection(snapshot *roomv1.RoomSnapshot, userID int64, updatedAtMS int64) RoomPresence {
|
||||
if snapshot == nil || snapshot.GetRoomId() == "" || userID <= 0 {
|
||||
return RoomPresence{}
|
||||
}
|
||||
return RoomPresence{
|
||||
AppCode: snapshot.GetAppCode(),
|
||||
UserID: userID,
|
||||
RoomID: snapshot.GetRoomId(),
|
||||
RoomVersion: snapshot.GetVersion(),
|
||||
Status: roomPresenceStatusLeft,
|
||||
UpdatedAtMS: updatedAtMS,
|
||||
}
|
||||
}
|
||||
|
||||
// containsUserID 是当前房间恢复入口的本地集合查询,独立保留便于后续替换为二分查找。
|
||||
func containsUserID(values []int64, target int64) bool {
|
||||
return slices.Contains(values, target)
|
||||
|
||||
@ -24,6 +24,7 @@ const (
|
||||
defaultRoomListLimit = 20
|
||||
maxRoomListLimit = 50
|
||||
maxRoomListQueryRunes = 64
|
||||
maxRoomOwnerIDFilters = 500
|
||||
roomHotHeatWeight = 650000
|
||||
roomHotOnlineWeight = 300000
|
||||
roomHotMicWeight = 50000
|
||||
@ -102,6 +103,45 @@ func (s *Service) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (
|
||||
return roomListResponseFromEntries(tab, query, countryCode, viewerCountryCode, allVisibleRegions, entries, limit), nil
|
||||
}
|
||||
|
||||
func (s *Service) ListRoomsByOwners(ctx context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
if req.GetViewerUserId() <= 0 {
|
||||
// owner 集合必须由 gateway 在鉴权后根据业务归属注入,room-service 不接受匿名组织页查询。
|
||||
return nil, xerr.New(xerr.InvalidArgument, "viewer_user_id is required")
|
||||
}
|
||||
tab := normalizeRoomListTab(req.GetTab())
|
||||
if tab == "" {
|
||||
return nil, xerr.New(xerr.InvalidArgument, "tab is invalid")
|
||||
}
|
||||
ownerUserIDs := normalizeRoomOwnerFilters(req.GetOwnerUserIds())
|
||||
if len(ownerUserIDs) == 0 {
|
||||
return roomListResponseFromEntries(tab, "", "", "", false, nil, normalizeRoomListLimit(req.GetLimit())), nil
|
||||
}
|
||||
limit := normalizeRoomListLimit(req.GetLimit())
|
||||
query, err := normalizeRoomListQuery(req.GetQuery())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cursor, err := decodeRoomListCursor(tab, query, "", "", false, req.GetCursor())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries, err := s.repository.ListRoomListEntries(ctx, RoomListQuery{
|
||||
AppCode: appcode.FromContext(ctx),
|
||||
Tab: tab,
|
||||
OwnerUserIDs: ownerUserIDs,
|
||||
Query: query,
|
||||
Limit: limit + 1,
|
||||
CursorSortScore: cursor.SortScore,
|
||||
CursorCreatedAtMS: cursor.CreatedAtMS,
|
||||
CursorRoomID: cursor.RoomID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roomListResponseFromEntries(tab, query, "", "", false, entries, limit), nil
|
||||
}
|
||||
|
||||
func (s *Service) listRoomListEntries(ctx context.Context, query RoomListQuery) ([]RoomListEntry, error) {
|
||||
if s != nil && s.roomListCache != nil && roomListCacheEligible(query) {
|
||||
entries, ok, err := s.roomListCache.ListRoomListEntries(ctx, query)
|
||||
@ -118,7 +158,7 @@ func (s *Service) listRoomListEntries(ctx context.Context, query RoomListQuery)
|
||||
|
||||
func roomListCacheEligible(query RoomListQuery) bool {
|
||||
// 搜索、全区白名单和内部定向查询仍走 MySQL,避免为了低频条件维护过宽的 Redis 索引。
|
||||
if strings.TrimSpace(query.Query) != "" || query.AllVisibleRegions || query.OwnerUserID > 0 {
|
||||
if strings.TrimSpace(query.Query) != "" || query.AllVisibleRegions || query.OwnerUserID > 0 || len(query.OwnerUserIDs) > 0 {
|
||||
return false
|
||||
}
|
||||
return query.Tab == roomListTabHot || query.Tab == roomListTabNew
|
||||
@ -439,6 +479,25 @@ func normalizeRoomListLimit(limit int32) int {
|
||||
return int(limit)
|
||||
}
|
||||
|
||||
func normalizeRoomOwnerFilters(ownerUserIDs []int64) []int64 {
|
||||
seen := make(map[int64]struct{}, len(ownerUserIDs))
|
||||
ids := make([]int64, 0, len(ownerUserIDs))
|
||||
for _, userID := range ownerUserIDs {
|
||||
if userID <= 0 {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[userID]; exists {
|
||||
continue
|
||||
}
|
||||
seen[userID] = struct{}{}
|
||||
ids = append(ids, userID)
|
||||
if len(ids) >= maxRoomOwnerIDFilters {
|
||||
break
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// normalizeVisibleRegionID 把负数区域收敛到 GLOBAL 桶,避免非法区域影响 SQL 查询边界。
|
||||
func normalizeVisibleRegionID(regionID int64) int64 {
|
||||
if regionID < 0 {
|
||||
|
||||
@ -84,6 +84,48 @@ func TestListRoomsFallsBackToMySQLWhenCacheMisses(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRoomsByOwnersReturnsActiveRoomsForAgencyHosts(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repository := mysqltest.NewRepository(t)
|
||||
svc := roomservice.New(roomservice.Config{
|
||||
NodeID: "node-list-by-owners-test",
|
||||
LeaseTTL: 10 * time.Second,
|
||||
RankLimit: 20,
|
||||
SnapshotEveryN: 1,
|
||||
}, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher())
|
||||
createPinnedListRoom(t, ctx, svc, "room-agency-owner", "agency-owner", 6201, 7101, "US")
|
||||
createPinnedListRoom(t, ctx, svc, "room-agency-member", "agency-member", 6202, 7202, "AE")
|
||||
createPinnedListRoom(t, ctx, svc, "room-outside-agency", "outside-agency", 6203, 7101, "US")
|
||||
createPinnedListRoom(t, ctx, svc, "room-agency-closed", "agency-closed", 6202, 7202, "AE")
|
||||
if _, err := svc.CloseRoom(ctx, &roomv1.CloseRoomRequest{
|
||||
Meta: roomservice.NewRequestMeta("room-agency-closed", 6202),
|
||||
Reason: "closed fixture",
|
||||
}); err != nil {
|
||||
t.Fatalf("close agency room fixture failed: %v", err)
|
||||
}
|
||||
|
||||
resp, err := svc.ListRoomsByOwners(ctx, &roomv1.ListRoomsByOwnersRequest{
|
||||
Meta: &roomv1.RequestMeta{AppCode: appcode.Default},
|
||||
ViewerUserId: 4001,
|
||||
OwnerUserIds: []int64{6201, 6202},
|
||||
Tab: "new",
|
||||
Limit: 10,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("list rooms by owners failed: %v", err)
|
||||
}
|
||||
got := roomIDs(resp.GetRooms())
|
||||
want := map[string]bool{"room-agency-owner": true, "room-agency-member": true}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("owner-filtered room count mismatch: got=%v", got)
|
||||
}
|
||||
for _, roomID := range got {
|
||||
if !want[roomID] {
|
||||
t.Fatalf("owner-filtered rooms must include only active agency host rooms, got=%v", got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fakeRoomListCache struct {
|
||||
entries []roomservice.RoomListEntry
|
||||
ok bool
|
||||
|
||||
@ -94,6 +94,95 @@ func TestListRoomOnlineUsersReturnsOwnerAdminRoleAndGiftValue(t *testing.T) {
|
||||
t.Logf("online users response items: %s", payload)
|
||||
}
|
||||
|
||||
func TestJoinLeaveRoomUpdatesPresenceIncrementally(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repository := mysqltest.NewRepository(t)
|
||||
now := &fixedRoomRocketClock{now: time.Date(2026, 5, 27, 13, 0, 0, 0, time.UTC)}
|
||||
svc := newRocketTestService(t, repository, &rocketTestWallet{}, now)
|
||||
|
||||
roomID := "room-presence-incremental"
|
||||
ownerID := int64(1101)
|
||||
viewerID := int64(1102)
|
||||
createRocketRoom(t, ctx, svc, roomID, ownerID, 9001)
|
||||
joinRocketRoom(t, ctx, svc, roomID, viewerID)
|
||||
|
||||
onlineResp, err := svc.ListRoomOnlineUsers(ctx, &roomv1.ListRoomOnlineUsersRequest{
|
||||
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
|
||||
RoomId: roomID,
|
||||
ViewerUserId: ownerID,
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("list online users after join failed: %v", err)
|
||||
}
|
||||
if item := onlineUserItemByID(onlineResp.GetItems(), viewerID); item == nil || item.GetRole() != "audience" {
|
||||
t.Fatalf("join must upsert viewer active presence: %+v", onlineResp.GetItems())
|
||||
}
|
||||
|
||||
if _, err := svc.LeaveRoom(ctx, &roomv1.LeaveRoomRequest{Meta: rocketMeta(roomID, viewerID, "presence-incremental-leave")}); err != nil {
|
||||
t.Fatalf("leave room failed: %v", err)
|
||||
}
|
||||
onlineResp, err = svc.ListRoomOnlineUsers(ctx, &roomv1.ListRoomOnlineUsersRequest{
|
||||
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
|
||||
RoomId: roomID,
|
||||
ViewerUserId: ownerID,
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("list online users after leave failed: %v", err)
|
||||
}
|
||||
if item := onlineUserItemByID(onlineResp.GetItems(), viewerID); item != nil {
|
||||
t.Fatalf("leave must mark only viewer presence left: %+v", onlineResp.GetItems())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarkRoomUserPresenceLeftDoesNotClearAnotherRoom(t *testing.T) {
|
||||
ctx := appcode.WithContext(context.Background(), appcode.Default)
|
||||
repository := mysqltest.NewRepository(t)
|
||||
userID := int64(1201)
|
||||
|
||||
if err := repository.UpsertRoomUserPresence(ctx, roomservice.RoomPresence{
|
||||
AppCode: appcode.Default,
|
||||
UserID: userID,
|
||||
RoomID: "room-current-active",
|
||||
Role: "audience",
|
||||
RoomVersion: 2,
|
||||
JoinedAtMS: 1000,
|
||||
LastSeenAtMS: 1000,
|
||||
UpdatedAtMS: 1000,
|
||||
}); err != nil {
|
||||
t.Fatalf("upsert current room presence failed: %v", err)
|
||||
}
|
||||
if err := repository.MarkRoomUserPresenceLeft(ctx, roomservice.RoomPresence{
|
||||
AppCode: appcode.Default,
|
||||
UserID: userID,
|
||||
RoomID: "room-old-left",
|
||||
RoomVersion: 3,
|
||||
UpdatedAtMS: 2000,
|
||||
}); err != nil {
|
||||
t.Fatalf("mark old room presence left failed: %v", err)
|
||||
}
|
||||
|
||||
presence, exists, err := repository.GetCurrentRoomPresence(ctx, userID)
|
||||
if err != nil {
|
||||
t.Fatalf("get current room presence failed: %v", err)
|
||||
}
|
||||
if !exists || presence.RoomID != "room-current-active" || presence.Status != "active" {
|
||||
t.Fatalf("old room leave projection must not clear newer room presence: exists=%v presence=%+v", exists, presence)
|
||||
}
|
||||
}
|
||||
|
||||
func onlineUserItemByID(items []*roomv1.RoomOnlineUser, userID int64) *roomv1.RoomOnlineUser {
|
||||
for _, item := range items {
|
||||
if item.GetUserId() == userID {
|
||||
return item
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestSendGiftPassesHostPeriodScopeToWallet(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repository := mysqltest.NewRepository(t)
|
||||
|
||||
@ -178,7 +178,7 @@ func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayabl
|
||||
// 列表读模型最终一致,失败只记录日志,不回滚已经提交的 Room Cell 命令。
|
||||
s.projectRoomListBestEffort(ctx, result.snapshot)
|
||||
// 当前房间恢复读模型同样最终一致;权威校验仍以 Room Cell 快照为准。
|
||||
s.projectRoomPresenceBestEffort(ctx, result.snapshot)
|
||||
s.projectRoomPresenceForCommandBestEffort(ctx, cmd, result.snapshot, result.user)
|
||||
// 跨房间贡献榜是 Redis 轻量读模型,不能影响已提交的房间状态和账务事实。
|
||||
s.recordRoomGiftLeaderboardBestEffort(ctx, result.roomGiftLeaderboard)
|
||||
projectionMS = elapsedMS(projectionStartedAt)
|
||||
|
||||
@ -19,6 +19,8 @@ import (
|
||||
"hyapp/services/room-service/internal/room/state"
|
||||
)
|
||||
|
||||
const joinRoomResponseModeLite = "lite"
|
||||
|
||||
// JoinRoom 把用户业务态接入房间。
|
||||
func (s *Service) JoinRoom(ctx context.Context, req *roomv1.JoinRoomRequest) (*roomv1.JoinRoomResponse, error) {
|
||||
ctx = contextFromMeta(ctx, req.GetMeta())
|
||||
@ -133,10 +135,38 @@ func (s *Service) JoinRoom(ctx context.Context, req *roomv1.JoinRoomRequest) (*r
|
||||
return &roomv1.JoinRoomResponse{
|
||||
Result: commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()),
|
||||
User: result.user,
|
||||
Room: result.snapshot,
|
||||
Room: joinRoomResponseSnapshot(result.snapshot, req.GetResponseMode()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func joinRoomResponseSnapshot(snapshot *roomv1.RoomSnapshot, responseMode string) *roomv1.RoomSnapshot {
|
||||
if strings.ToLower(strings.TrimSpace(responseMode)) != joinRoomResponseModeLite || snapshot == nil {
|
||||
return snapshot
|
||||
}
|
||||
onlineCount := snapshot.GetOnlineCount()
|
||||
if onlineCount <= 0 && len(snapshot.GetOnlineUsers()) > 0 {
|
||||
onlineCount = int32(len(snapshot.GetOnlineUsers()))
|
||||
}
|
||||
// lite 只裁剪返回给 gateway 的快照;Room Cell 提交、持久化、projection、outbox 都已经使用完整 snapshot。
|
||||
return &roomv1.RoomSnapshot{
|
||||
RoomId: snapshot.GetRoomId(),
|
||||
OwnerUserId: snapshot.GetOwnerUserId(),
|
||||
Mode: snapshot.GetMode(),
|
||||
Status: snapshot.GetStatus(),
|
||||
ChatEnabled: snapshot.GetChatEnabled(),
|
||||
MicSeats: snapshot.GetMicSeats(),
|
||||
RoomExt: snapshot.GetRoomExt(),
|
||||
Heat: snapshot.GetHeat(),
|
||||
Version: snapshot.GetVersion(),
|
||||
AppCode: snapshot.GetAppCode(),
|
||||
RoomShortId: snapshot.GetRoomShortId(),
|
||||
VisibleRegionId: snapshot.GetVisibleRegionId(),
|
||||
Locked: snapshot.GetLocked(),
|
||||
Rocket: snapshot.GetRocket(),
|
||||
OnlineCount: onlineCount,
|
||||
}
|
||||
}
|
||||
|
||||
func userDisplayProfileFromProto(item *roomv1.RoomUserDisplayProfile) command.UserDisplayProfile {
|
||||
if item == nil || item.GetUserId() <= 0 {
|
||||
return command.UserDisplayProfile{}
|
||||
|
||||
@ -497,6 +497,8 @@ type RoomListQuery struct {
|
||||
Tab string
|
||||
// OwnerUserID 保留给内部定向读模型;公开 Mine 顶部卡片走 GetMyRoom。
|
||||
OwnerUserID int64
|
||||
// OwnerUserIDs 是业务方预先解析出的房主集合,用于 Agency 等组织页批量取房间卡片。
|
||||
OwnerUserIDs []int64
|
||||
// Query 非空时按 room_id 或 title 做包含匹配。
|
||||
Query string
|
||||
// CountryCode 非空时只返回房主国家命中的房间;gateway 必须先校验它属于当前用户区域。
|
||||
@ -782,6 +784,10 @@ type RoomListStore interface {
|
||||
type PresenceStore interface {
|
||||
// ProjectRoomPresence 用最新快照刷新用户当前房间读模型;失败不应破坏 Room Cell 已提交状态。
|
||||
ProjectRoomPresence(ctx context.Context, snapshot RoomPresenceSnapshot) error
|
||||
// UpsertRoomUserPresence 只刷新单个用户 active presence,服务 JoinRoom/Heartbeat 等单用户热路径。
|
||||
UpsertRoomUserPresence(ctx context.Context, presence RoomPresence) error
|
||||
// MarkRoomUserPresenceLeft 只把指定用户在指定房间标记为 left,避免 LeaveRoom 重新写整房间在线用户。
|
||||
MarkRoomUserPresenceLeft(ctx context.Context, presence RoomPresence) error
|
||||
// GetCurrentRoomPresence 查询用户当前 active 房间 presence,不扫描房间列表或快照。
|
||||
GetCurrentRoomPresence(ctx context.Context, userID int64) (RoomPresence, bool, error)
|
||||
// ListRoomOnlineUsers 查询房间 active 在线用户分页,不读取完整 RoomSnapshot。
|
||||
|
||||
@ -151,6 +151,42 @@ func TestRepeatJoinRoomPublishesEntryBroadcastDirectIMOnly(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoinRoomLiteTrimsResponseSnapshotOnly(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repository := mysqltest.NewRepository(t)
|
||||
now := &fixedRoomRocketClock{now: time.Date(2026, 6, 27, 12, 0, 0, 0, time.UTC)}
|
||||
svc := newRocketTestServiceWithDirectIM(t, repository, &rocketTestWallet{}, now, nil, newRecordingRoomDirectIMPublisher())
|
||||
|
||||
roomID := "room-lite-response-snapshot"
|
||||
createRocketRoom(t, ctx, svc, roomID, 1001, 9001)
|
||||
joinRocketRoom(t, ctx, svc, roomID, 1002)
|
||||
joinRocketRoom(t, ctx, svc, roomID, 1003)
|
||||
|
||||
resp, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{
|
||||
Meta: roomservice.NewRequestMeta(roomID, 1004),
|
||||
Role: "audience",
|
||||
ResponseMode: "lite",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("lite join room failed: %v", err)
|
||||
}
|
||||
if len(resp.GetRoom().GetOnlineUsers()) != 0 || len(resp.GetRoom().GetGiftRank()) != 0 || len(resp.GetRoom().GetAdminUserIds()) != 0 {
|
||||
t.Fatalf("lite response must trim heavy room arrays: %+v", resp.GetRoom())
|
||||
}
|
||||
|
||||
snapshot, err := svc.GetRoomSnapshot(ctx, &roomv1.GetRoomSnapshotRequest{
|
||||
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
|
||||
RoomId: roomID,
|
||||
ViewerUserId: 1004,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("snapshot after lite join failed: %v", err)
|
||||
}
|
||||
if got, want := resp.GetRoom().GetOnlineCount(), int32(len(snapshot.GetRoom().GetOnlineUsers())); got != want || want == 0 {
|
||||
t.Fatalf("lite response must keep accurate online_count without mutating stored snapshot: got=%d want=%d snapshot=%+v", got, want, snapshot.GetRoom())
|
||||
}
|
||||
}
|
||||
|
||||
func (w *rocketTestWallet) DebitGift(_ context.Context, req *walletv1.DebitGiftRequest) (*walletv1.DebitGiftResponse, error) {
|
||||
w.lastDebit = req
|
||||
w.debitRequests = append(w.debitRequests, req)
|
||||
|
||||
@ -465,6 +465,7 @@ func (s *RoomState) ToProto() *roomv1.RoomSnapshot {
|
||||
Locked: s.RoomPasswordHash != "",
|
||||
Rocket: rocketStateToProto(s.Rocket),
|
||||
BanStates: sortedModerationStates(s.BanUsers),
|
||||
OnlineCount: int32(len(users)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +77,62 @@ func (r *Repository) ProjectRoomPresence(ctx context.Context, snapshot roomservi
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// UpsertRoomUserPresence 只写入单个 active 用户,避免 JoinRoom 为整房间在线用户产生 O(N) 写放大。
|
||||
func (r *Repository) UpsertRoomUserPresence(ctx context.Context, presence roomservice.RoomPresence) error {
|
||||
appCode := normalizedRecordAppCode(ctx, presence.AppCode)
|
||||
if presence.UserID <= 0 || strings.TrimSpace(presence.RoomID) == "" {
|
||||
return nil
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx,
|
||||
`INSERT INTO room_user_presence (
|
||||
app_code, user_id, room_id, role, publish_state, mic_session_id, room_version, status, joined_at_ms, last_seen_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
room_id = VALUES(room_id),
|
||||
role = VALUES(role),
|
||||
publish_state = VALUES(publish_state),
|
||||
mic_session_id = VALUES(mic_session_id),
|
||||
room_version = VALUES(room_version),
|
||||
status = VALUES(status),
|
||||
joined_at_ms = VALUES(joined_at_ms),
|
||||
last_seen_at_ms = VALUES(last_seen_at_ms),
|
||||
updated_at_ms = VALUES(updated_at_ms)`,
|
||||
appCode,
|
||||
presence.UserID,
|
||||
presence.RoomID,
|
||||
presence.Role,
|
||||
presence.PublishState,
|
||||
presence.MicSessionID,
|
||||
presence.RoomVersion,
|
||||
roomPresenceStatusActiveSQL,
|
||||
presence.JoinedAtMS,
|
||||
presence.LastSeenAtMS,
|
||||
presence.UpdatedAtMS,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// MarkRoomUserPresenceLeft 只关闭指定用户在指定房间的 active presence,避免旧离房投影误伤新房间。
|
||||
func (r *Repository) MarkRoomUserPresenceLeft(ctx context.Context, presence roomservice.RoomPresence) error {
|
||||
appCode := normalizedRecordAppCode(ctx, presence.AppCode)
|
||||
if presence.UserID <= 0 || strings.TrimSpace(presence.RoomID) == "" {
|
||||
return nil
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx,
|
||||
`UPDATE room_user_presence
|
||||
SET status = ?, publish_state = '', mic_session_id = '', room_version = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND user_id = ? AND room_id = ? AND status = ?`,
|
||||
roomPresenceStatusLeftSQL,
|
||||
presence.RoomVersion,
|
||||
presence.UpdatedAtMS,
|
||||
appCode,
|
||||
presence.UserID,
|
||||
presence.RoomID,
|
||||
roomPresenceStatusActiveSQL,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetCurrentRoomPresence 查询用户当前 active 房间,不扫描发现页列表。
|
||||
func (r *Repository) GetCurrentRoomPresence(ctx context.Context, userID int64) (roomservice.RoomPresence, bool, error) {
|
||||
row := r.db.QueryRowContext(ctx,
|
||||
|
||||
@ -572,6 +572,9 @@ const roomFollowSelectColumns = `
|
||||
JOIN room_list_entries r ON r.app_code = f.app_code AND r.room_id = f.room_id`
|
||||
|
||||
func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
|
||||
if len(query.OwnerUserIDs) > 0 {
|
||||
return buildRoomListByOwnersQuerySQL(query)
|
||||
}
|
||||
regionID := query.VisibleRegionID
|
||||
if regionID < 0 {
|
||||
regionID = 0
|
||||
@ -674,6 +677,40 @@ func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
|
||||
return selectSQL + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY " + pinRankExpr + " ASC, " + pinWeightExpr + " DESC, " + pinExpiresExpr + " DESC, r.sort_score DESC, r.room_id ASC\n\tLIMIT ?", args
|
||||
}
|
||||
|
||||
func buildRoomListByOwnersQuerySQL(query roomservice.RoomListQuery) (string, []any) {
|
||||
where := []string{"app_code = ?", "status = ?"}
|
||||
args := []any{appcode.Normalize(query.AppCode), "active"}
|
||||
|
||||
placeholders := make([]string, 0, len(query.OwnerUserIDs))
|
||||
for _, ownerUserID := range query.OwnerUserIDs {
|
||||
placeholders = append(placeholders, "?")
|
||||
args = append(args, ownerUserID)
|
||||
}
|
||||
where = append(where, "owner_user_id IN ("+strings.Join(placeholders, ",")+")")
|
||||
|
||||
if strings.TrimSpace(query.Query) != "" {
|
||||
where = append(where, "(room_id LIKE ? ESCAPE '\\\\' OR room_short_id LIKE ? ESCAPE '\\\\' OR title LIKE ? ESCAPE '\\\\')")
|
||||
like := "%" + escapeRoomListLike(query.Query) + "%"
|
||||
args = append(args, like, like, like)
|
||||
}
|
||||
|
||||
if query.Tab == "new" {
|
||||
if query.CursorRoomID != "" {
|
||||
where = append(where, "(created_at_ms < ? OR (created_at_ms = ? AND room_id > ?))")
|
||||
args = append(args, query.CursorCreatedAtMS, query.CursorCreatedAtMS, query.CursorRoomID)
|
||||
}
|
||||
args = append(args, query.Limit)
|
||||
return roomListSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY created_at_ms DESC, room_id ASC\n\tLIMIT ?", args
|
||||
}
|
||||
|
||||
if query.CursorRoomID != "" {
|
||||
where = append(where, "(sort_score < ? OR (sort_score = ? AND room_id > ?))")
|
||||
args = append(args, query.CursorSortScore, query.CursorSortScore, query.CursorRoomID)
|
||||
}
|
||||
args = append(args, query.Limit)
|
||||
return roomListSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY sort_score DESC, room_id ASC\n\tLIMIT ?", args
|
||||
}
|
||||
|
||||
func normalizeRoomListSQLCountryCode(countryCode string) string {
|
||||
countryCode = strings.ToUpper(strings.TrimSpace(countryCode))
|
||||
if len(countryCode) < 2 || len(countryCode) > 3 {
|
||||
|
||||
@ -485,6 +485,13 @@ func (s *Server) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (*
|
||||
return mapServiceResult(s.svc.ListRooms(ctx, req))
|
||||
}
|
||||
|
||||
// ListRoomsByOwners 代理到 owner 批量房间卡片读模型。
|
||||
func (s *Server) ListRoomsByOwners(ctx context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
// owner 集合由上游业务归属解析后注入,room-service 只按房间 owner 投影批量读取卡片。
|
||||
ctx = contextWithMetaApp(ctx, req.GetMeta())
|
||||
return mapServiceResult(s.svc.ListRoomsByOwners(ctx, req))
|
||||
}
|
||||
|
||||
// ListRoomFeeds 代理到 Mine 页用户房间流读模型。
|
||||
func (s *Server) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
|
||||
// feed 查询只读用户到房间索引,并 join 房间卡片投影,不扫描 Room Cell 内存集合。
|
||||
|
||||
@ -811,6 +811,7 @@ CREATE TABLE IF NOT EXISTS agencies (
|
||||
owner_user_id BIGINT NOT NULL COMMENT '房主用户 ID',
|
||||
parent_bd_user_id BIGINT NOT NULL COMMENT '父级BD用户 ID',
|
||||
name VARCHAR(128) NOT NULL COMMENT '名称',
|
||||
avatar VARCHAR(512) NOT NULL DEFAULT '' COMMENT '公会头像',
|
||||
status VARCHAR(32) NOT NULL COMMENT '业务状态',
|
||||
join_enabled BOOLEAN NOT NULL COMMENT '加入是否启用',
|
||||
max_hosts INT NOT NULL COMMENT '最大主播',
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
ALTER TABLE agencies
|
||||
ADD COLUMN avatar VARCHAR(512) NOT NULL DEFAULT '' COMMENT '公会头像' AFTER name;
|
||||
|
||||
UPDATE agencies a
|
||||
JOIN users u
|
||||
ON u.app_code = a.app_code AND u.user_id = a.owner_user_id
|
||||
SET a.avatar = COALESCE(u.avatar, '')
|
||||
WHERE a.avatar = '';
|
||||
@ -128,6 +128,8 @@ const (
|
||||
CommandTypeDeleteAgency = "admin_delete_agency"
|
||||
// CommandTypeSetAgencyJoinEnabled 记录后台设置 Agency 入会开关命令。
|
||||
CommandTypeSetAgencyJoinEnabled = "admin_set_agency_join_enabled"
|
||||
// CommandTypeUpdateAgencyProfile 记录 Agency owner 修改独立资料的命令。
|
||||
CommandTypeUpdateAgencyProfile = "update_agency_profile"
|
||||
// CommandTypeAdminAddAgencyHost 记录后台直接把用户添加为 Agency Host 的命令。
|
||||
CommandTypeAdminAddAgencyHost = "admin_add_agency_host"
|
||||
// CommandTypeCreateCoinSeller 记录后台创建币商身份命令。
|
||||
@ -171,7 +173,7 @@ type Agency struct {
|
||||
RegionID int64
|
||||
ParentBDUserID int64
|
||||
Name string
|
||||
OwnerAvatar string
|
||||
Avatar string
|
||||
ActiveHostCount int32
|
||||
Status string
|
||||
JoinEnabled bool
|
||||
|
||||
@ -294,6 +294,18 @@ type User struct {
|
||||
UpdatedAtMs int64
|
||||
}
|
||||
|
||||
// RoomBasicUser 是房间首屏热路径使用的最小用户展示资料,不能混入国家、靓号详情或装扮字段。
|
||||
type RoomBasicUser struct {
|
||||
// UserID 是系统内部不可变用户 ID,调用方用它和麦位/房主/当前用户状态关联。
|
||||
UserID int64
|
||||
// Username 是用户当前基础昵称;为空时客户端按 display_user_id 或 user_id 兜底。
|
||||
Username string
|
||||
// Avatar 是用户当前基础头像 URL;装扮头像框不属于这个结构。
|
||||
Avatar string
|
||||
// DisplayUserID 是房间首屏展示短号;过期靓号在 SQL 内兜底为默认短号。
|
||||
DisplayUserID string
|
||||
}
|
||||
|
||||
// ProfileStats 是我的页顶部统计 read model,只保存预聚合计数。
|
||||
type ProfileStats struct {
|
||||
// AppCode 是统计所属 App,关系链和礼物统计都必须在 App 内隔离。
|
||||
|
||||
@ -390,6 +390,28 @@ type SetAgencyJoinEnabledCommand struct {
|
||||
NowMs int64
|
||||
}
|
||||
|
||||
// UpdateAgencyProfileInput 是 Agency owner 修改独立组织资料的外部输入。
|
||||
type UpdateAgencyProfileInput struct {
|
||||
CommandID string
|
||||
OperatorUserID int64
|
||||
AgencyID int64
|
||||
Name *string
|
||||
Avatar *string
|
||||
RequestID string
|
||||
}
|
||||
|
||||
// UpdateAgencyProfileCommand 是修改 Agency 独立资料事务需要的完整命令。
|
||||
type UpdateAgencyProfileCommand struct {
|
||||
CommandID string
|
||||
OperatorUserID int64
|
||||
AgencyID int64
|
||||
Name *string
|
||||
Avatar *string
|
||||
RequestID string
|
||||
EventID int64
|
||||
NowMs int64
|
||||
}
|
||||
|
||||
// AdminAddAgencyHostInput 是后台直接添加 Agency Host 的外部输入。
|
||||
type AdminAddAgencyHostInput struct {
|
||||
CommandID string
|
||||
|
||||
@ -45,6 +45,7 @@ type Repository interface {
|
||||
ListActiveCoinSellersInMyRegion(ctx context.Context, userID int64) ([]hostdomain.CoinSellerListItem, error)
|
||||
GetUserRoleSummary(ctx context.Context, userID int64) (hostdomain.UserRoleSummary, error)
|
||||
GetAgency(ctx context.Context, agencyID int64) (hostdomain.Agency, error)
|
||||
UpdateAgencyProfile(ctx context.Context, command UpdateAgencyProfileCommand) (hostdomain.Agency, error)
|
||||
HasActiveAgencyOwner(ctx context.Context, userID int64) (int64, bool, error)
|
||||
HasActiveManagerProfile(ctx context.Context, userID int64) (bool, error)
|
||||
HasActiveManagerCapability(ctx context.Context, userID int64, capability string) (bool, error)
|
||||
@ -208,15 +209,55 @@ func (s *Service) GetAgency(ctx context.Context, agencyID int64) (hostdomain.Age
|
||||
return s.repository.GetAgency(ctx, agencyID)
|
||||
}
|
||||
|
||||
// UpdateAgencyProfile 只修改 Agency 独立组织资料,不回写 owner 用户昵称或头像。
|
||||
func (s *Service) UpdateAgencyProfile(ctx context.Context, command UpdateAgencyProfileInput) (hostdomain.Agency, error) {
|
||||
if err := s.requireWriteDependencies(); err != nil {
|
||||
return hostdomain.Agency{}, err
|
||||
}
|
||||
if strings.TrimSpace(command.CommandID) == "" || command.OperatorUserID <= 0 || command.AgencyID <= 0 {
|
||||
return hostdomain.Agency{}, xerr.New(xerr.InvalidArgument, "command_id, operator_user_id and agency_id are required")
|
||||
}
|
||||
if command.Name == nil && command.Avatar == nil {
|
||||
return hostdomain.Agency{}, xerr.New(xerr.InvalidArgument, "name or avatar is required")
|
||||
}
|
||||
var name *string
|
||||
if command.Name != nil {
|
||||
trimmed := strings.TrimSpace(*command.Name)
|
||||
if trimmed == "" {
|
||||
return hostdomain.Agency{}, xerr.New(xerr.InvalidArgument, "agency name is required")
|
||||
}
|
||||
name = &trimmed
|
||||
}
|
||||
var avatar *string
|
||||
if command.Avatar != nil {
|
||||
trimmed := strings.TrimSpace(*command.Avatar)
|
||||
if trimmed == "" {
|
||||
return hostdomain.Agency{}, xerr.New(xerr.InvalidArgument, "agency avatar is required")
|
||||
}
|
||||
avatar = &trimmed
|
||||
}
|
||||
|
||||
return s.repository.UpdateAgencyProfile(ctx, UpdateAgencyProfileCommand{
|
||||
CommandID: strings.TrimSpace(command.CommandID),
|
||||
OperatorUserID: command.OperatorUserID,
|
||||
AgencyID: command.AgencyID,
|
||||
Name: name,
|
||||
Avatar: avatar,
|
||||
RequestID: strings.TrimSpace(command.RequestID),
|
||||
EventID: s.nextEventIDRange(1),
|
||||
NowMs: s.now().UnixMilli(),
|
||||
})
|
||||
}
|
||||
|
||||
// InviteAgency 由 BD 或 BD Leader 创建 Agency owner 邀请;目标用户接受前不创建 Agency 身份。
|
||||
func (s *Service) InviteAgency(ctx context.Context, command InviteAgencyInput) (hostdomain.RoleInvitation, error) {
|
||||
if err := s.requireWriteDependencies(); err != nil {
|
||||
return hostdomain.RoleInvitation{}, err
|
||||
}
|
||||
// Agency 名称在邀请动作里固化,接受时按这份快照创建 Agency,避免目标确认后前端再传入不同名称。
|
||||
// Agency 名称允许邀请方显式覆盖;为空时在目标接受并真正创建 Agency 时复制 owner 当前昵称/短 ID。
|
||||
agencyName := strings.TrimSpace(command.AgencyName)
|
||||
if strings.TrimSpace(command.CommandID) == "" || command.InviterUserID <= 0 || command.TargetUserID <= 0 || agencyName == "" {
|
||||
return hostdomain.RoleInvitation{}, xerr.New(xerr.InvalidArgument, "command_id, inviter_user_id, target_user_id and agency_name are required")
|
||||
if strings.TrimSpace(command.CommandID) == "" || command.InviterUserID <= 0 || command.TargetUserID <= 0 {
|
||||
return hostdomain.RoleInvitation{}, xerr.New(xerr.InvalidArgument, "command_id, inviter_user_id and target_user_id are required")
|
||||
}
|
||||
nowMs := s.now().UnixMilli()
|
||||
|
||||
@ -501,8 +542,8 @@ func (s *Service) CreateAgency(ctx context.Context, command CreateAgencyInput) (
|
||||
return hostdomain.CreateAgencyResult{}, err
|
||||
}
|
||||
name := strings.TrimSpace(command.Name)
|
||||
if strings.TrimSpace(command.CommandID) == "" || command.AdminUserID <= 0 || command.OwnerUserID <= 0 || name == "" {
|
||||
return hostdomain.CreateAgencyResult{}, xerr.New(xerr.InvalidArgument, "command_id, admin_user_id, owner_user_id and name are required")
|
||||
if strings.TrimSpace(command.CommandID) == "" || command.AdminUserID <= 0 || command.OwnerUserID <= 0 {
|
||||
return hostdomain.CreateAgencyResult{}, xerr.New(xerr.InvalidArgument, "command_id, admin_user_id and owner_user_id are required")
|
||||
}
|
||||
if command.ParentBDUserID < 0 {
|
||||
return hostdomain.CreateAgencyResult{}, xerr.New(xerr.InvalidArgument, "parent_bd_user_id must not be negative")
|
||||
|
||||
@ -1101,7 +1101,7 @@ func TestAdminCreateAgencyControlsAppSearch(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("SearchAgencies list failed: %v", err)
|
||||
}
|
||||
if len(agencies) != 1 || agencies[0].AgencyID != created.Agency.AgencyID || agencies[0].OwnerAvatar != "https://cdn.example/owner-901.png" || agencies[0].ActiveHostCount != 1 {
|
||||
if len(agencies) != 1 || agencies[0].AgencyID != created.Agency.AgencyID || agencies[0].Avatar != "https://cdn.example/owner-901.png" || agencies[0].ActiveHostCount != 1 {
|
||||
t.Fatalf("created agency list should be scoped by country with display fields: %+v", agencies)
|
||||
}
|
||||
if agencies[0].RegionID != 30 {
|
||||
@ -1121,6 +1121,13 @@ func TestAdminCreateAgencyControlsAppSearch(t *testing.T) {
|
||||
if len(agencies) != 1 || agencies[0].AgencyID != created.Agency.AgencyID {
|
||||
t.Fatalf("created agency should be searchable by owner display id: %+v", agencies)
|
||||
}
|
||||
agencies, err = svc.SearchAgencies(ctx, 902, displayID(900), 20)
|
||||
if err != nil {
|
||||
t.Fatalf("SearchAgencies by non-owner parent BD display id failed: %v", err)
|
||||
}
|
||||
if len(agencies) != 0 {
|
||||
t.Fatalf("parent BD display id must not expand to child agencies: %+v", agencies)
|
||||
}
|
||||
|
||||
disabledJoin, err := svc.SetAgencyJoinEnabled(ctx, hostservice.SetAgencyJoinEnabledInput{
|
||||
CommandID: "admin-disable-agency-join-901",
|
||||
@ -1226,6 +1233,96 @@ func TestAdminCreateAgencyControlsAppSearch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgencyProfileDefaultsAndStaysIndependent(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repository := mysqltest.NewRepository(t)
|
||||
repository.PutUser(userdomain.User{
|
||||
UserID: 921,
|
||||
DefaultDisplayUserID: displayID(921),
|
||||
CurrentDisplayUserID: displayID(921),
|
||||
Username: "Owner Nick",
|
||||
Avatar: "https://cdn.example/owner-old.png",
|
||||
Country: "CN",
|
||||
RegionID: 30,
|
||||
ProfileCompleted: true,
|
||||
ProfileCompletedAtMs: 1,
|
||||
OnboardingStatus: userdomain.OnboardingStatusCompleted,
|
||||
Status: userdomain.StatusActive,
|
||||
})
|
||||
seedActiveUser(t, repository, 922, 30)
|
||||
svc := newHostService(repository, 5200, 6200)
|
||||
|
||||
created, err := svc.CreateAgency(ctx, hostservice.CreateAgencyInput{
|
||||
CommandID: "admin-create-agency-default-profile",
|
||||
AdminUserID: 1,
|
||||
OwnerUserID: 921,
|
||||
JoinEnabled: true,
|
||||
RequestID: "req-agency-default-profile",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateAgency with default profile failed: %v", err)
|
||||
}
|
||||
if created.Agency.Name != "Owner Nick" || created.Agency.Avatar != "https://cdn.example/owner-old.png" {
|
||||
t.Fatalf("agency must copy owner profile once on create: %+v", created.Agency)
|
||||
}
|
||||
|
||||
newName := "Agency New"
|
||||
newAvatar := "https://cdn.example/agency-new.png"
|
||||
updated, err := svc.UpdateAgencyProfile(ctx, hostservice.UpdateAgencyProfileInput{
|
||||
CommandID: "agency-profile-update-owner",
|
||||
OperatorUserID: 921,
|
||||
AgencyID: created.Agency.AgencyID,
|
||||
Name: &newName,
|
||||
Avatar: &newAvatar,
|
||||
RequestID: "req-agency-profile-update-owner",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateAgencyProfile by owner failed: %v", err)
|
||||
}
|
||||
if updated.Name != newName || updated.Avatar != newAvatar {
|
||||
t.Fatalf("agency profile update mismatch: %+v", updated)
|
||||
}
|
||||
owner, err := repository.GetUser(ctx, 921)
|
||||
if err != nil {
|
||||
t.Fatalf("GetUser after agency update failed: %v", err)
|
||||
}
|
||||
if owner.Username != "Owner Nick" || owner.Avatar != "https://cdn.example/owner-old.png" {
|
||||
t.Fatalf("agency profile update must not modify owner user: %+v", owner)
|
||||
}
|
||||
|
||||
repository.PutUser(userdomain.User{
|
||||
UserID: 921,
|
||||
DefaultDisplayUserID: displayID(921),
|
||||
CurrentDisplayUserID: displayID(921),
|
||||
Username: "Owner New",
|
||||
Avatar: "https://cdn.example/owner-new.png",
|
||||
Country: "CN",
|
||||
RegionID: 30,
|
||||
ProfileCompleted: true,
|
||||
ProfileCompletedAtMs: 1,
|
||||
OnboardingStatus: userdomain.OnboardingStatusCompleted,
|
||||
Status: userdomain.StatusActive,
|
||||
})
|
||||
afterUserChange, err := svc.GetAgency(ctx, created.Agency.AgencyID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetAgency after owner profile change failed: %v", err)
|
||||
}
|
||||
if afterUserChange.Name != newName || afterUserChange.Avatar != newAvatar {
|
||||
t.Fatalf("owner profile change must not sync back to agency: %+v", afterUserChange)
|
||||
}
|
||||
|
||||
_, err = svc.UpdateAgencyProfile(ctx, hostservice.UpdateAgencyProfileInput{
|
||||
CommandID: "agency-profile-update-non-owner",
|
||||
OperatorUserID: 922,
|
||||
AgencyID: created.Agency.AgencyID,
|
||||
Name: &newName,
|
||||
RequestID: "req-agency-profile-update-non-owner",
|
||||
})
|
||||
if got := xerr.CodeOf(err); got != xerr.PermissionDenied {
|
||||
t.Fatalf("non owner agency update must be denied: got %s err=%v", got, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminCreateAgencyWithoutParentBD(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repository := mysqltest.NewRepository(t)
|
||||
|
||||
@ -216,6 +216,10 @@ func (r *fakeModerationRepository) BatchGetUsers(context.Context, []int64) (map[
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *fakeModerationRepository) BatchGetRoomBasicUsers(context.Context, []int64) (map[int64]userdomain.RoomBasicUser, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *fakeModerationRepository) FindInviteReferrerByCode(_ context.Context, appCode string, inviteCode string) (userdomain.User, error) {
|
||||
r.lastFindAppCode = appCode
|
||||
r.lastFindInviteCode = inviteCode
|
||||
|
||||
@ -45,6 +45,8 @@ type UserRepository interface {
|
||||
BusinessUserLookup(ctx context.Context, keyword string, numericKeyword bool, pageSize int32) ([]userdomain.BusinessUserLookupItem, error)
|
||||
// BatchGetUsers 批量查询用户主状态,缺失用户不应返回占位对象。
|
||||
BatchGetUsers(ctx context.Context, userIDs []int64) (map[int64]userdomain.User, error)
|
||||
// BatchGetRoomBasicUsers 批量查询房间首屏最小用户资料,不触发完整用户主状态投影。
|
||||
BatchGetRoomBasicUsers(ctx context.Context, userIDs []int64) (map[int64]userdomain.RoomBasicUser, error)
|
||||
// GetInviteAttribution 按被邀请用户读取邀请归因快照;无关系时返回 Found=false。
|
||||
GetInviteAttribution(ctx context.Context, invitedUserID int64) (invitedomain.Attribution, error)
|
||||
// FindInviteReferrerByCode 按 active 邀请码读取归属用户,供 H5 绑定页搜索同区域邀请人。
|
||||
|
||||
@ -94,6 +94,25 @@ func (s *Service) BatchGetUsers(ctx context.Context, userIDs []int64) (map[int64
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// BatchGetRoomBasicUsers 批量查询房间首屏最小用户资料。
|
||||
func (s *Service) BatchGetRoomBasicUsers(ctx context.Context, userIDs []int64) (map[int64]userdomain.RoomBasicUser, error) {
|
||||
if len(userIDs) == 0 {
|
||||
// 空批量请求返回空 map,gateway 可以直接输出空 profiles。
|
||||
return map[int64]userdomain.RoomBasicUser{}, nil
|
||||
}
|
||||
for _, userID := range userIDs {
|
||||
if userID <= 0 {
|
||||
// room-service 只接受正 user_id;这里继续对调用方输入做边界收敛。
|
||||
return nil, xerr.New(xerr.InvalidArgument, "user_ids contains invalid value")
|
||||
}
|
||||
}
|
||||
if s.userRepository == nil {
|
||||
// 房间热路径也不能绕过 owner repository;无存储时明确返回不可用。
|
||||
return nil, xerr.New(xerr.Unavailable, "user repository is not configured")
|
||||
}
|
||||
return s.userRepository.BatchGetRoomBasicUsers(ctx, userIDs)
|
||||
}
|
||||
|
||||
// ListUserIDs returns active user IDs for low-frequency backend fanout tasks.
|
||||
func (s *Service) ListUserIDs(ctx context.Context, filter userdomain.UserIDPageFilter) ([]int64, int64, bool, error) {
|
||||
if s.userRepository == nil {
|
||||
|
||||
@ -315,8 +315,12 @@ func (r *Repository) CreateAgency(ctx context.Context, command hostservice.Creat
|
||||
return hostdomain.CreateAgencyResult{}, err
|
||||
}
|
||||
|
||||
agencyName, agencyAvatar, err := defaultAgencyProfileFromOwner(ctx, tx, command.OwnerUserID, command.Name)
|
||||
if err != nil {
|
||||
return hostdomain.CreateAgencyResult{}, err
|
||||
}
|
||||
// max_hosts 是历史兼容字段,当前业务不再限制主播数量,新建 Agency 固化为 0。
|
||||
agency := hostdomain.Agency{AgencyID: command.AgencyID, OwnerUserID: command.OwnerUserID, RegionID: regionID, ParentBDUserID: command.ParentBDUserID, Name: command.Name, Status: hostdomain.AgencyStatusActive, JoinEnabled: command.JoinEnabled, MaxHosts: 0, CreatedByUserID: command.AdminUserID, CreatedAtMs: command.NowMs, UpdatedAtMs: command.NowMs}
|
||||
agency := hostdomain.Agency{AgencyID: command.AgencyID, OwnerUserID: command.OwnerUserID, RegionID: regionID, ParentBDUserID: command.ParentBDUserID, Name: agencyName, Avatar: agencyAvatar, Status: hostdomain.AgencyStatusActive, JoinEnabled: command.JoinEnabled, MaxHosts: 0, CreatedByUserID: command.AdminUserID, CreatedAtMs: command.NowMs, UpdatedAtMs: command.NowMs}
|
||||
if err := insertAgency(ctx, tx, agency); err != nil {
|
||||
return hostdomain.CreateAgencyResult{}, mapHostDuplicateError(err)
|
||||
}
|
||||
@ -590,6 +594,53 @@ func (r *Repository) SetAgencyJoinEnabled(ctx context.Context, command hostservi
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateAgencyProfile 只允许 active Agency owner 修改组织独立资料。
|
||||
func (r *Repository) UpdateAgencyProfile(ctx context.Context, command hostservice.UpdateAgencyProfileCommand) (hostdomain.Agency, error) {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return hostdomain.Agency{}, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if existing, ok, err := commandResult(ctx, tx, command.CommandID); err != nil {
|
||||
return hostdomain.Agency{}, err
|
||||
} else if ok {
|
||||
if err := requireCommandResult(existing, hostdomain.CommandTypeUpdateAgencyProfile, hostdomain.ResultTypeAgency); err != nil {
|
||||
return hostdomain.Agency{}, err
|
||||
}
|
||||
return queryAgency(ctx, tx, "WHERE agency_id = ?", existing.ResultID)
|
||||
}
|
||||
|
||||
agency, err := queryAgency(ctx, tx, "WHERE agency_id = ? FOR UPDATE", command.AgencyID)
|
||||
if err != nil {
|
||||
return hostdomain.Agency{}, err
|
||||
}
|
||||
if agency.Status != hostdomain.AgencyStatusActive || agency.OwnerUserID != command.OperatorUserID {
|
||||
// Agency 资料的写权限只属于当前 active owner;普通成员、关闭团队和历史 owner 都不能改。
|
||||
return hostdomain.Agency{}, xerr.New(xerr.PermissionDenied, "permission denied")
|
||||
}
|
||||
if command.Name != nil {
|
||||
agency.Name = *command.Name
|
||||
}
|
||||
if command.Avatar != nil {
|
||||
agency.Avatar = *command.Avatar
|
||||
}
|
||||
agency.UpdatedAtMs = command.NowMs
|
||||
if err := updateAgencyProfile(ctx, tx, agency); err != nil {
|
||||
return hostdomain.Agency{}, err
|
||||
}
|
||||
if err := insertCommandResult(ctx, tx, hostdomain.CommandResult{CommandID: command.CommandID, CommandType: hostdomain.CommandTypeUpdateAgencyProfile, ResultType: hostdomain.ResultTypeAgency, ResultID: agency.AgencyID, CreatedAtMs: command.NowMs}); err != nil {
|
||||
return hostdomain.Agency{}, mapHostDuplicateError(err)
|
||||
}
|
||||
if err := insertHostOutbox(ctx, tx, command.EventID, "AgencyChanged", "agency", agency.AgencyID, command.NowMs); err != nil {
|
||||
return hostdomain.Agency{}, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return hostdomain.Agency{}, err
|
||||
}
|
||||
return agency, nil
|
||||
}
|
||||
|
||||
func (r *Repository) updateAgencyAdmin(ctx context.Context, commandID string, commandType string, agencyID int64, eventID int64, nowMs int64, mutate func(hostdomain.Agency) hostdomain.Agency) (hostdomain.Agency, error) {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
|
||||
@ -50,8 +50,15 @@ var (
|
||||
), 0),
|
||||
source, first_became_host_at_ms, created_at_ms, updated_at_ms`, userRegionProjection("host_profiles", "user_id"))
|
||||
agencyColumns = fmt.Sprintf(`
|
||||
agency_id, owner_user_id, %s, parent_bd_user_id, name, status,
|
||||
join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms`, userRegionProjection("agencies", "owner_user_id"))
|
||||
agency_id, owner_user_id, %s, parent_bd_user_id, name, avatar, status,
|
||||
join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms,
|
||||
COALESCE((
|
||||
SELECT COUNT(*)
|
||||
FROM agency_memberships active_member
|
||||
WHERE active_member.app_code = agencies.app_code
|
||||
AND active_member.agency_id = agencies.agency_id
|
||||
AND active_member.status = '%s'
|
||||
), 0)`, userRegionProjection("agencies", "owner_user_id"), hostdomain.MembershipStatusActive)
|
||||
bdProfileColumns = fmt.Sprintf(`
|
||||
user_id, role, %s, COALESCE(parent_leader_user_id, 0), status,
|
||||
created_by_user_id, created_at_ms, updated_at_ms`, userRegionProjection("bd_profiles", "user_id"))
|
||||
@ -118,6 +125,29 @@ func userRegionValue(ctx context.Context, q sqlQueryer, userID int64, lockClause
|
||||
return regionID, err
|
||||
}
|
||||
|
||||
func defaultAgencyProfileFromOwner(ctx context.Context, tx *sql.Tx, ownerUserID int64, explicitName string) (string, string, error) {
|
||||
snapshot, err := roleInvitationUserSnapshotByID(ctx, tx, ownerUserID)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
name := strings.TrimSpace(explicitName)
|
||||
if name == "" {
|
||||
// Agency 的默认资料只在创建身份这一刻从 owner 用户资料复制一次;
|
||||
// 后续用户资料和 Agency 资料完全分离,不能再在查询层动态兜底。
|
||||
name = firstNonBlank(snapshot.Username, snapshot.DisplayUserID, fmt.Sprintf("%d", ownerUserID))
|
||||
}
|
||||
return name, strings.TrimSpace(snapshot.Avatar), nil
|
||||
}
|
||||
|
||||
func firstNonBlank(values ...string) string {
|
||||
for _, value := range values {
|
||||
if trimmed := strings.TrimSpace(value); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func currentUserRegion(ctx context.Context, q sqlQueryer, userID int64, lockClause string) (int64, error) {
|
||||
// Host 领域不拥有 users 表,但所有角色流转都依赖用户当前有效区域。
|
||||
// 调用方需要串行化用户身份变化时传入 FOR UPDATE 来锁住 users 行。
|
||||
|
||||
@ -512,12 +512,17 @@ func (r *Repository) acceptAgencyInvitation(ctx context.Context, tx *sql.Tx, com
|
||||
|
||||
// Agency、拥有者 host_profile、拥有者成员关系是同一业务事实的三张表投影,
|
||||
// 必须全部创建成功后邀请才能进入已接受状态。
|
||||
agencyName, agencyAvatar, err := defaultAgencyProfileFromOwner(ctx, tx, invitation.TargetUserID, invitation.AgencyName)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
agency := hostdomain.Agency{
|
||||
AgencyID: command.AgencyID,
|
||||
OwnerUserID: invitation.TargetUserID,
|
||||
RegionID: targetRegionID,
|
||||
ParentBDUserID: invitation.ParentBDUserID,
|
||||
Name: invitation.AgencyName,
|
||||
Name: agencyName,
|
||||
Avatar: agencyAvatar,
|
||||
Status: hostdomain.AgencyStatusActive,
|
||||
JoinEnabled: true,
|
||||
// max_hosts 是历史兼容字段,当前业务不再限制主播数量。
|
||||
|
||||
@ -31,13 +31,13 @@ func (r *Repository) SearchAgencies(ctx context.Context, command hostservice.Sea
|
||||
COALESCE(owner.region_id, 0),
|
||||
a.parent_bd_user_id,
|
||||
a.name,
|
||||
a.avatar,
|
||||
a.status,
|
||||
a.join_enabled,
|
||||
a.max_hosts,
|
||||
a.created_by_user_id,
|
||||
a.created_at_ms,
|
||||
a.updated_at_ms,
|
||||
COALESCE(owner.avatar, ''),
|
||||
COUNT(active_member.membership_id)
|
||||
FROM agencies a
|
||||
INNER JOIN users owner
|
||||
@ -65,13 +65,13 @@ func (r *Repository) SearchAgencies(ctx context.Context, command hostservice.Sea
|
||||
owner.region_id,
|
||||
a.parent_bd_user_id,
|
||||
a.name,
|
||||
a.avatar,
|
||||
a.status,
|
||||
a.join_enabled,
|
||||
a.max_hosts,
|
||||
a.created_by_user_id,
|
||||
a.created_at_ms,
|
||||
a.updated_at_ms,
|
||||
owner.avatar
|
||||
a.updated_at_ms
|
||||
ORDER BY a.created_at_ms DESC, a.agency_id DESC
|
||||
LIMIT ?
|
||||
`
|
||||
@ -618,12 +618,14 @@ func scanAgency(scanner rowScanner) (hostdomain.Agency, error) {
|
||||
&agency.RegionID,
|
||||
&agency.ParentBDUserID,
|
||||
&agency.Name,
|
||||
&agency.Avatar,
|
||||
&agency.Status,
|
||||
&agency.JoinEnabled,
|
||||
&agency.MaxHosts,
|
||||
&agency.CreatedByUserID,
|
||||
&agency.CreatedAtMs,
|
||||
&agency.UpdatedAtMs,
|
||||
&agency.ActiveHostCount,
|
||||
)
|
||||
return agency, err
|
||||
}
|
||||
@ -636,13 +638,13 @@ func scanSearchAgency(scanner rowScanner) (hostdomain.Agency, error) {
|
||||
&agency.RegionID,
|
||||
&agency.ParentBDUserID,
|
||||
&agency.Name,
|
||||
&agency.Avatar,
|
||||
&agency.Status,
|
||||
&agency.JoinEnabled,
|
||||
&agency.MaxHosts,
|
||||
&agency.CreatedByUserID,
|
||||
&agency.CreatedAtMs,
|
||||
&agency.UpdatedAtMs,
|
||||
&agency.OwnerAvatar,
|
||||
&agency.ActiveHostCount,
|
||||
)
|
||||
return agency, err
|
||||
|
||||
@ -192,10 +192,10 @@ func insertAgency(ctx context.Context, tx *sql.Tx, agency hostdomain.Agency) err
|
||||
// 第一阶段只有接受 Agency 邀请时会创建 Agency。
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO agencies (
|
||||
app_code, agency_id, owner_user_id, parent_bd_user_id, name, status,
|
||||
app_code, agency_id, owner_user_id, parent_bd_user_id, name, avatar, status,
|
||||
join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, appcode.FromContext(ctx), agency.AgencyID, agency.OwnerUserID, agency.ParentBDUserID, agency.Name, agency.Status, agency.JoinEnabled, agency.MaxHosts, agency.CreatedByUserID, agency.CreatedAtMs, agency.UpdatedAtMs)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, appcode.FromContext(ctx), agency.AgencyID, agency.OwnerUserID, agency.ParentBDUserID, agency.Name, agency.Avatar, agency.Status, agency.JoinEnabled, agency.MaxHosts, agency.CreatedByUserID, agency.CreatedAtMs, agency.UpdatedAtMs)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -209,6 +209,16 @@ func updateAgencyAdminState(ctx context.Context, tx *sql.Tx, agency hostdomain.A
|
||||
return err
|
||||
}
|
||||
|
||||
func updateAgencyProfile(ctx context.Context, tx *sql.Tx, agency hostdomain.Agency) error {
|
||||
// Agency 资料是独立组织资料;这里绝不更新 users 表,也不从 owner 用户资料重新派生。
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
UPDATE agencies
|
||||
SET name = ?, avatar = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND agency_id = ?
|
||||
`, agency.Name, agency.Avatar, agency.UpdatedAtMs, appcode.FromContext(ctx), agency.AgencyID)
|
||||
return err
|
||||
}
|
||||
|
||||
func insertBDProfile(ctx context.Context, tx *sql.Tx, profile hostdomain.BDProfile) error {
|
||||
// 普通 BD 身份行和 host_profile 相互独立;BD 用户不会自动成为 Host,也不会隐式拥有 BD Leader 权限。
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
|
||||
@ -92,6 +92,49 @@ func (r *Repository) BatchGetUsers(ctx context.Context, userIDs []int64) (map[in
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
// BatchGetRoomBasicUsers 只读取房间首屏需要的基础展示字段,避免 JoinRoom lite 触发完整用户投影。
|
||||
func (r *Repository) BatchGetRoomBasicUsers(ctx context.Context, userIDs []int64) (map[int64]userdomain.RoomBasicUser, error) {
|
||||
placeholders := make([]string, 0, len(userIDs))
|
||||
args := make([]any, 0, len(userIDs)+2)
|
||||
nowMS := time.Now().UTC().UnixMilli()
|
||||
args = append(args, nowMS)
|
||||
for _, userID := range userIDs {
|
||||
placeholders = append(placeholders, "?")
|
||||
args = append(args, userID)
|
||||
}
|
||||
args = append(args, appcode.FromContext(ctx))
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, fmt.Sprintf(`
|
||||
SELECT user_id,
|
||||
COALESCE(username, ''),
|
||||
COALESCE(avatar, ''),
|
||||
CASE
|
||||
WHEN current_display_user_id_kind <> 'default'
|
||||
AND COALESCE(current_display_user_id_expires_at_ms, 0) > 0
|
||||
AND current_display_user_id_expires_at_ms <= ?
|
||||
THEN default_display_user_id
|
||||
ELSE current_display_user_id
|
||||
END
|
||||
FROM users FORCE INDEX (PRIMARY)
|
||||
WHERE user_id IN (%s)
|
||||
AND app_code = ?
|
||||
`, strings.Join(placeholders, ",")), args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
result := make(map[int64]userdomain.RoomBasicUser, len(userIDs))
|
||||
for rows.Next() {
|
||||
var user userdomain.RoomBasicUser
|
||||
if err := rows.Scan(&user.UserID, &user.Username, &user.Avatar, &user.DisplayUserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[user.UserID] = user
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
// ListUserIDs returns active user IDs in ascending order for cursor-based backend fanout.
|
||||
func (r *Repository) ListUserIDs(ctx context.Context, filter userdomain.UserIDPageFilter) ([]int64, error) {
|
||||
conditions := []string{"app_code = ?", "status = ?", "user_id > ?"}
|
||||
|
||||
@ -129,6 +129,11 @@ func (r *Repository) BatchGetUsers(ctx context.Context, userIDs []int64) (map[in
|
||||
return r.Repository.UserRepository().BatchGetUsers(ctx, userIDs)
|
||||
}
|
||||
|
||||
// BatchGetRoomBasicUsers 让测试 wrapper 继续满足房间首屏基础资料查询接口。
|
||||
func (r *Repository) BatchGetRoomBasicUsers(ctx context.Context, userIDs []int64) (map[int64]userdomain.RoomBasicUser, error) {
|
||||
return r.Repository.UserRepository().BatchGetRoomBasicUsers(ctx, userIDs)
|
||||
}
|
||||
|
||||
// ListUserIDs 让测试 wrapper 继续满足后台 fanout 目标用户查询接口。
|
||||
func (r *Repository) ListUserIDs(ctx context.Context, filter userdomain.UserIDPageFilter) ([]int64, error) {
|
||||
return r.Repository.UserRepository().ListUserIDs(ctx, filter)
|
||||
@ -866,18 +871,19 @@ func (r *Repository) PutAgency(agency hostdomain.Agency) {
|
||||
|
||||
_, err := r.schema.DB.ExecContext(context.Background(), `
|
||||
INSERT INTO agencies (
|
||||
agency_id, owner_user_id, parent_bd_user_id, name, status,
|
||||
agency_id, owner_user_id, parent_bd_user_id, name, avatar, status,
|
||||
join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
owner_user_id = VALUES(owner_user_id),
|
||||
parent_bd_user_id = VALUES(parent_bd_user_id),
|
||||
name = VALUES(name),
|
||||
avatar = VALUES(avatar),
|
||||
status = VALUES(status),
|
||||
join_enabled = VALUES(join_enabled),
|
||||
max_hosts = VALUES(max_hosts),
|
||||
updated_at_ms = VALUES(updated_at_ms)
|
||||
`, agency.AgencyID, agency.OwnerUserID, agency.ParentBDUserID, agency.Name, agency.Status, agency.JoinEnabled, agency.MaxHosts, agency.CreatedByUserID, agency.CreatedAtMs, agency.UpdatedAtMs)
|
||||
`, agency.AgencyID, agency.OwnerUserID, agency.ParentBDUserID, agency.Name, agency.Avatar, agency.Status, agency.JoinEnabled, agency.MaxHosts, agency.CreatedByUserID, agency.CreatedAtMs, agency.UpdatedAtMs)
|
||||
if err != nil {
|
||||
r.t.Fatalf("seed agency %d failed: %v", agency.AgencyID, err)
|
||||
}
|
||||
|
||||
@ -435,7 +435,7 @@ func toProtoAgency(agency hostdomain.Agency) *userv1.Agency {
|
||||
CreatedByUserId: agency.CreatedByUserID,
|
||||
CreatedAtMs: agency.CreatedAtMs,
|
||||
UpdatedAtMs: agency.UpdatedAtMs,
|
||||
Avatar: agency.OwnerAvatar,
|
||||
Avatar: agency.Avatar,
|
||||
HostCount: agency.ActiveHostCount,
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,6 +393,26 @@ func (s *Server) GetAgency(ctx context.Context, req *userv1.GetAgencyRequest) (*
|
||||
return &userv1.GetAgencyResponse{Agency: toProtoAgency(agency)}, nil
|
||||
}
|
||||
|
||||
// UpdateAgencyProfile 修改 Agency 独立资料;用户资料和 Agency 资料不会互相回写。
|
||||
func (s *Server) UpdateAgencyProfile(ctx context.Context, req *userv1.UpdateAgencyProfileRequest) (*userv1.UpdateAgencyProfileResponse, error) {
|
||||
if s.hostSvc == nil {
|
||||
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
|
||||
}
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
agency, err := s.hostSvc.UpdateAgencyProfile(ctx, hostservice.UpdateAgencyProfileInput{
|
||||
CommandID: req.GetCommandId(),
|
||||
OperatorUserID: req.GetOperatorUserId(),
|
||||
AgencyID: req.GetAgencyId(),
|
||||
Name: req.Name,
|
||||
Avatar: req.Avatar,
|
||||
RequestID: req.GetMeta().GetRequestId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &userv1.UpdateAgencyProfileResponse{Agency: toProtoAgency(agency)}, nil
|
||||
}
|
||||
|
||||
// CheckBusinessCapability 返回 H5/App 业务入口可用性,具体身份规则由 host service 统一判断。
|
||||
func (s *Server) CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) {
|
||||
if s.hostSvc == nil {
|
||||
|
||||
@ -660,6 +660,26 @@ func (s *Server) BatchGetUsers(ctx context.Context, req *userv1.BatchGetUsersReq
|
||||
return &userv1.BatchGetUsersResponse{Users: result}, nil
|
||||
}
|
||||
|
||||
// BatchGetRoomBasicUsers 批量返回房间首屏最小用户展示资料。
|
||||
func (s *Server) BatchGetRoomBasicUsers(ctx context.Context, req *userv1.BatchGetRoomBasicUsersRequest) (*userv1.BatchGetRoomBasicUsersResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
users, err := s.userSvc.BatchGetRoomBasicUsers(ctx, req.GetUserIds())
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
result := make(map[int64]*userv1.RoomBasicUser, len(users))
|
||||
for userID, user := range users {
|
||||
// 只透出首屏绘制必需字段,避免 gateway lite 路径拿到完整用户主状态。
|
||||
result[userID] = &userv1.RoomBasicUser{
|
||||
UserId: user.UserID,
|
||||
Username: user.Username,
|
||||
Avatar: user.Avatar,
|
||||
DisplayUserId: user.DisplayUserID,
|
||||
}
|
||||
}
|
||||
return &userv1.BatchGetRoomBasicUsersResponse{Users: result}, nil
|
||||
}
|
||||
|
||||
// ListUserIDs 为后台 fanout 任务返回稳定递增的用户 ID 游标页。
|
||||
func (s *Server) ListUserIDs(ctx context.Context, req *userv1.ListUserIDsRequest) (*userv1.ListUserIDsResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user