游戏id修改
This commit is contained in:
parent
dedf6e8382
commit
d4eef547a8
File diff suppressed because it is too large
Load Diff
@ -1187,6 +1187,27 @@ message ConsumeLevelEventResponse {
|
||||
int64 reward_job_count = 6;
|
||||
}
|
||||
|
||||
message SetUserLevelRequest {
|
||||
RequestMeta meta = 1;
|
||||
string command_id = 2;
|
||||
int64 user_id = 3;
|
||||
string track = 4;
|
||||
int32 level = 5;
|
||||
int64 operator_user_id = 6;
|
||||
string reason = 7;
|
||||
}
|
||||
|
||||
message SetUserLevelResponse {
|
||||
string event_id = 1;
|
||||
string status = 2;
|
||||
string track = 3;
|
||||
int32 previous_level = 4;
|
||||
int32 new_level = 5;
|
||||
int64 total_value = 6;
|
||||
int64 reward_job_count = 7;
|
||||
int64 server_time_ms = 8;
|
||||
}
|
||||
|
||||
message RegistrationLevelBadgeGrant {
|
||||
string track = 1;
|
||||
int32 level = 2;
|
||||
@ -1844,6 +1865,7 @@ service GrowthLevelService {
|
||||
rpc BatchGetUserLevelDisplayProfiles(BatchGetUserLevelDisplayProfilesRequest) returns (BatchGetUserLevelDisplayProfilesResponse);
|
||||
rpc ListLevelRewards(ListLevelRewardsRequest) returns (ListLevelRewardsResponse);
|
||||
rpc ConsumeLevelEvent(ConsumeLevelEventRequest) returns (ConsumeLevelEventResponse);
|
||||
rpc SetUserLevel(SetUserLevelRequest) returns (SetUserLevelResponse);
|
||||
rpc IssueRegistrationLevelBadges(IssueRegistrationLevelBadgesRequest) returns (IssueRegistrationLevelBadgesResponse);
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.0
|
||||
// source: proto/activity/v1/activity.proto
|
||||
|
||||
@ -80,10 +80,10 @@ type ActivityServiceServer interface {
|
||||
type UnimplementedActivityServiceServer struct{}
|
||||
|
||||
func (UnimplementedActivityServiceServer) PingActivity(context.Context, *PingActivityRequest) (*PingActivityResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PingActivity not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method PingActivity not implemented")
|
||||
}
|
||||
func (UnimplementedActivityServiceServer) GetActivityStatus(context.Context, *GetActivityStatusRequest) (*GetActivityStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetActivityStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetActivityStatus not implemented")
|
||||
}
|
||||
func (UnimplementedActivityServiceServer) mustEmbedUnimplementedActivityServiceServer() {}
|
||||
func (UnimplementedActivityServiceServer) testEmbeddedByValue() {}
|
||||
@ -96,7 +96,7 @@ type UnsafeActivityServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterActivityServiceServer(s grpc.ServiceRegistrar, srv ActivityServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedActivityServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedActivityServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -289,25 +289,25 @@ type MessageInboxServiceServer interface {
|
||||
type UnimplementedMessageInboxServiceServer struct{}
|
||||
|
||||
func (UnimplementedMessageInboxServiceServer) ListMessageTabs(context.Context, *ListMessageTabsRequest) (*ListMessageTabsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListMessageTabs not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListMessageTabs not implemented")
|
||||
}
|
||||
func (UnimplementedMessageInboxServiceServer) ListInboxMessages(context.Context, *ListInboxMessagesRequest) (*ListInboxMessagesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListInboxMessages not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListInboxMessages not implemented")
|
||||
}
|
||||
func (UnimplementedMessageInboxServiceServer) MarkInboxMessageRead(context.Context, *MarkInboxMessageReadRequest) (*MarkInboxMessageReadResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method MarkInboxMessageRead not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method MarkInboxMessageRead not implemented")
|
||||
}
|
||||
func (UnimplementedMessageInboxServiceServer) MarkInboxSectionRead(context.Context, *MarkInboxSectionReadRequest) (*MarkInboxSectionReadResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method MarkInboxSectionRead not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method MarkInboxSectionRead not implemented")
|
||||
}
|
||||
func (UnimplementedMessageInboxServiceServer) DeleteInboxMessage(context.Context, *DeleteInboxMessageRequest) (*DeleteInboxMessageResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteInboxMessage not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteInboxMessage not implemented")
|
||||
}
|
||||
func (UnimplementedMessageInboxServiceServer) CreateInboxMessage(context.Context, *CreateInboxMessageRequest) (*CreateInboxMessageResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateInboxMessage not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateInboxMessage not implemented")
|
||||
}
|
||||
func (UnimplementedMessageInboxServiceServer) CreateFanoutJob(context.Context, *CreateFanoutJobRequest) (*CreateFanoutJobResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateFanoutJob not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateFanoutJob not implemented")
|
||||
}
|
||||
func (UnimplementedMessageInboxServiceServer) mustEmbedUnimplementedMessageInboxServiceServer() {}
|
||||
func (UnimplementedMessageInboxServiceServer) testEmbeddedByValue() {}
|
||||
@ -320,7 +320,7 @@ type UnsafeMessageInboxServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterMessageInboxServiceServer(s grpc.ServiceRegistrar, srv MessageInboxServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedMessageInboxServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedMessageInboxServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -597,19 +597,19 @@ type ActivityCronServiceServer interface {
|
||||
type UnimplementedActivityCronServiceServer struct{}
|
||||
|
||||
func (UnimplementedActivityCronServiceServer) ProcessMessageFanoutBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessMessageFanoutBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessMessageFanoutBatch not implemented")
|
||||
}
|
||||
func (UnimplementedActivityCronServiceServer) ProcessLevelRewardBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessLevelRewardBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessLevelRewardBatch not implemented")
|
||||
}
|
||||
func (UnimplementedActivityCronServiceServer) ProcessAchievementRewardBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessAchievementRewardBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessAchievementRewardBatch not implemented")
|
||||
}
|
||||
func (UnimplementedActivityCronServiceServer) ProcessRoomTurnoverRewardSettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessRoomTurnoverRewardSettlementBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessRoomTurnoverRewardSettlementBatch not implemented")
|
||||
}
|
||||
func (UnimplementedActivityCronServiceServer) ProcessWeeklyStarSettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessWeeklyStarSettlementBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessWeeklyStarSettlementBatch not implemented")
|
||||
}
|
||||
func (UnimplementedActivityCronServiceServer) mustEmbedUnimplementedActivityCronServiceServer() {}
|
||||
func (UnimplementedActivityCronServiceServer) testEmbeddedByValue() {}
|
||||
@ -622,7 +622,7 @@ type UnsafeActivityCronServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterActivityCronServiceServer(s grpc.ServiceRegistrar, srv ActivityCronServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedActivityCronServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedActivityCronServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -829,13 +829,13 @@ type TaskServiceServer interface {
|
||||
type UnimplementedTaskServiceServer struct{}
|
||||
|
||||
func (UnimplementedTaskServiceServer) ListUserTasks(context.Context, *ListUserTasksRequest) (*ListUserTasksResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListUserTasks not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListUserTasks not implemented")
|
||||
}
|
||||
func (UnimplementedTaskServiceServer) ClaimTaskReward(context.Context, *ClaimTaskRewardRequest) (*ClaimTaskRewardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ClaimTaskReward not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ClaimTaskReward not implemented")
|
||||
}
|
||||
func (UnimplementedTaskServiceServer) ConsumeTaskEvent(context.Context, *ConsumeTaskEventRequest) (*ConsumeTaskEventResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConsumeTaskEvent not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConsumeTaskEvent not implemented")
|
||||
}
|
||||
func (UnimplementedTaskServiceServer) mustEmbedUnimplementedTaskServiceServer() {}
|
||||
func (UnimplementedTaskServiceServer) testEmbeddedByValue() {}
|
||||
@ -848,7 +848,7 @@ type UnsafeTaskServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterTaskServiceServer(s grpc.ServiceRegistrar, srv TaskServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedTaskServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedTaskServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -942,6 +942,7 @@ const (
|
||||
GrowthLevelService_BatchGetUserLevelDisplayProfiles_FullMethodName = "/hyapp.activity.v1.GrowthLevelService/BatchGetUserLevelDisplayProfiles"
|
||||
GrowthLevelService_ListLevelRewards_FullMethodName = "/hyapp.activity.v1.GrowthLevelService/ListLevelRewards"
|
||||
GrowthLevelService_ConsumeLevelEvent_FullMethodName = "/hyapp.activity.v1.GrowthLevelService/ConsumeLevelEvent"
|
||||
GrowthLevelService_SetUserLevel_FullMethodName = "/hyapp.activity.v1.GrowthLevelService/SetUserLevel"
|
||||
GrowthLevelService_IssueRegistrationLevelBadges_FullMethodName = "/hyapp.activity.v1.GrowthLevelService/IssueRegistrationLevelBadges"
|
||||
)
|
||||
|
||||
@ -956,6 +957,7 @@ type GrowthLevelServiceClient interface {
|
||||
BatchGetUserLevelDisplayProfiles(ctx context.Context, in *BatchGetUserLevelDisplayProfilesRequest, opts ...grpc.CallOption) (*BatchGetUserLevelDisplayProfilesResponse, error)
|
||||
ListLevelRewards(ctx context.Context, in *ListLevelRewardsRequest, opts ...grpc.CallOption) (*ListLevelRewardsResponse, error)
|
||||
ConsumeLevelEvent(ctx context.Context, in *ConsumeLevelEventRequest, opts ...grpc.CallOption) (*ConsumeLevelEventResponse, error)
|
||||
SetUserLevel(ctx context.Context, in *SetUserLevelRequest, opts ...grpc.CallOption) (*SetUserLevelResponse, error)
|
||||
IssueRegistrationLevelBadges(ctx context.Context, in *IssueRegistrationLevelBadgesRequest, opts ...grpc.CallOption) (*IssueRegistrationLevelBadgesResponse, error)
|
||||
}
|
||||
|
||||
@ -1017,6 +1019,16 @@ func (c *growthLevelServiceClient) ConsumeLevelEvent(ctx context.Context, in *Co
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *growthLevelServiceClient) SetUserLevel(ctx context.Context, in *SetUserLevelRequest, opts ...grpc.CallOption) (*SetUserLevelResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SetUserLevelResponse)
|
||||
err := c.cc.Invoke(ctx, GrowthLevelService_SetUserLevel_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *growthLevelServiceClient) IssueRegistrationLevelBadges(ctx context.Context, in *IssueRegistrationLevelBadgesRequest, opts ...grpc.CallOption) (*IssueRegistrationLevelBadgesResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(IssueRegistrationLevelBadgesResponse)
|
||||
@ -1038,6 +1050,7 @@ type GrowthLevelServiceServer interface {
|
||||
BatchGetUserLevelDisplayProfiles(context.Context, *BatchGetUserLevelDisplayProfilesRequest) (*BatchGetUserLevelDisplayProfilesResponse, error)
|
||||
ListLevelRewards(context.Context, *ListLevelRewardsRequest) (*ListLevelRewardsResponse, error)
|
||||
ConsumeLevelEvent(context.Context, *ConsumeLevelEventRequest) (*ConsumeLevelEventResponse, error)
|
||||
SetUserLevel(context.Context, *SetUserLevelRequest) (*SetUserLevelResponse, error)
|
||||
IssueRegistrationLevelBadges(context.Context, *IssueRegistrationLevelBadgesRequest) (*IssueRegistrationLevelBadgesResponse, error)
|
||||
mustEmbedUnimplementedGrowthLevelServiceServer()
|
||||
}
|
||||
@ -1050,22 +1063,25 @@ type GrowthLevelServiceServer interface {
|
||||
type UnimplementedGrowthLevelServiceServer struct{}
|
||||
|
||||
func (UnimplementedGrowthLevelServiceServer) GetMyLevelOverview(context.Context, *GetMyLevelOverviewRequest) (*GetMyLevelOverviewResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetMyLevelOverview not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetMyLevelOverview not implemented")
|
||||
}
|
||||
func (UnimplementedGrowthLevelServiceServer) GetLevelTrack(context.Context, *GetLevelTrackRequest) (*GetLevelTrackResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetLevelTrack not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetLevelTrack not implemented")
|
||||
}
|
||||
func (UnimplementedGrowthLevelServiceServer) BatchGetUserLevelDisplayProfiles(context.Context, *BatchGetUserLevelDisplayProfilesRequest) (*BatchGetUserLevelDisplayProfilesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BatchGetUserLevelDisplayProfiles not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method BatchGetUserLevelDisplayProfiles not implemented")
|
||||
}
|
||||
func (UnimplementedGrowthLevelServiceServer) ListLevelRewards(context.Context, *ListLevelRewardsRequest) (*ListLevelRewardsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListLevelRewards not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListLevelRewards not implemented")
|
||||
}
|
||||
func (UnimplementedGrowthLevelServiceServer) ConsumeLevelEvent(context.Context, *ConsumeLevelEventRequest) (*ConsumeLevelEventResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConsumeLevelEvent not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConsumeLevelEvent not implemented")
|
||||
}
|
||||
func (UnimplementedGrowthLevelServiceServer) SetUserLevel(context.Context, *SetUserLevelRequest) (*SetUserLevelResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SetUserLevel not implemented")
|
||||
}
|
||||
func (UnimplementedGrowthLevelServiceServer) IssueRegistrationLevelBadges(context.Context, *IssueRegistrationLevelBadgesRequest) (*IssueRegistrationLevelBadgesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method IssueRegistrationLevelBadges not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method IssueRegistrationLevelBadges not implemented")
|
||||
}
|
||||
func (UnimplementedGrowthLevelServiceServer) mustEmbedUnimplementedGrowthLevelServiceServer() {}
|
||||
func (UnimplementedGrowthLevelServiceServer) testEmbeddedByValue() {}
|
||||
@ -1078,7 +1094,7 @@ type UnsafeGrowthLevelServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterGrowthLevelServiceServer(s grpc.ServiceRegistrar, srv GrowthLevelServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedGrowthLevelServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedGrowthLevelServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1178,6 +1194,24 @@ func _GrowthLevelService_ConsumeLevelEvent_Handler(srv interface{}, ctx context.
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GrowthLevelService_SetUserLevel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SetUserLevelRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GrowthLevelServiceServer).SetUserLevel(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: GrowthLevelService_SetUserLevel_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GrowthLevelServiceServer).SetUserLevel(ctx, req.(*SetUserLevelRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GrowthLevelService_IssueRegistrationLevelBadges_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(IssueRegistrationLevelBadgesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -1223,6 +1257,10 @@ var GrowthLevelService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ConsumeLevelEvent",
|
||||
Handler: _GrowthLevelService_ConsumeLevelEvent_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SetUserLevel",
|
||||
Handler: _GrowthLevelService_SetUserLevel_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "IssueRegistrationLevelBadges",
|
||||
Handler: _GrowthLevelService_IssueRegistrationLevelBadges_Handler,
|
||||
@ -1320,16 +1358,16 @@ type AchievementServiceServer interface {
|
||||
type UnimplementedAchievementServiceServer struct{}
|
||||
|
||||
func (UnimplementedAchievementServiceServer) ListAchievements(context.Context, *ListAchievementsRequest) (*ListAchievementsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListAchievements not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListAchievements not implemented")
|
||||
}
|
||||
func (UnimplementedAchievementServiceServer) ConsumeAchievementEvent(context.Context, *ConsumeAchievementEventRequest) (*ConsumeAchievementEventResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConsumeAchievementEvent not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConsumeAchievementEvent not implemented")
|
||||
}
|
||||
func (UnimplementedAchievementServiceServer) ListMyBadges(context.Context, *ListMyBadgesRequest) (*ListMyBadgesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListMyBadges not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListMyBadges not implemented")
|
||||
}
|
||||
func (UnimplementedAchievementServiceServer) SetBadgeDisplay(context.Context, *SetBadgeDisplayRequest) (*SetBadgeDisplayResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetBadgeDisplay not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetBadgeDisplay not implemented")
|
||||
}
|
||||
func (UnimplementedAchievementServiceServer) mustEmbedUnimplementedAchievementServiceServer() {}
|
||||
func (UnimplementedAchievementServiceServer) testEmbeddedByValue() {}
|
||||
@ -1342,7 +1380,7 @@ type UnsafeAchievementServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAchievementServiceServer(s grpc.ServiceRegistrar, srv AchievementServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAchievementServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAchievementServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1514,10 +1552,10 @@ type LuckyGiftServiceServer interface {
|
||||
type UnimplementedLuckyGiftServiceServer struct{}
|
||||
|
||||
func (UnimplementedLuckyGiftServiceServer) CheckLuckyGift(context.Context, *CheckLuckyGiftRequest) (*CheckLuckyGiftResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CheckLuckyGift not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CheckLuckyGift not implemented")
|
||||
}
|
||||
func (UnimplementedLuckyGiftServiceServer) ExecuteLuckyGiftDraw(context.Context, *ExecuteLuckyGiftDrawRequest) (*ExecuteLuckyGiftDrawResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ExecuteLuckyGiftDraw not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ExecuteLuckyGiftDraw not implemented")
|
||||
}
|
||||
func (UnimplementedLuckyGiftServiceServer) mustEmbedUnimplementedLuckyGiftServiceServer() {}
|
||||
func (UnimplementedLuckyGiftServiceServer) testEmbeddedByValue() {}
|
||||
@ -1530,7 +1568,7 @@ type UnsafeLuckyGiftServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterLuckyGiftServiceServer(s grpc.ServiceRegistrar, srv LuckyGiftServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedLuckyGiftServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedLuckyGiftServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1645,7 +1683,7 @@ type RoomTurnoverRewardServiceServer interface {
|
||||
type UnimplementedRoomTurnoverRewardServiceServer struct{}
|
||||
|
||||
func (UnimplementedRoomTurnoverRewardServiceServer) GetRoomTurnoverRewardStatus(context.Context, *GetRoomTurnoverRewardStatusRequest) (*GetRoomTurnoverRewardStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRoomTurnoverRewardStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRoomTurnoverRewardStatus not implemented")
|
||||
}
|
||||
func (UnimplementedRoomTurnoverRewardServiceServer) mustEmbedUnimplementedRoomTurnoverRewardServiceServer() {
|
||||
}
|
||||
@ -1659,7 +1697,7 @@ type UnsafeRoomTurnoverRewardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterRoomTurnoverRewardServiceServer(s grpc.ServiceRegistrar, srv RoomTurnoverRewardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRoomTurnoverRewardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedRoomTurnoverRewardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1778,13 +1816,13 @@ type WeeklyStarServiceServer interface {
|
||||
type UnimplementedWeeklyStarServiceServer struct{}
|
||||
|
||||
func (UnimplementedWeeklyStarServiceServer) GetWeeklyStarCurrent(context.Context, *GetWeeklyStarCurrentRequest) (*GetWeeklyStarCurrentResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetWeeklyStarCurrent not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetWeeklyStarCurrent not implemented")
|
||||
}
|
||||
func (UnimplementedWeeklyStarServiceServer) ListWeeklyStarLeaderboard(context.Context, *ListWeeklyStarLeaderboardRequest) (*ListWeeklyStarLeaderboardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarLeaderboard not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarLeaderboard not implemented")
|
||||
}
|
||||
func (UnimplementedWeeklyStarServiceServer) ListWeeklyStarHistory(context.Context, *ListWeeklyStarHistoryRequest) (*ListWeeklyStarHistoryResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarHistory not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarHistory not implemented")
|
||||
}
|
||||
func (UnimplementedWeeklyStarServiceServer) mustEmbedUnimplementedWeeklyStarServiceServer() {}
|
||||
func (UnimplementedWeeklyStarServiceServer) testEmbeddedByValue() {}
|
||||
@ -1797,7 +1835,7 @@ type UnsafeWeeklyStarServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterWeeklyStarServiceServer(s grpc.ServiceRegistrar, srv WeeklyStarServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedWeeklyStarServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedWeeklyStarServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1986,19 +2024,19 @@ type BroadcastServiceServer interface {
|
||||
type UnimplementedBroadcastServiceServer struct{}
|
||||
|
||||
func (UnimplementedBroadcastServiceServer) EnsureBroadcastGroups(context.Context, *EnsureBroadcastGroupsRequest) (*EnsureBroadcastGroupsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method EnsureBroadcastGroups not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method EnsureBroadcastGroups not implemented")
|
||||
}
|
||||
func (UnimplementedBroadcastServiceServer) PublishRegionBroadcast(context.Context, *PublishRegionBroadcastRequest) (*PublishBroadcastResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PublishRegionBroadcast not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method PublishRegionBroadcast not implemented")
|
||||
}
|
||||
func (UnimplementedBroadcastServiceServer) PublishGlobalBroadcast(context.Context, *PublishGlobalBroadcastRequest) (*PublishBroadcastResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PublishGlobalBroadcast not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method PublishGlobalBroadcast not implemented")
|
||||
}
|
||||
func (UnimplementedBroadcastServiceServer) RemoveRegionBroadcastMember(context.Context, *RemoveRegionBroadcastMemberRequest) (*RemoveRegionBroadcastMemberResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RemoveRegionBroadcastMember not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RemoveRegionBroadcastMember not implemented")
|
||||
}
|
||||
func (UnimplementedBroadcastServiceServer) ProcessBroadcastOutboxBatch(context.Context, *CronBatchRequest) (*ProcessBroadcastOutboxBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessBroadcastOutboxBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessBroadcastOutboxBatch not implemented")
|
||||
}
|
||||
func (UnimplementedBroadcastServiceServer) mustEmbedUnimplementedBroadcastServiceServer() {}
|
||||
func (UnimplementedBroadcastServiceServer) testEmbeddedByValue() {}
|
||||
@ -2011,7 +2049,7 @@ type UnsafeBroadcastServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterBroadcastServiceServer(s grpc.ServiceRegistrar, srv BroadcastServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedBroadcastServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedBroadcastServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -2192,7 +2230,7 @@ type RoomEventConsumerServiceServer interface {
|
||||
type UnimplementedRoomEventConsumerServiceServer struct{}
|
||||
|
||||
func (UnimplementedRoomEventConsumerServiceServer) ConsumeRoomEvent(context.Context, *ConsumeRoomEventRequest) (*ConsumeRoomEventResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConsumeRoomEvent not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConsumeRoomEvent not implemented")
|
||||
}
|
||||
func (UnimplementedRoomEventConsumerServiceServer) mustEmbedUnimplementedRoomEventConsumerServiceServer() {
|
||||
}
|
||||
@ -2206,7 +2244,7 @@ type UnsafeRoomEventConsumerServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterRoomEventConsumerServiceServer(s grpc.ServiceRegistrar, srv RoomEventConsumerServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRoomEventConsumerServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedRoomEventConsumerServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -2325,13 +2363,13 @@ type AdminTaskServiceServer interface {
|
||||
type UnimplementedAdminTaskServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminTaskServiceServer) ListTaskDefinitions(context.Context, *ListTaskDefinitionsRequest) (*ListTaskDefinitionsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListTaskDefinitions not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListTaskDefinitions not implemented")
|
||||
}
|
||||
func (UnimplementedAdminTaskServiceServer) UpsertTaskDefinition(context.Context, *UpsertTaskDefinitionRequest) (*UpsertTaskDefinitionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertTaskDefinition not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertTaskDefinition not implemented")
|
||||
}
|
||||
func (UnimplementedAdminTaskServiceServer) SetTaskDefinitionStatus(context.Context, *SetTaskDefinitionStatusRequest) (*SetTaskDefinitionStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetTaskDefinitionStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetTaskDefinitionStatus not implemented")
|
||||
}
|
||||
func (UnimplementedAdminTaskServiceServer) mustEmbedUnimplementedAdminTaskServiceServer() {}
|
||||
func (UnimplementedAdminTaskServiceServer) testEmbeddedByValue() {}
|
||||
@ -2344,7 +2382,7 @@ type UnsafeAdminTaskServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminTaskServiceServer(s grpc.ServiceRegistrar, srv AdminTaskServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminTaskServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminTaskServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -2494,10 +2532,10 @@ type RegistrationRewardServiceServer interface {
|
||||
type UnimplementedRegistrationRewardServiceServer struct{}
|
||||
|
||||
func (UnimplementedRegistrationRewardServiceServer) GetRegistrationRewardEligibility(context.Context, *GetRegistrationRewardEligibilityRequest) (*GetRegistrationRewardEligibilityResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRegistrationRewardEligibility not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRegistrationRewardEligibility not implemented")
|
||||
}
|
||||
func (UnimplementedRegistrationRewardServiceServer) IssueRegistrationReward(context.Context, *IssueRegistrationRewardRequest) (*IssueRegistrationRewardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method IssueRegistrationReward not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method IssueRegistrationReward not implemented")
|
||||
}
|
||||
func (UnimplementedRegistrationRewardServiceServer) mustEmbedUnimplementedRegistrationRewardServiceServer() {
|
||||
}
|
||||
@ -2511,7 +2549,7 @@ type UnsafeRegistrationRewardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterRegistrationRewardServiceServer(s grpc.ServiceRegistrar, srv RegistrationRewardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRegistrationRewardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedRegistrationRewardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -2652,13 +2690,13 @@ type AdminRegistrationRewardServiceServer interface {
|
||||
type UnimplementedAdminRegistrationRewardServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminRegistrationRewardServiceServer) GetRegistrationRewardConfig(context.Context, *GetRegistrationRewardConfigRequest) (*GetRegistrationRewardConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRegistrationRewardConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRegistrationRewardConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminRegistrationRewardServiceServer) UpdateRegistrationRewardConfig(context.Context, *UpdateRegistrationRewardConfigRequest) (*UpdateRegistrationRewardConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateRegistrationRewardConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateRegistrationRewardConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminRegistrationRewardServiceServer) ListRegistrationRewardClaims(context.Context, *ListRegistrationRewardClaimsRequest) (*ListRegistrationRewardClaimsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRegistrationRewardClaims not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRegistrationRewardClaims not implemented")
|
||||
}
|
||||
func (UnimplementedAdminRegistrationRewardServiceServer) mustEmbedUnimplementedAdminRegistrationRewardServiceServer() {
|
||||
}
|
||||
@ -2672,7 +2710,7 @@ type UnsafeAdminRegistrationRewardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminRegistrationRewardServiceServer(s grpc.ServiceRegistrar, srv AdminRegistrationRewardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminRegistrationRewardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminRegistrationRewardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -2822,10 +2860,10 @@ type FirstRechargeRewardServiceServer interface {
|
||||
type UnimplementedFirstRechargeRewardServiceServer struct{}
|
||||
|
||||
func (UnimplementedFirstRechargeRewardServiceServer) GetFirstRechargeRewardStatus(context.Context, *GetFirstRechargeRewardStatusRequest) (*GetFirstRechargeRewardStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetFirstRechargeRewardStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetFirstRechargeRewardStatus not implemented")
|
||||
}
|
||||
func (UnimplementedFirstRechargeRewardServiceServer) ConsumeFirstRechargeReward(context.Context, *ConsumeFirstRechargeRewardRequest) (*ConsumeFirstRechargeRewardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConsumeFirstRechargeReward not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConsumeFirstRechargeReward not implemented")
|
||||
}
|
||||
func (UnimplementedFirstRechargeRewardServiceServer) mustEmbedUnimplementedFirstRechargeRewardServiceServer() {
|
||||
}
|
||||
@ -2839,7 +2877,7 @@ type UnsafeFirstRechargeRewardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterFirstRechargeRewardServiceServer(s grpc.ServiceRegistrar, srv FirstRechargeRewardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedFirstRechargeRewardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedFirstRechargeRewardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -2980,13 +3018,13 @@ type AdminFirstRechargeRewardServiceServer interface {
|
||||
type UnimplementedAdminFirstRechargeRewardServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminFirstRechargeRewardServiceServer) GetFirstRechargeRewardConfig(context.Context, *GetFirstRechargeRewardConfigRequest) (*GetFirstRechargeRewardConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetFirstRechargeRewardConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetFirstRechargeRewardConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminFirstRechargeRewardServiceServer) UpdateFirstRechargeRewardConfig(context.Context, *UpdateFirstRechargeRewardConfigRequest) (*UpdateFirstRechargeRewardConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateFirstRechargeRewardConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateFirstRechargeRewardConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminFirstRechargeRewardServiceServer) ListFirstRechargeRewardClaims(context.Context, *ListFirstRechargeRewardClaimsRequest) (*ListFirstRechargeRewardClaimsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListFirstRechargeRewardClaims not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListFirstRechargeRewardClaims not implemented")
|
||||
}
|
||||
func (UnimplementedAdminFirstRechargeRewardServiceServer) mustEmbedUnimplementedAdminFirstRechargeRewardServiceServer() {
|
||||
}
|
||||
@ -3000,7 +3038,7 @@ type UnsafeAdminFirstRechargeRewardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminFirstRechargeRewardServiceServer(s grpc.ServiceRegistrar, srv AdminFirstRechargeRewardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminFirstRechargeRewardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminFirstRechargeRewardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -3150,10 +3188,10 @@ type CumulativeRechargeRewardServiceServer interface {
|
||||
type UnimplementedCumulativeRechargeRewardServiceServer struct{}
|
||||
|
||||
func (UnimplementedCumulativeRechargeRewardServiceServer) GetCumulativeRechargeRewardStatus(context.Context, *GetCumulativeRechargeRewardStatusRequest) (*GetCumulativeRechargeRewardStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetCumulativeRechargeRewardStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetCumulativeRechargeRewardStatus not implemented")
|
||||
}
|
||||
func (UnimplementedCumulativeRechargeRewardServiceServer) ConsumeCumulativeRechargeReward(context.Context, *ConsumeCumulativeRechargeRewardRequest) (*ConsumeCumulativeRechargeRewardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConsumeCumulativeRechargeReward not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConsumeCumulativeRechargeReward not implemented")
|
||||
}
|
||||
func (UnimplementedCumulativeRechargeRewardServiceServer) mustEmbedUnimplementedCumulativeRechargeRewardServiceServer() {
|
||||
}
|
||||
@ -3167,7 +3205,7 @@ type UnsafeCumulativeRechargeRewardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterCumulativeRechargeRewardServiceServer(s grpc.ServiceRegistrar, srv CumulativeRechargeRewardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedCumulativeRechargeRewardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedCumulativeRechargeRewardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -3308,13 +3346,13 @@ type AdminCumulativeRechargeRewardServiceServer interface {
|
||||
type UnimplementedAdminCumulativeRechargeRewardServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminCumulativeRechargeRewardServiceServer) GetCumulativeRechargeRewardConfig(context.Context, *GetCumulativeRechargeRewardConfigRequest) (*GetCumulativeRechargeRewardConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetCumulativeRechargeRewardConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetCumulativeRechargeRewardConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminCumulativeRechargeRewardServiceServer) UpdateCumulativeRechargeRewardConfig(context.Context, *UpdateCumulativeRechargeRewardConfigRequest) (*UpdateCumulativeRechargeRewardConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateCumulativeRechargeRewardConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateCumulativeRechargeRewardConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminCumulativeRechargeRewardServiceServer) ListCumulativeRechargeRewardGrants(context.Context, *ListCumulativeRechargeRewardGrantsRequest) (*ListCumulativeRechargeRewardGrantsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListCumulativeRechargeRewardGrants not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListCumulativeRechargeRewardGrants not implemented")
|
||||
}
|
||||
func (UnimplementedAdminCumulativeRechargeRewardServiceServer) mustEmbedUnimplementedAdminCumulativeRechargeRewardServiceServer() {
|
||||
}
|
||||
@ -3328,7 +3366,7 @@ type UnsafeAdminCumulativeRechargeRewardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminCumulativeRechargeRewardServiceServer(s grpc.ServiceRegistrar, srv AdminCumulativeRechargeRewardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminCumulativeRechargeRewardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminCumulativeRechargeRewardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -3504,16 +3542,16 @@ type AdminRoomTurnoverRewardServiceServer interface {
|
||||
type UnimplementedAdminRoomTurnoverRewardServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminRoomTurnoverRewardServiceServer) GetRoomTurnoverRewardConfig(context.Context, *GetRoomTurnoverRewardConfigRequest) (*GetRoomTurnoverRewardConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRoomTurnoverRewardConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRoomTurnoverRewardConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminRoomTurnoverRewardServiceServer) UpdateRoomTurnoverRewardConfig(context.Context, *UpdateRoomTurnoverRewardConfigRequest) (*UpdateRoomTurnoverRewardConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateRoomTurnoverRewardConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateRoomTurnoverRewardConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminRoomTurnoverRewardServiceServer) ListRoomTurnoverRewardSettlements(context.Context, *ListRoomTurnoverRewardSettlementsRequest) (*ListRoomTurnoverRewardSettlementsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRoomTurnoverRewardSettlements not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRoomTurnoverRewardSettlements not implemented")
|
||||
}
|
||||
func (UnimplementedAdminRoomTurnoverRewardServiceServer) RetryRoomTurnoverRewardSettlement(context.Context, *RetryRoomTurnoverRewardSettlementRequest) (*RetryRoomTurnoverRewardSettlementResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RetryRoomTurnoverRewardSettlement not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RetryRoomTurnoverRewardSettlement not implemented")
|
||||
}
|
||||
func (UnimplementedAdminRoomTurnoverRewardServiceServer) mustEmbedUnimplementedAdminRoomTurnoverRewardServiceServer() {
|
||||
}
|
||||
@ -3527,7 +3565,7 @@ type UnsafeAdminRoomTurnoverRewardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminRoomTurnoverRewardServiceServer(s grpc.ServiceRegistrar, srv AdminRoomTurnoverRewardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminRoomTurnoverRewardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminRoomTurnoverRewardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -3764,25 +3802,25 @@ type AdminWeeklyStarServiceServer interface {
|
||||
type UnimplementedAdminWeeklyStarServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminWeeklyStarServiceServer) ListWeeklyStarCycles(context.Context, *ListWeeklyStarCyclesRequest) (*ListWeeklyStarCyclesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarCycles not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarCycles not implemented")
|
||||
}
|
||||
func (UnimplementedAdminWeeklyStarServiceServer) CreateWeeklyStarCycle(context.Context, *UpsertWeeklyStarCycleRequest) (*UpsertWeeklyStarCycleResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateWeeklyStarCycle not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateWeeklyStarCycle not implemented")
|
||||
}
|
||||
func (UnimplementedAdminWeeklyStarServiceServer) GetWeeklyStarCycle(context.Context, *GetWeeklyStarCycleRequest) (*GetWeeklyStarCycleResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetWeeklyStarCycle not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetWeeklyStarCycle not implemented")
|
||||
}
|
||||
func (UnimplementedAdminWeeklyStarServiceServer) UpdateWeeklyStarCycle(context.Context, *UpsertWeeklyStarCycleRequest) (*UpsertWeeklyStarCycleResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateWeeklyStarCycle not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateWeeklyStarCycle not implemented")
|
||||
}
|
||||
func (UnimplementedAdminWeeklyStarServiceServer) SetWeeklyStarCycleStatus(context.Context, *SetWeeklyStarCycleStatusRequest) (*SetWeeklyStarCycleStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetWeeklyStarCycleStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetWeeklyStarCycleStatus not implemented")
|
||||
}
|
||||
func (UnimplementedAdminWeeklyStarServiceServer) ListWeeklyStarLeaderboard(context.Context, *ListWeeklyStarLeaderboardRequest) (*ListWeeklyStarLeaderboardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarLeaderboard not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarLeaderboard not implemented")
|
||||
}
|
||||
func (UnimplementedAdminWeeklyStarServiceServer) ListWeeklyStarSettlements(context.Context, *ListWeeklyStarSettlementsRequest) (*ListWeeklyStarSettlementsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarSettlements not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarSettlements not implemented")
|
||||
}
|
||||
func (UnimplementedAdminWeeklyStarServiceServer) mustEmbedUnimplementedAdminWeeklyStarServiceServer() {
|
||||
}
|
||||
@ -3796,7 +3834,7 @@ type UnsafeAdminWeeklyStarServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminWeeklyStarServiceServer(s grpc.ServiceRegistrar, srv AdminWeeklyStarServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminWeeklyStarServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminWeeklyStarServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -4034,10 +4072,10 @@ type SevenDayCheckInServiceServer interface {
|
||||
type UnimplementedSevenDayCheckInServiceServer struct{}
|
||||
|
||||
func (UnimplementedSevenDayCheckInServiceServer) GetSevenDayCheckInStatus(context.Context, *GetSevenDayCheckInStatusRequest) (*GetSevenDayCheckInStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetSevenDayCheckInStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetSevenDayCheckInStatus not implemented")
|
||||
}
|
||||
func (UnimplementedSevenDayCheckInServiceServer) SignSevenDayCheckIn(context.Context, *SignSevenDayCheckInRequest) (*SignSevenDayCheckInResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SignSevenDayCheckIn not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SignSevenDayCheckIn not implemented")
|
||||
}
|
||||
func (UnimplementedSevenDayCheckInServiceServer) mustEmbedUnimplementedSevenDayCheckInServiceServer() {
|
||||
}
|
||||
@ -4051,7 +4089,7 @@ type UnsafeSevenDayCheckInServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterSevenDayCheckInServiceServer(s grpc.ServiceRegistrar, srv SevenDayCheckInServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedSevenDayCheckInServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedSevenDayCheckInServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -4192,13 +4230,13 @@ type AdminSevenDayCheckInServiceServer interface {
|
||||
type UnimplementedAdminSevenDayCheckInServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminSevenDayCheckInServiceServer) GetSevenDayCheckInConfig(context.Context, *GetSevenDayCheckInConfigRequest) (*GetSevenDayCheckInConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetSevenDayCheckInConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetSevenDayCheckInConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminSevenDayCheckInServiceServer) UpdateSevenDayCheckInConfig(context.Context, *UpdateSevenDayCheckInConfigRequest) (*UpdateSevenDayCheckInConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateSevenDayCheckInConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateSevenDayCheckInConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminSevenDayCheckInServiceServer) ListSevenDayCheckInClaims(context.Context, *ListSevenDayCheckInClaimsRequest) (*ListSevenDayCheckInClaimsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListSevenDayCheckInClaims not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListSevenDayCheckInClaims not implemented")
|
||||
}
|
||||
func (UnimplementedAdminSevenDayCheckInServiceServer) mustEmbedUnimplementedAdminSevenDayCheckInServiceServer() {
|
||||
}
|
||||
@ -4212,7 +4250,7 @@ type UnsafeAdminSevenDayCheckInServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminSevenDayCheckInServiceServer(s grpc.ServiceRegistrar, srv AdminSevenDayCheckInServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminSevenDayCheckInServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminSevenDayCheckInServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -4388,16 +4426,16 @@ type AdminGrowthLevelServiceServer interface {
|
||||
type UnimplementedAdminGrowthLevelServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminGrowthLevelServiceServer) ListLevelConfig(context.Context, *ListLevelConfigRequest) (*ListLevelConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListLevelConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListLevelConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminGrowthLevelServiceServer) UpsertLevelTrack(context.Context, *UpsertLevelTrackRequest) (*UpsertLevelTrackResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertLevelTrack not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertLevelTrack not implemented")
|
||||
}
|
||||
func (UnimplementedAdminGrowthLevelServiceServer) UpsertLevelRule(context.Context, *UpsertLevelRuleRequest) (*UpsertLevelRuleResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertLevelRule not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertLevelRule not implemented")
|
||||
}
|
||||
func (UnimplementedAdminGrowthLevelServiceServer) UpsertLevelTier(context.Context, *UpsertLevelTierRequest) (*UpsertLevelTierResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertLevelTier not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertLevelTier not implemented")
|
||||
}
|
||||
func (UnimplementedAdminGrowthLevelServiceServer) mustEmbedUnimplementedAdminGrowthLevelServiceServer() {
|
||||
}
|
||||
@ -4411,7 +4449,7 @@ type UnsafeAdminGrowthLevelServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminGrowthLevelServiceServer(s grpc.ServiceRegistrar, srv AdminGrowthLevelServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminGrowthLevelServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminGrowthLevelServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -4583,10 +4621,10 @@ type AdminAchievementServiceServer interface {
|
||||
type UnimplementedAdminAchievementServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminAchievementServiceServer) ListAchievementDefinitions(context.Context, *ListAchievementsRequest) (*ListAchievementsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListAchievementDefinitions not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListAchievementDefinitions not implemented")
|
||||
}
|
||||
func (UnimplementedAdminAchievementServiceServer) UpsertAchievementDefinition(context.Context, *UpsertAchievementDefinitionRequest) (*UpsertAchievementDefinitionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertAchievementDefinition not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertAchievementDefinition not implemented")
|
||||
}
|
||||
func (UnimplementedAdminAchievementServiceServer) mustEmbedUnimplementedAdminAchievementServiceServer() {
|
||||
}
|
||||
@ -4600,7 +4638,7 @@ type UnsafeAdminAchievementServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminAchievementServiceServer(s grpc.ServiceRegistrar, srv AdminAchievementServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminAchievementServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminAchievementServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -4767,19 +4805,19 @@ type AdminLuckyGiftServiceServer interface {
|
||||
type UnimplementedAdminLuckyGiftServiceServer struct{}
|
||||
|
||||
func (UnimplementedAdminLuckyGiftServiceServer) GetLuckyGiftConfig(context.Context, *GetLuckyGiftConfigRequest) (*GetLuckyGiftConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetLuckyGiftConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetLuckyGiftConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminLuckyGiftServiceServer) UpsertLuckyGiftConfig(context.Context, *UpsertLuckyGiftConfigRequest) (*UpsertLuckyGiftConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertLuckyGiftConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertLuckyGiftConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAdminLuckyGiftServiceServer) ListLuckyGiftConfigs(context.Context, *ListLuckyGiftConfigsRequest) (*ListLuckyGiftConfigsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListLuckyGiftConfigs not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListLuckyGiftConfigs not implemented")
|
||||
}
|
||||
func (UnimplementedAdminLuckyGiftServiceServer) ListLuckyGiftDraws(context.Context, *ListLuckyGiftDrawsRequest) (*ListLuckyGiftDrawsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListLuckyGiftDraws not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListLuckyGiftDraws not implemented")
|
||||
}
|
||||
func (UnimplementedAdminLuckyGiftServiceServer) GetLuckyGiftDrawSummary(context.Context, *GetLuckyGiftDrawSummaryRequest) (*GetLuckyGiftDrawSummaryResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetLuckyGiftDrawSummary not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetLuckyGiftDrawSummary not implemented")
|
||||
}
|
||||
func (UnimplementedAdminLuckyGiftServiceServer) mustEmbedUnimplementedAdminLuckyGiftServiceServer() {}
|
||||
func (UnimplementedAdminLuckyGiftServiceServer) testEmbeddedByValue() {}
|
||||
@ -4792,7 +4830,7 @@ type UnsafeAdminLuckyGiftServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAdminLuckyGiftServiceServer(s grpc.ServiceRegistrar, srv AdminLuckyGiftServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAdminLuckyGiftServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAdminLuckyGiftServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -83,6 +83,32 @@ message ListGamesResponse {
|
||||
int64 server_time_ms = 2;
|
||||
}
|
||||
|
||||
message ListRecentGamesRequest {
|
||||
RequestMeta meta = 1;
|
||||
int64 user_id = 2;
|
||||
string scene = 3;
|
||||
string room_id = 4;
|
||||
int64 region_id = 5;
|
||||
string language = 6;
|
||||
string client_platform = 7;
|
||||
int32 page_size = 8;
|
||||
}
|
||||
|
||||
message GetBridgeScriptRequest {
|
||||
RequestMeta meta = 1;
|
||||
}
|
||||
|
||||
message GameBridgeScriptConfig {
|
||||
string bridge_script_url = 1;
|
||||
string bridge_script_version = 2;
|
||||
string bridge_script_sha256 = 3;
|
||||
}
|
||||
|
||||
message GetBridgeScriptResponse {
|
||||
GameBridgeScriptConfig config = 1;
|
||||
int64 server_time_ms = 2;
|
||||
}
|
||||
|
||||
message LaunchGameRequest {
|
||||
RequestMeta meta = 1;
|
||||
int64 user_id = 2;
|
||||
@ -196,6 +222,8 @@ message DeleteCatalogResponse {
|
||||
|
||||
service GameAppService {
|
||||
rpc ListGames(ListGamesRequest) returns (ListGamesResponse);
|
||||
rpc ListRecentGames(ListRecentGamesRequest) returns (ListGamesResponse);
|
||||
rpc GetBridgeScript(GetBridgeScriptRequest) returns (GetBridgeScriptResponse);
|
||||
rpc LaunchGame(LaunchGameRequest) returns (LaunchGameResponse);
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.0
|
||||
// source: proto/game/v1/game.proto
|
||||
|
||||
@ -19,8 +19,10 @@ import (
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
GameAppService_ListGames_FullMethodName = "/hyapp.game.v1.GameAppService/ListGames"
|
||||
GameAppService_LaunchGame_FullMethodName = "/hyapp.game.v1.GameAppService/LaunchGame"
|
||||
GameAppService_ListGames_FullMethodName = "/hyapp.game.v1.GameAppService/ListGames"
|
||||
GameAppService_ListRecentGames_FullMethodName = "/hyapp.game.v1.GameAppService/ListRecentGames"
|
||||
GameAppService_GetBridgeScript_FullMethodName = "/hyapp.game.v1.GameAppService/GetBridgeScript"
|
||||
GameAppService_LaunchGame_FullMethodName = "/hyapp.game.v1.GameAppService/LaunchGame"
|
||||
)
|
||||
|
||||
// GameAppServiceClient is the client API for GameAppService service.
|
||||
@ -28,6 +30,8 @@ const (
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type GameAppServiceClient interface {
|
||||
ListGames(ctx context.Context, in *ListGamesRequest, opts ...grpc.CallOption) (*ListGamesResponse, error)
|
||||
ListRecentGames(ctx context.Context, in *ListRecentGamesRequest, opts ...grpc.CallOption) (*ListGamesResponse, error)
|
||||
GetBridgeScript(ctx context.Context, in *GetBridgeScriptRequest, opts ...grpc.CallOption) (*GetBridgeScriptResponse, error)
|
||||
LaunchGame(ctx context.Context, in *LaunchGameRequest, opts ...grpc.CallOption) (*LaunchGameResponse, error)
|
||||
}
|
||||
|
||||
@ -49,6 +53,26 @@ func (c *gameAppServiceClient) ListGames(ctx context.Context, in *ListGamesReque
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *gameAppServiceClient) ListRecentGames(ctx context.Context, in *ListRecentGamesRequest, opts ...grpc.CallOption) (*ListGamesResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListGamesResponse)
|
||||
err := c.cc.Invoke(ctx, GameAppService_ListRecentGames_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *gameAppServiceClient) GetBridgeScript(ctx context.Context, in *GetBridgeScriptRequest, opts ...grpc.CallOption) (*GetBridgeScriptResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetBridgeScriptResponse)
|
||||
err := c.cc.Invoke(ctx, GameAppService_GetBridgeScript_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *gameAppServiceClient) LaunchGame(ctx context.Context, in *LaunchGameRequest, opts ...grpc.CallOption) (*LaunchGameResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(LaunchGameResponse)
|
||||
@ -64,6 +88,8 @@ func (c *gameAppServiceClient) LaunchGame(ctx context.Context, in *LaunchGameReq
|
||||
// for forward compatibility.
|
||||
type GameAppServiceServer interface {
|
||||
ListGames(context.Context, *ListGamesRequest) (*ListGamesResponse, error)
|
||||
ListRecentGames(context.Context, *ListRecentGamesRequest) (*ListGamesResponse, error)
|
||||
GetBridgeScript(context.Context, *GetBridgeScriptRequest) (*GetBridgeScriptResponse, error)
|
||||
LaunchGame(context.Context, *LaunchGameRequest) (*LaunchGameResponse, error)
|
||||
mustEmbedUnimplementedGameAppServiceServer()
|
||||
}
|
||||
@ -76,10 +102,16 @@ type GameAppServiceServer interface {
|
||||
type UnimplementedGameAppServiceServer struct{}
|
||||
|
||||
func (UnimplementedGameAppServiceServer) ListGames(context.Context, *ListGamesRequest) (*ListGamesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListGames not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListGames not implemented")
|
||||
}
|
||||
func (UnimplementedGameAppServiceServer) ListRecentGames(context.Context, *ListRecentGamesRequest) (*ListGamesResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRecentGames not implemented")
|
||||
}
|
||||
func (UnimplementedGameAppServiceServer) GetBridgeScript(context.Context, *GetBridgeScriptRequest) (*GetBridgeScriptResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetBridgeScript not implemented")
|
||||
}
|
||||
func (UnimplementedGameAppServiceServer) LaunchGame(context.Context, *LaunchGameRequest) (*LaunchGameResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method LaunchGame not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method LaunchGame not implemented")
|
||||
}
|
||||
func (UnimplementedGameAppServiceServer) mustEmbedUnimplementedGameAppServiceServer() {}
|
||||
func (UnimplementedGameAppServiceServer) testEmbeddedByValue() {}
|
||||
@ -92,7 +124,7 @@ type UnsafeGameAppServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterGameAppServiceServer(s grpc.ServiceRegistrar, srv GameAppServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedGameAppServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedGameAppServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -120,6 +152,42 @@ func _GameAppService_ListGames_Handler(srv interface{}, ctx context.Context, dec
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GameAppService_ListRecentGames_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListRecentGamesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GameAppServiceServer).ListRecentGames(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: GameAppService_ListRecentGames_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GameAppServiceServer).ListRecentGames(ctx, req.(*ListRecentGamesRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GameAppService_GetBridgeScript_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetBridgeScriptRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GameAppServiceServer).GetBridgeScript(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: GameAppService_GetBridgeScript_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GameAppServiceServer).GetBridgeScript(ctx, req.(*GetBridgeScriptRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GameAppService_LaunchGame_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(LaunchGameRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -149,6 +217,14 @@ var GameAppService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ListGames",
|
||||
Handler: _GameAppService_ListGames_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListRecentGames",
|
||||
Handler: _GameAppService_ListRecentGames_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetBridgeScript",
|
||||
Handler: _GameAppService_GetBridgeScript_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "LaunchGame",
|
||||
Handler: _GameAppService_LaunchGame_Handler,
|
||||
@ -203,7 +279,7 @@ type GameCallbackServiceServer interface {
|
||||
type UnimplementedGameCallbackServiceServer struct{}
|
||||
|
||||
func (UnimplementedGameCallbackServiceServer) HandleCallback(context.Context, *CallbackRequest) (*CallbackResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method HandleCallback not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method HandleCallback not implemented")
|
||||
}
|
||||
func (UnimplementedGameCallbackServiceServer) mustEmbedUnimplementedGameCallbackServiceServer() {}
|
||||
func (UnimplementedGameCallbackServiceServer) testEmbeddedByValue() {}
|
||||
@ -216,7 +292,7 @@ type UnsafeGameCallbackServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterGameCallbackServiceServer(s grpc.ServiceRegistrar, srv GameCallbackServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedGameCallbackServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedGameCallbackServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -309,7 +385,7 @@ type GameCronServiceServer interface {
|
||||
type UnimplementedGameCronServiceServer struct{}
|
||||
|
||||
func (UnimplementedGameCronServiceServer) ProcessLevelEventOutboxBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessLevelEventOutboxBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessLevelEventOutboxBatch not implemented")
|
||||
}
|
||||
func (UnimplementedGameCronServiceServer) mustEmbedUnimplementedGameCronServiceServer() {}
|
||||
func (UnimplementedGameCronServiceServer) testEmbeddedByValue() {}
|
||||
@ -322,7 +398,7 @@ type UnsafeGameCronServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterGameCronServiceServer(s grpc.ServiceRegistrar, srv GameCronServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedGameCronServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedGameCronServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -476,22 +552,22 @@ type GameAdminServiceServer interface {
|
||||
type UnimplementedGameAdminServiceServer struct{}
|
||||
|
||||
func (UnimplementedGameAdminServiceServer) ListPlatforms(context.Context, *ListPlatformsRequest) (*ListPlatformsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListPlatforms not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListPlatforms not implemented")
|
||||
}
|
||||
func (UnimplementedGameAdminServiceServer) UpsertPlatform(context.Context, *UpsertPlatformRequest) (*PlatformResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertPlatform not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertPlatform not implemented")
|
||||
}
|
||||
func (UnimplementedGameAdminServiceServer) ListCatalog(context.Context, *ListCatalogRequest) (*ListCatalogResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListCatalog not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListCatalog not implemented")
|
||||
}
|
||||
func (UnimplementedGameAdminServiceServer) UpsertCatalog(context.Context, *UpsertCatalogRequest) (*CatalogResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertCatalog not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertCatalog not implemented")
|
||||
}
|
||||
func (UnimplementedGameAdminServiceServer) SetGameStatus(context.Context, *SetGameStatusRequest) (*CatalogResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetGameStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetGameStatus not implemented")
|
||||
}
|
||||
func (UnimplementedGameAdminServiceServer) DeleteCatalog(context.Context, *DeleteCatalogRequest) (*DeleteCatalogResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteCatalog not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteCatalog not implemented")
|
||||
}
|
||||
func (UnimplementedGameAdminServiceServer) mustEmbedUnimplementedGameAdminServiceServer() {}
|
||||
func (UnimplementedGameAdminServiceServer) testEmbeddedByValue() {}
|
||||
@ -504,7 +580,7 @@ type UnsafeGameAdminServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterGameAdminServiceServer(s grpc.ServiceRegistrar, srv GameAdminServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedGameAdminServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedGameAdminServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -425,6 +425,8 @@ message CreateRoomRequest {
|
||||
string room_description = 7;
|
||||
// room_short_id 是房间短 ID,首版直接等于创建者当前 default/current display_user_id。
|
||||
string room_short_id = 8;
|
||||
// owner_country_code 由 gateway 按创建者 user-service 当前国家填充,用于发现页国家分类筛选。
|
||||
string owner_country_code = 9;
|
||||
}
|
||||
|
||||
// CreateRoomResponse 返回新建后的房间快照。
|
||||
@ -901,6 +903,8 @@ message ListRoomsRequest {
|
||||
string cursor = 5;
|
||||
int32 limit = 6;
|
||||
string query = 7;
|
||||
// country_code 是可选国家筛选值;gateway 只能传当前用户区域国家列表内的国家码。
|
||||
string country_code = 8;
|
||||
}
|
||||
|
||||
// ListRoomFeedsRequest 查询 Mine 页 visited/friend/following/followed 房间流。
|
||||
@ -947,6 +951,7 @@ message RoomListItem {
|
||||
string app_code = 13;
|
||||
string room_short_id = 14;
|
||||
bool locked = 15;
|
||||
string country_code = 16;
|
||||
}
|
||||
|
||||
// ListRoomsResponse 返回一页房间卡片和下一页不透明 cursor。
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.0
|
||||
// source: proto/room/v1/room.proto
|
||||
|
||||
@ -470,100 +470,100 @@ type RoomCommandServiceServer interface {
|
||||
type UnimplementedRoomCommandServiceServer struct{}
|
||||
|
||||
func (UnimplementedRoomCommandServiceServer) CreateRoom(context.Context, *CreateRoomRequest) (*CreateRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) UpdateRoomProfile(context.Context, *UpdateRoomProfileRequest) (*UpdateRoomProfileResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateRoomProfile not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateRoomProfile not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SaveRoomBackground(context.Context, *SaveRoomBackgroundRequest) (*SaveRoomBackgroundResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SaveRoomBackground not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SaveRoomBackground not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SetRoomBackground(context.Context, *SetRoomBackgroundRequest) (*SetRoomBackgroundResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetRoomBackground not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetRoomBackground not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) JoinRoom(context.Context, *JoinRoomRequest) (*JoinRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method JoinRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method JoinRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) RoomHeartbeat(context.Context, *RoomHeartbeatRequest) (*RoomHeartbeatResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RoomHeartbeat not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RoomHeartbeat not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) LeaveRoom(context.Context, *LeaveRoomRequest) (*LeaveRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method LeaveRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method LeaveRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) CloseRoom(context.Context, *CloseRoomRequest) (*CloseRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CloseRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CloseRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) AdminUpdateRoom(context.Context, *AdminUpdateRoomRequest) (*AdminUpdateRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminUpdateRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) AdminDeleteRoom(context.Context, *AdminDeleteRoomRequest) (*AdminDeleteRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminDeleteRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminDeleteRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) AdminUpdateRoomRocketConfig(context.Context, *AdminUpdateRoomRocketConfigRequest) (*AdminUpdateRoomRocketConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateRoomRocketConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminUpdateRoomRocketConfig not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) AdminUpdateRoomSeatConfig(context.Context, *AdminUpdateRoomSeatConfigRequest) (*AdminUpdateRoomSeatConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateRoomSeatConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminUpdateRoomSeatConfig not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) AdminCreateRoomPin(context.Context, *AdminCreateRoomPinRequest) (*AdminCreateRoomPinResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminCreateRoomPin not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminCreateRoomPin not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) AdminCancelRoomPin(context.Context, *AdminCancelRoomPinRequest) (*AdminCancelRoomPinResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminCancelRoomPin not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminCancelRoomPin not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) MicUp(context.Context, *MicUpRequest) (*MicUpResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method MicUp not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method MicUp not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) MicDown(context.Context, *MicDownRequest) (*MicDownResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method MicDown not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method MicDown not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) ChangeMicSeat(context.Context, *ChangeMicSeatRequest) (*ChangeMicSeatResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ChangeMicSeat not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ChangeMicSeat not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) ConfirmMicPublishing(context.Context, *ConfirmMicPublishingRequest) (*ConfirmMicPublishingResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConfirmMicPublishing not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConfirmMicPublishing not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) MicHeartbeat(context.Context, *MicHeartbeatRequest) (*MicHeartbeatResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method MicHeartbeat not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method MicHeartbeat not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SetMicMute(context.Context, *SetMicMuteRequest) (*SetMicMuteResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetMicMute not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetMicMute not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) ApplyRTCEvent(context.Context, *ApplyRTCEventRequest) (*ApplyRTCEventResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ApplyRTCEvent not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ApplyRTCEvent not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SetMicSeatLock(context.Context, *SetMicSeatLockRequest) (*SetMicSeatLockResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetMicSeatLock not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetMicSeatLock not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SetChatEnabled(context.Context, *SetChatEnabledRequest) (*SetChatEnabledResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetChatEnabled not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetChatEnabled not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SetRoomPassword(context.Context, *SetRoomPasswordRequest) (*SetRoomPasswordResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetRoomPassword not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetRoomPassword not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SetRoomAdmin(context.Context, *SetRoomAdminRequest) (*SetRoomAdminResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetRoomAdmin not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetRoomAdmin not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) MuteUser(context.Context, *MuteUserRequest) (*MuteUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method MuteUser not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method MuteUser not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) KickUser(context.Context, *KickUserRequest) (*KickUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method KickUser not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method KickUser not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) UnbanUser(context.Context, *UnbanUserRequest) (*UnbanUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UnbanUser not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UnbanUser not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SystemEvictUser(context.Context, *SystemEvictUserRequest) (*SystemEvictUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SystemEvictUser not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SystemEvictUser not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) SendGift(context.Context, *SendGiftRequest) (*SendGiftResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SendGift not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SendGift not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) FollowRoom(context.Context, *FollowRoomRequest) (*FollowRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method FollowRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method FollowRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) UnfollowRoom(context.Context, *UnfollowRoomRequest) (*UnfollowRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UnfollowRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UnfollowRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomCommandServiceServer) mustEmbedUnimplementedRoomCommandServiceServer() {}
|
||||
func (UnimplementedRoomCommandServiceServer) testEmbeddedByValue() {}
|
||||
@ -576,7 +576,7 @@ type UnsafeRoomCommandServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterRoomCommandServiceServer(s grpc.ServiceRegistrar, srv RoomCommandServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRoomCommandServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedRoomCommandServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1364,10 +1364,10 @@ type RoomGuardServiceServer interface {
|
||||
type UnimplementedRoomGuardServiceServer struct{}
|
||||
|
||||
func (UnimplementedRoomGuardServiceServer) CheckSpeakPermission(context.Context, *CheckSpeakPermissionRequest) (*CheckSpeakPermissionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CheckSpeakPermission not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CheckSpeakPermission not implemented")
|
||||
}
|
||||
func (UnimplementedRoomGuardServiceServer) VerifyRoomPresence(context.Context, *VerifyRoomPresenceRequest) (*VerifyRoomPresenceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VerifyRoomPresence not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method VerifyRoomPresence not implemented")
|
||||
}
|
||||
func (UnimplementedRoomGuardServiceServer) mustEmbedUnimplementedRoomGuardServiceServer() {}
|
||||
func (UnimplementedRoomGuardServiceServer) testEmbeddedByValue() {}
|
||||
@ -1380,7 +1380,7 @@ type UnsafeRoomGuardServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterRoomGuardServiceServer(s grpc.ServiceRegistrar, srv RoomGuardServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRoomGuardServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedRoomGuardServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1677,49 +1677,49 @@ type RoomQueryServiceServer interface {
|
||||
type UnimplementedRoomQueryServiceServer struct{}
|
||||
|
||||
func (UnimplementedRoomQueryServiceServer) AdminListRooms(context.Context, *AdminListRoomsRequest) (*AdminListRoomsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminListRooms not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminListRooms not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) AdminGetRoom(context.Context, *AdminGetRoomRequest) (*AdminGetRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminGetRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminGetRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) AdminGetRoomRocketConfig(context.Context, *AdminGetRoomRocketConfigRequest) (*AdminGetRoomRocketConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminGetRoomRocketConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminGetRoomRocketConfig not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) AdminGetRoomSeatConfig(context.Context, *AdminGetRoomSeatConfigRequest) (*AdminGetRoomSeatConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminGetRoomSeatConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminGetRoomSeatConfig not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) AdminListRoomPins(context.Context, *AdminListRoomPinsRequest) (*AdminListRoomPinsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminListRoomPins not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminListRoomPins not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRooms not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRooms not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) ListRoomFeeds(context.Context, *ListRoomFeedsRequest) (*ListRoomsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRoomFeeds not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRoomFeeds not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) ListRoomGiftLeaderboard(context.Context, *ListRoomGiftLeaderboardRequest) (*ListRoomGiftLeaderboardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRoomGiftLeaderboard not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRoomGiftLeaderboard not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) GetMyRoom(context.Context, *GetMyRoomRequest) (*GetMyRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetMyRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetMyRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) GetCurrentRoom(context.Context, *GetCurrentRoomRequest) (*GetCurrentRoomResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetCurrentRoom not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetCurrentRoom not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) GetRoomSnapshot(context.Context, *GetRoomSnapshotRequest) (*GetRoomSnapshotResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRoomSnapshot not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRoomSnapshot not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) ListRoomBackgrounds(context.Context, *ListRoomBackgroundsRequest) (*ListRoomBackgroundsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRoomBackgrounds not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRoomBackgrounds not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) GetRoomRocket(context.Context, *GetRoomRocketRequest) (*GetRoomRocketResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRoomRocket not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRoomRocket not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) ListRoomOnlineUsers(context.Context, *ListRoomOnlineUsersRequest) (*ListRoomOnlineUsersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRoomOnlineUsers not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRoomOnlineUsers not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) ListRoomBannedUsers(context.Context, *ListRoomBannedUsersRequest) (*ListRoomBannedUsersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRoomBannedUsers not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRoomBannedUsers not implemented")
|
||||
}
|
||||
func (UnimplementedRoomQueryServiceServer) mustEmbedUnimplementedRoomQueryServiceServer() {}
|
||||
func (UnimplementedRoomQueryServiceServer) testEmbeddedByValue() {}
|
||||
@ -1732,7 +1732,7 @@ type UnsafeRoomQueryServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterRoomQueryServiceServer(s grpc.ServiceRegistrar, srv RoomQueryServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRoomQueryServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedRoomQueryServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.35.1
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v7.35.0
|
||||
// source: proto/user/v1/auth.proto
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -22,13 +23,12 @@ const (
|
||||
|
||||
// LoginPasswordRequest 使用当前 display_user_id 和已设置密码登录。
|
||||
type LoginPasswordRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
DisplayUserId string `protobuf:"bytes,2,opt,name=display_user_id,json=displayUserId,proto3" json:"display_user_id,omitempty"`
|
||||
Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
DisplayUserId string `protobuf:"bytes,2,opt,name=display_user_id,json=displayUserId,proto3" json:"display_user_id,omitempty"`
|
||||
Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *LoginPasswordRequest) Reset() {
|
||||
@ -84,30 +84,29 @@ func (x *LoginPasswordRequest) GetPassword() string {
|
||||
|
||||
// LoginThirdPartyRequest 使用三方凭证登录或注册。
|
||||
type LoginThirdPartyRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Credential string `protobuf:"bytes,3,opt,name=credential,proto3" json:"credential,omitempty"`
|
||||
Username string `protobuf:"bytes,4,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Gender string `protobuf:"bytes,5,opt,name=gender,proto3" json:"gender,omitempty"`
|
||||
Country string `protobuf:"bytes,6,opt,name=country,proto3" json:"country,omitempty"`
|
||||
InviteCode string `protobuf:"bytes,7,opt,name=invite_code,json=inviteCode,proto3" json:"invite_code,omitempty"`
|
||||
DeviceId string `protobuf:"bytes,8,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
|
||||
Device string `protobuf:"bytes,9,opt,name=device,proto3" json:"device,omitempty"`
|
||||
Avatar string `protobuf:"bytes,10,opt,name=avatar,proto3" json:"avatar,omitempty"`
|
||||
Birth string `protobuf:"bytes,11,opt,name=birth,proto3" json:"birth,omitempty"`
|
||||
AppVersion string `protobuf:"bytes,12,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"`
|
||||
Source string `protobuf:"bytes,13,opt,name=source,proto3" json:"source,omitempty"`
|
||||
Platform string `protobuf:"bytes,14,opt,name=platform,proto3" json:"platform,omitempty"`
|
||||
Language string `protobuf:"bytes,15,opt,name=language,proto3" json:"language,omitempty"`
|
||||
OsVersion string `protobuf:"bytes,16,opt,name=os_version,json=osVersion,proto3" json:"os_version,omitempty"`
|
||||
BuildNumber string `protobuf:"bytes,17,opt,name=build_number,json=buildNumber,proto3" json:"build_number,omitempty"`
|
||||
Timezone string `protobuf:"bytes,18,opt,name=timezone,proto3" json:"timezone,omitempty"`
|
||||
InstallChannel string `protobuf:"bytes,19,opt,name=install_channel,json=installChannel,proto3" json:"install_channel,omitempty"`
|
||||
Campaign string `protobuf:"bytes,20,opt,name=campaign,proto3" json:"campaign,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Credential string `protobuf:"bytes,3,opt,name=credential,proto3" json:"credential,omitempty"`
|
||||
Username string `protobuf:"bytes,4,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Gender string `protobuf:"bytes,5,opt,name=gender,proto3" json:"gender,omitempty"`
|
||||
Country string `protobuf:"bytes,6,opt,name=country,proto3" json:"country,omitempty"`
|
||||
InviteCode string `protobuf:"bytes,7,opt,name=invite_code,json=inviteCode,proto3" json:"invite_code,omitempty"`
|
||||
DeviceId string `protobuf:"bytes,8,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
|
||||
Device string `protobuf:"bytes,9,opt,name=device,proto3" json:"device,omitempty"`
|
||||
Avatar string `protobuf:"bytes,10,opt,name=avatar,proto3" json:"avatar,omitempty"`
|
||||
Birth string `protobuf:"bytes,11,opt,name=birth,proto3" json:"birth,omitempty"`
|
||||
AppVersion string `protobuf:"bytes,12,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"`
|
||||
Source string `protobuf:"bytes,13,opt,name=source,proto3" json:"source,omitempty"`
|
||||
Platform string `protobuf:"bytes,14,opt,name=platform,proto3" json:"platform,omitempty"`
|
||||
Language string `protobuf:"bytes,15,opt,name=language,proto3" json:"language,omitempty"`
|
||||
OsVersion string `protobuf:"bytes,16,opt,name=os_version,json=osVersion,proto3" json:"os_version,omitempty"`
|
||||
BuildNumber string `protobuf:"bytes,17,opt,name=build_number,json=buildNumber,proto3" json:"build_number,omitempty"`
|
||||
Timezone string `protobuf:"bytes,18,opt,name=timezone,proto3" json:"timezone,omitempty"`
|
||||
InstallChannel string `protobuf:"bytes,19,opt,name=install_channel,json=installChannel,proto3" json:"install_channel,omitempty"`
|
||||
Campaign string `protobuf:"bytes,20,opt,name=campaign,proto3" json:"campaign,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *LoginThirdPartyRequest) Reset() {
|
||||
@ -282,14 +281,13 @@ func (x *LoginThirdPartyRequest) GetCampaign() string {
|
||||
|
||||
// AuthResponse 返回标准认证令牌。
|
||||
type AuthResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Token *AuthToken `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
IsNewUser bool `protobuf:"varint,2,opt,name=is_new_user,json=isNewUser,proto3" json:"is_new_user,omitempty"`
|
||||
ProfileCompleted bool `protobuf:"varint,3,opt,name=profile_completed,json=profileCompleted,proto3" json:"profile_completed,omitempty"`
|
||||
OnboardingStatus string `protobuf:"bytes,4,opt,name=onboarding_status,json=onboardingStatus,proto3" json:"onboarding_status,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Token *AuthToken `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
IsNewUser bool `protobuf:"varint,2,opt,name=is_new_user,json=isNewUser,proto3" json:"is_new_user,omitempty"`
|
||||
ProfileCompleted bool `protobuf:"varint,3,opt,name=profile_completed,json=profileCompleted,proto3" json:"profile_completed,omitempty"`
|
||||
OnboardingStatus string `protobuf:"bytes,4,opt,name=onboarding_status,json=onboardingStatus,proto3" json:"onboarding_status,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AuthResponse) Reset() {
|
||||
@ -352,13 +350,12 @@ func (x *AuthResponse) GetOnboardingStatus() string {
|
||||
|
||||
// SetPasswordRequest 为已经三方登录的用户首次设置密码。
|
||||
type SetPasswordRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SetPasswordRequest) Reset() {
|
||||
@ -414,11 +411,10 @@ func (x *SetPasswordRequest) GetPassword() string {
|
||||
|
||||
// SetPasswordResponse 返回密码是否已经成功设置。
|
||||
type SetPasswordResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
PasswordSet bool `protobuf:"varint,1,opt,name=password_set,json=passwordSet,proto3" json:"password_set,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
PasswordSet bool `protobuf:"varint,1,opt,name=password_set,json=passwordSet,proto3" json:"password_set,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SetPasswordResponse) Reset() {
|
||||
@ -460,29 +456,28 @@ func (x *SetPasswordResponse) GetPasswordSet() bool {
|
||||
|
||||
// QuickCreateAccountRequest 为测试和三方联调快速创建一个可密码登录的完整账号。
|
||||
type QuickCreateAccountRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
|
||||
Username string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Avatar string `protobuf:"bytes,4,opt,name=avatar,proto3" json:"avatar,omitempty"`
|
||||
Gender string `protobuf:"bytes,5,opt,name=gender,proto3" json:"gender,omitempty"`
|
||||
Country string `protobuf:"bytes,6,opt,name=country,proto3" json:"country,omitempty"`
|
||||
InviteCode string `protobuf:"bytes,7,opt,name=invite_code,json=inviteCode,proto3" json:"invite_code,omitempty"`
|
||||
DeviceId string `protobuf:"bytes,8,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
|
||||
Device string `protobuf:"bytes,9,opt,name=device,proto3" json:"device,omitempty"`
|
||||
OsVersion string `protobuf:"bytes,10,opt,name=os_version,json=osVersion,proto3" json:"os_version,omitempty"`
|
||||
Birth string `protobuf:"bytes,11,opt,name=birth,proto3" json:"birth,omitempty"`
|
||||
AppVersion string `protobuf:"bytes,12,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"`
|
||||
BuildNumber string `protobuf:"bytes,13,opt,name=build_number,json=buildNumber,proto3" json:"build_number,omitempty"`
|
||||
Source string `protobuf:"bytes,14,opt,name=source,proto3" json:"source,omitempty"`
|
||||
InstallChannel string `protobuf:"bytes,15,opt,name=install_channel,json=installChannel,proto3" json:"install_channel,omitempty"`
|
||||
Campaign string `protobuf:"bytes,16,opt,name=campaign,proto3" json:"campaign,omitempty"`
|
||||
Platform string `protobuf:"bytes,17,opt,name=platform,proto3" json:"platform,omitempty"`
|
||||
Language string `protobuf:"bytes,18,opt,name=language,proto3" json:"language,omitempty"`
|
||||
Timezone string `protobuf:"bytes,19,opt,name=timezone,proto3" json:"timezone,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
|
||||
Username string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Avatar string `protobuf:"bytes,4,opt,name=avatar,proto3" json:"avatar,omitempty"`
|
||||
Gender string `protobuf:"bytes,5,opt,name=gender,proto3" json:"gender,omitempty"`
|
||||
Country string `protobuf:"bytes,6,opt,name=country,proto3" json:"country,omitempty"`
|
||||
InviteCode string `protobuf:"bytes,7,opt,name=invite_code,json=inviteCode,proto3" json:"invite_code,omitempty"`
|
||||
DeviceId string `protobuf:"bytes,8,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
|
||||
Device string `protobuf:"bytes,9,opt,name=device,proto3" json:"device,omitempty"`
|
||||
OsVersion string `protobuf:"bytes,10,opt,name=os_version,json=osVersion,proto3" json:"os_version,omitempty"`
|
||||
Birth string `protobuf:"bytes,11,opt,name=birth,proto3" json:"birth,omitempty"`
|
||||
AppVersion string `protobuf:"bytes,12,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"`
|
||||
BuildNumber string `protobuf:"bytes,13,opt,name=build_number,json=buildNumber,proto3" json:"build_number,omitempty"`
|
||||
Source string `protobuf:"bytes,14,opt,name=source,proto3" json:"source,omitempty"`
|
||||
InstallChannel string `protobuf:"bytes,15,opt,name=install_channel,json=installChannel,proto3" json:"install_channel,omitempty"`
|
||||
Campaign string `protobuf:"bytes,16,opt,name=campaign,proto3" json:"campaign,omitempty"`
|
||||
Platform string `protobuf:"bytes,17,opt,name=platform,proto3" json:"platform,omitempty"`
|
||||
Language string `protobuf:"bytes,18,opt,name=language,proto3" json:"language,omitempty"`
|
||||
Timezone string `protobuf:"bytes,19,opt,name=timezone,proto3" json:"timezone,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *QuickCreateAccountRequest) Reset() {
|
||||
@ -650,12 +645,11 @@ func (x *QuickCreateAccountRequest) GetTimezone() string {
|
||||
|
||||
// QuickCreateAccountResponse 返回新账号登录态;display_user_id 即后续账号密码登录用账号。
|
||||
type QuickCreateAccountResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Token *AuthToken `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
PasswordSet bool `protobuf:"varint,2,opt,name=password_set,json=passwordSet,proto3" json:"password_set,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Token *AuthToken `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
PasswordSet bool `protobuf:"varint,2,opt,name=password_set,json=passwordSet,proto3" json:"password_set,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *QuickCreateAccountResponse) Reset() {
|
||||
@ -704,12 +698,11 @@ func (x *QuickCreateAccountResponse) GetPasswordSet() bool {
|
||||
|
||||
// RefreshTokenRequest 使用 refresh token 换取新 token。
|
||||
type RefreshTokenRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
RefreshToken string `protobuf:"bytes,2,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
RefreshToken string `protobuf:"bytes,2,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RefreshTokenRequest) Reset() {
|
||||
@ -758,11 +751,10 @@ func (x *RefreshTokenRequest) GetRefreshToken() string {
|
||||
|
||||
// RefreshTokenResponse 返回轮换后的令牌。
|
||||
type RefreshTokenResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Token *AuthToken `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Token *AuthToken `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RefreshTokenResponse) Reset() {
|
||||
@ -804,13 +796,12 @@ func (x *RefreshTokenResponse) GetToken() *AuthToken {
|
||||
|
||||
// LogoutRequest 失效指定会话或 refresh token。
|
||||
type LogoutRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
SessionId string `protobuf:"bytes,2,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
|
||||
RefreshToken string `protobuf:"bytes,3,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
SessionId string `protobuf:"bytes,2,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
|
||||
RefreshToken string `protobuf:"bytes,3,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *LogoutRequest) Reset() {
|
||||
@ -866,11 +857,10 @@ func (x *LogoutRequest) GetRefreshToken() string {
|
||||
|
||||
// LogoutResponse 返回会话是否被失效。
|
||||
type LogoutResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Revoked bool `protobuf:"varint,1,opt,name=revoked,proto3" json:"revoked,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Revoked bool `protobuf:"varint,1,opt,name=revoked,proto3" json:"revoked,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *LogoutResponse) Reset() {
|
||||
@ -912,16 +902,15 @@ func (x *LogoutResponse) GetRevoked() bool {
|
||||
|
||||
// RecordLoginBlockedRequest 记录 gateway 入口快拦拒绝的登录审计。
|
||||
type RecordLoginBlockedRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
Channel string `protobuf:"bytes,2,opt,name=channel,proto3" json:"channel,omitempty"`
|
||||
Platform string `protobuf:"bytes,3,opt,name=platform,proto3" json:"platform,omitempty"`
|
||||
Language string `protobuf:"bytes,4,opt,name=language,proto3" json:"language,omitempty"`
|
||||
Timezone string `protobuf:"bytes,5,opt,name=timezone,proto3" json:"timezone,omitempty"`
|
||||
BlockReason string `protobuf:"bytes,6,opt,name=block_reason,json=blockReason,proto3" json:"block_reason,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
Channel string `protobuf:"bytes,2,opt,name=channel,proto3" json:"channel,omitempty"`
|
||||
Platform string `protobuf:"bytes,3,opt,name=platform,proto3" json:"platform,omitempty"`
|
||||
Language string `protobuf:"bytes,4,opt,name=language,proto3" json:"language,omitempty"`
|
||||
Timezone string `protobuf:"bytes,5,opt,name=timezone,proto3" json:"timezone,omitempty"`
|
||||
BlockReason string `protobuf:"bytes,6,opt,name=block_reason,json=blockReason,proto3" json:"block_reason,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RecordLoginBlockedRequest) Reset() {
|
||||
@ -998,11 +987,10 @@ func (x *RecordLoginBlockedRequest) GetBlockReason() string {
|
||||
|
||||
// RecordLoginBlockedResponse 返回审计写入是否成功。
|
||||
type RecordLoginBlockedResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Recorded bool `protobuf:"varint,1,opt,name=recorded,proto3" json:"recorded,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Recorded bool `protobuf:"varint,1,opt,name=recorded,proto3" json:"recorded,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RecordLoginBlockedResponse) Reset() {
|
||||
@ -1044,13 +1032,12 @@ func (x *RecordLoginBlockedResponse) GetRecorded() bool {
|
||||
|
||||
// AppHeartbeatRequest 刷新当前登录会话的 App 在线心跳。
|
||||
type AppHeartbeatRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AppHeartbeatRequest) Reset() {
|
||||
@ -1106,13 +1093,12 @@ func (x *AppHeartbeatRequest) GetSessionId() string {
|
||||
|
||||
// AppHeartbeatResponse 返回本次会话心跳写入时间。
|
||||
type AppHeartbeatResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"`
|
||||
HeartbeatAtMs int64 `protobuf:"varint,2,opt,name=heartbeat_at_ms,json=heartbeatAtMs,proto3" json:"heartbeat_at_ms,omitempty"`
|
||||
ServerTimeMs int64 `protobuf:"varint,3,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"`
|
||||
HeartbeatAtMs int64 `protobuf:"varint,2,opt,name=heartbeat_at_ms,json=heartbeatAtMs,proto3" json:"heartbeat_at_ms,omitempty"`
|
||||
ServerTimeMs int64 `protobuf:"varint,3,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AppHeartbeatResponse) Reset() {
|
||||
@ -1168,241 +1154,126 @@ func (x *AppHeartbeatResponse) GetServerTimeMs() int64 {
|
||||
|
||||
var File_proto_user_v1_auth_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_proto_user_v1_auth_proto_rawDesc = []byte{
|
||||
0x0a, 0x18, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f,
|
||||
0x61, 0x75, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x1a, 0x18, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x8a, 0x01, 0x0a, 0x14, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73,
|
||||
0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04,
|
||||
0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x26, 0x0a, 0x0f,
|
||||
0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73,
|
||||
0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
||||
0x22, 0xea, 0x04, 0x0a, 0x16, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50,
|
||||
0x61, 0x72, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d,
|
||||
0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x70,
|
||||
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
|
||||
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x5f,
|
||||
0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x76, 0x69,
|
||||
0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63,
|
||||
0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x09, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61,
|
||||
0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61,
|
||||
0x74, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x18, 0x0b, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70,
|
||||
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
||||
0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0e,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73,
|
||||
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
|
||||
0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x75, 0x69,
|
||||
0x6c, 0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x73, 0x74,
|
||||
0x61, 0x6c, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x13, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65,
|
||||
0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x6d, 0x70, 0x61, 0x69, 0x67, 0x6e, 0x18, 0x14, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x6d, 0x70, 0x61, 0x69, 0x67, 0x6e, 0x22, 0xb8, 0x01,
|
||||
0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e,
|
||||
0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75,
|
||||
0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1e,
|
||||
0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x4e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x12, 0x2b,
|
||||
0x0a, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65,
|
||||
0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x66, 0x69,
|
||||
0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x6f,
|
||||
0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69,
|
||||
0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x79, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x50,
|
||||
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e,
|
||||
0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x17,
|
||||
0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
|
||||
0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
|
||||
0x6f, 0x72, 0x64, 0x22, 0x38, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f,
|
||||
0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61,
|
||||
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x0b, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x53, 0x65, 0x74, 0x22, 0xcd, 0x04,
|
||||
0x0a, 0x19, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d,
|
||||
0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 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, 0x1a, 0x0a, 0x08, 0x70,
|
||||
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
|
||||
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x67,
|
||||
0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x65, 0x6e,
|
||||
0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1f, 0x0a,
|
||||
0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1b,
|
||||
0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x64,
|
||||
0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76,
|
||||
0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61,
|
||||
0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x75, 0x69,
|
||||
0x6c, 0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f,
|
||||
0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x63, 0x61, 0x6d, 0x70, 0x61, 0x69, 0x67, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x63, 0x61, 0x6d, 0x70, 0x61, 0x69, 0x67, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67,
|
||||
0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67,
|
||||
0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x13, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x22, 0x6f, 0x0a,
|
||||
0x1a, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x74,
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54,
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x70,
|
||||
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x0b, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x53, 0x65, 0x74, 0x22, 0x6a,
|
||||
0x0a, 0x13, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52,
|
||||
0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68,
|
||||
0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65,
|
||||
0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x46, 0x0a, 0x14, 0x52, 0x65,
|
||||
0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x74, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 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, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74,
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72,
|
||||
0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2a, 0x0a, 0x0e, 0x4c, 0x6f, 0x67, 0x6f,
|
||||
0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65,
|
||||
0x76, 0x6f, 0x6b, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x76,
|
||||
0x6f, 0x6b, 0x65, 0x64, 0x22, 0xdc, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 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, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67,
|
||||
0x75, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67,
|
||||
0x75, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65,
|
||||
0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
|
||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x61,
|
||||
0x73, 0x6f, 0x6e, 0x22, 0x38, 0x0a, 0x1a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67,
|
||||
0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x65, 0x64, 0x22, 0x7d, 0x0a,
|
||||
0x13, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04,
|
||||
0x6d, 0x65, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x80, 0x01, 0x0a,
|
||||
0x14, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65,
|
||||
0x64, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x5f, 0x61,
|
||||
0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x68, 0x65, 0x61, 0x72,
|
||||
0x74, 0x62, 0x65, 0x61, 0x74, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x32,
|
||||
0xdc, 0x05, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x51, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
||||
0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x55, 0x0a, 0x0f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x68, 0x69, 0x72, 0x64,
|
||||
0x50, 0x61, 0x72, 0x74, 0x79, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x68, 0x69, 0x72, 0x64,
|
||||
0x50, 0x61, 0x72, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74,
|
||||
0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x53, 0x65, 0x74,
|
||||
0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50,
|
||||
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x69, 0x0a, 0x12, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 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,
|
||||
0x51, 0x75, 0x69, 0x63, 0x6b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x52, 0x65,
|
||||
0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65,
|
||||
0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52,
|
||||
0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x1c, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f,
|
||||
0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f,
|
||||
0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x52, 0x65,
|
||||
0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64,
|
||||
0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72,
|
||||
0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72,
|
||||
0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65,
|
||||
0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61,
|
||||
0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x26,
|
||||
0x5a, 0x24, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70,
|
||||
0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b,
|
||||
0x75, 0x73, 0x65, 0x72, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
const file_proto_user_v1_auth_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x18proto/user/v1/auth.proto\x12\rhyapp.user.v1\x1a\x18proto/user/v1/user.proto\"\x8a\x01\n" +
|
||||
"\x14LoginPasswordRequest\x12.\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1a.hyapp.user.v1.RequestMetaR\x04meta\x12&\n" +
|
||||
"\x0fdisplay_user_id\x18\x02 \x01(\tR\rdisplayUserId\x12\x1a\n" +
|
||||
"\bpassword\x18\x03 \x01(\tR\bpassword\"\xea\x04\n" +
|
||||
"\x16LoginThirdPartyRequest\x12.\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1a.hyapp.user.v1.RequestMetaR\x04meta\x12\x1a\n" +
|
||||
"\bprovider\x18\x02 \x01(\tR\bprovider\x12\x1e\n" +
|
||||
"\n" +
|
||||
"credential\x18\x03 \x01(\tR\n" +
|
||||
"credential\x12\x1a\n" +
|
||||
"\busername\x18\x04 \x01(\tR\busername\x12\x16\n" +
|
||||
"\x06gender\x18\x05 \x01(\tR\x06gender\x12\x18\n" +
|
||||
"\acountry\x18\x06 \x01(\tR\acountry\x12\x1f\n" +
|
||||
"\vinvite_code\x18\a \x01(\tR\n" +
|
||||
"inviteCode\x12\x1b\n" +
|
||||
"\tdevice_id\x18\b \x01(\tR\bdeviceId\x12\x16\n" +
|
||||
"\x06device\x18\t \x01(\tR\x06device\x12\x16\n" +
|
||||
"\x06avatar\x18\n" +
|
||||
" \x01(\tR\x06avatar\x12\x14\n" +
|
||||
"\x05birth\x18\v \x01(\tR\x05birth\x12\x1f\n" +
|
||||
"\vapp_version\x18\f \x01(\tR\n" +
|
||||
"appVersion\x12\x16\n" +
|
||||
"\x06source\x18\r \x01(\tR\x06source\x12\x1a\n" +
|
||||
"\bplatform\x18\x0e \x01(\tR\bplatform\x12\x1a\n" +
|
||||
"\blanguage\x18\x0f \x01(\tR\blanguage\x12\x1d\n" +
|
||||
"\n" +
|
||||
"os_version\x18\x10 \x01(\tR\tosVersion\x12!\n" +
|
||||
"\fbuild_number\x18\x11 \x01(\tR\vbuildNumber\x12\x1a\n" +
|
||||
"\btimezone\x18\x12 \x01(\tR\btimezone\x12'\n" +
|
||||
"\x0finstall_channel\x18\x13 \x01(\tR\x0einstallChannel\x12\x1a\n" +
|
||||
"\bcampaign\x18\x14 \x01(\tR\bcampaign\"\xb8\x01\n" +
|
||||
"\fAuthResponse\x12.\n" +
|
||||
"\x05token\x18\x01 \x01(\v2\x18.hyapp.user.v1.AuthTokenR\x05token\x12\x1e\n" +
|
||||
"\vis_new_user\x18\x02 \x01(\bR\tisNewUser\x12+\n" +
|
||||
"\x11profile_completed\x18\x03 \x01(\bR\x10profileCompleted\x12+\n" +
|
||||
"\x11onboarding_status\x18\x04 \x01(\tR\x10onboardingStatus\"y\n" +
|
||||
"\x12SetPasswordRequest\x12.\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1a.hyapp.user.v1.RequestMetaR\x04meta\x12\x17\n" +
|
||||
"\auser_id\x18\x02 \x01(\x03R\x06userId\x12\x1a\n" +
|
||||
"\bpassword\x18\x03 \x01(\tR\bpassword\"8\n" +
|
||||
"\x13SetPasswordResponse\x12!\n" +
|
||||
"\fpassword_set\x18\x01 \x01(\bR\vpasswordSet\"\xcd\x04\n" +
|
||||
"\x19QuickCreateAccountRequest\x12.\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1a.hyapp.user.v1.RequestMetaR\x04meta\x12\x1a\n" +
|
||||
"\bpassword\x18\x02 \x01(\tR\bpassword\x12\x1a\n" +
|
||||
"\busername\x18\x03 \x01(\tR\busername\x12\x16\n" +
|
||||
"\x06avatar\x18\x04 \x01(\tR\x06avatar\x12\x16\n" +
|
||||
"\x06gender\x18\x05 \x01(\tR\x06gender\x12\x18\n" +
|
||||
"\acountry\x18\x06 \x01(\tR\acountry\x12\x1f\n" +
|
||||
"\vinvite_code\x18\a \x01(\tR\n" +
|
||||
"inviteCode\x12\x1b\n" +
|
||||
"\tdevice_id\x18\b \x01(\tR\bdeviceId\x12\x16\n" +
|
||||
"\x06device\x18\t \x01(\tR\x06device\x12\x1d\n" +
|
||||
"\n" +
|
||||
"os_version\x18\n" +
|
||||
" \x01(\tR\tosVersion\x12\x14\n" +
|
||||
"\x05birth\x18\v \x01(\tR\x05birth\x12\x1f\n" +
|
||||
"\vapp_version\x18\f \x01(\tR\n" +
|
||||
"appVersion\x12!\n" +
|
||||
"\fbuild_number\x18\r \x01(\tR\vbuildNumber\x12\x16\n" +
|
||||
"\x06source\x18\x0e \x01(\tR\x06source\x12'\n" +
|
||||
"\x0finstall_channel\x18\x0f \x01(\tR\x0einstallChannel\x12\x1a\n" +
|
||||
"\bcampaign\x18\x10 \x01(\tR\bcampaign\x12\x1a\n" +
|
||||
"\bplatform\x18\x11 \x01(\tR\bplatform\x12\x1a\n" +
|
||||
"\blanguage\x18\x12 \x01(\tR\blanguage\x12\x1a\n" +
|
||||
"\btimezone\x18\x13 \x01(\tR\btimezone\"o\n" +
|
||||
"\x1aQuickCreateAccountResponse\x12.\n" +
|
||||
"\x05token\x18\x01 \x01(\v2\x18.hyapp.user.v1.AuthTokenR\x05token\x12!\n" +
|
||||
"\fpassword_set\x18\x02 \x01(\bR\vpasswordSet\"j\n" +
|
||||
"\x13RefreshTokenRequest\x12.\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1a.hyapp.user.v1.RequestMetaR\x04meta\x12#\n" +
|
||||
"\rrefresh_token\x18\x02 \x01(\tR\frefreshToken\"F\n" +
|
||||
"\x14RefreshTokenResponse\x12.\n" +
|
||||
"\x05token\x18\x01 \x01(\v2\x18.hyapp.user.v1.AuthTokenR\x05token\"\x83\x01\n" +
|
||||
"\rLogoutRequest\x12.\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1a.hyapp.user.v1.RequestMetaR\x04meta\x12\x1d\n" +
|
||||
"\n" +
|
||||
"session_id\x18\x02 \x01(\tR\tsessionId\x12#\n" +
|
||||
"\rrefresh_token\x18\x03 \x01(\tR\frefreshToken\"*\n" +
|
||||
"\x0eLogoutResponse\x12\x18\n" +
|
||||
"\arevoked\x18\x01 \x01(\bR\arevoked\"\xdc\x01\n" +
|
||||
"\x19RecordLoginBlockedRequest\x12.\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1a.hyapp.user.v1.RequestMetaR\x04meta\x12\x18\n" +
|
||||
"\achannel\x18\x02 \x01(\tR\achannel\x12\x1a\n" +
|
||||
"\bplatform\x18\x03 \x01(\tR\bplatform\x12\x1a\n" +
|
||||
"\blanguage\x18\x04 \x01(\tR\blanguage\x12\x1a\n" +
|
||||
"\btimezone\x18\x05 \x01(\tR\btimezone\x12!\n" +
|
||||
"\fblock_reason\x18\x06 \x01(\tR\vblockReason\"8\n" +
|
||||
"\x1aRecordLoginBlockedResponse\x12\x1a\n" +
|
||||
"\brecorded\x18\x01 \x01(\bR\brecorded\"}\n" +
|
||||
"\x13AppHeartbeatRequest\x12.\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1a.hyapp.user.v1.RequestMetaR\x04meta\x12\x17\n" +
|
||||
"\auser_id\x18\x02 \x01(\x03R\x06userId\x12\x1d\n" +
|
||||
"\n" +
|
||||
"session_id\x18\x03 \x01(\tR\tsessionId\"\x80\x01\n" +
|
||||
"\x14AppHeartbeatResponse\x12\x1a\n" +
|
||||
"\baccepted\x18\x01 \x01(\bR\baccepted\x12&\n" +
|
||||
"\x0fheartbeat_at_ms\x18\x02 \x01(\x03R\rheartbeatAtMs\x12$\n" +
|
||||
"\x0eserver_time_ms\x18\x03 \x01(\x03R\fserverTimeMs2\xdc\x05\n" +
|
||||
"\vAuthService\x12Q\n" +
|
||||
"\rLoginPassword\x12#.hyapp.user.v1.LoginPasswordRequest\x1a\x1b.hyapp.user.v1.AuthResponse\x12U\n" +
|
||||
"\x0fLoginThirdParty\x12%.hyapp.user.v1.LoginThirdPartyRequest\x1a\x1b.hyapp.user.v1.AuthResponse\x12T\n" +
|
||||
"\vSetPassword\x12!.hyapp.user.v1.SetPasswordRequest\x1a\".hyapp.user.v1.SetPasswordResponse\x12i\n" +
|
||||
"\x12QuickCreateAccount\x12(.hyapp.user.v1.QuickCreateAccountRequest\x1a).hyapp.user.v1.QuickCreateAccountResponse\x12W\n" +
|
||||
"\fRefreshToken\x12\".hyapp.user.v1.RefreshTokenRequest\x1a#.hyapp.user.v1.RefreshTokenResponse\x12E\n" +
|
||||
"\x06Logout\x12\x1c.hyapp.user.v1.LogoutRequest\x1a\x1d.hyapp.user.v1.LogoutResponse\x12i\n" +
|
||||
"\x12RecordLoginBlocked\x12(.hyapp.user.v1.RecordLoginBlockedRequest\x1a).hyapp.user.v1.RecordLoginBlockedResponse\x12W\n" +
|
||||
"\fAppHeartbeat\x12\".hyapp.user.v1.AppHeartbeatRequest\x1a#.hyapp.user.v1.AppHeartbeatResponseB&Z$hyapp.local/api/proto/user/v1;userv1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_proto_user_v1_auth_proto_rawDescOnce sync.Once
|
||||
file_proto_user_v1_auth_proto_rawDescData = file_proto_user_v1_auth_proto_rawDesc
|
||||
file_proto_user_v1_auth_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_proto_user_v1_auth_proto_rawDescGZIP() []byte {
|
||||
file_proto_user_v1_auth_proto_rawDescOnce.Do(func() {
|
||||
file_proto_user_v1_auth_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_user_v1_auth_proto_rawDescData)
|
||||
file_proto_user_v1_auth_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_user_v1_auth_proto_rawDesc), len(file_proto_user_v1_auth_proto_rawDesc)))
|
||||
})
|
||||
return file_proto_user_v1_auth_proto_rawDescData
|
||||
}
|
||||
@ -1472,7 +1343,7 @@ func file_proto_user_v1_auth_proto_init() {
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proto_user_v1_auth_proto_rawDesc,
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_user_v1_auth_proto_rawDesc), len(file_proto_user_v1_auth_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 15,
|
||||
NumExtensions: 0,
|
||||
@ -1483,7 +1354,6 @@ func file_proto_user_v1_auth_proto_init() {
|
||||
MessageInfos: file_proto_user_v1_auth_proto_msgTypes,
|
||||
}.Build()
|
||||
File_proto_user_v1_auth_proto = out.File
|
||||
file_proto_user_v1_auth_proto_rawDesc = nil
|
||||
file_proto_user_v1_auth_proto_goTypes = nil
|
||||
file_proto_user_v1_auth_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.0
|
||||
// source: proto/user/v1/auth.proto
|
||||
|
||||
@ -158,28 +158,28 @@ type AuthServiceServer interface {
|
||||
type UnimplementedAuthServiceServer struct{}
|
||||
|
||||
func (UnimplementedAuthServiceServer) LoginPassword(context.Context, *LoginPasswordRequest) (*AuthResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method LoginPassword not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method LoginPassword not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) LoginThirdParty(context.Context, *LoginThirdPartyRequest) (*AuthResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method LoginThirdParty not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method LoginThirdParty not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) SetPassword(context.Context, *SetPasswordRequest) (*SetPasswordResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetPassword not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetPassword not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) QuickCreateAccount(context.Context, *QuickCreateAccountRequest) (*QuickCreateAccountResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method QuickCreateAccount not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method QuickCreateAccount not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) RefreshToken(context.Context, *RefreshTokenRequest) (*RefreshTokenResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RefreshToken not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RefreshToken not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) Logout(context.Context, *LogoutRequest) (*LogoutResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Logout not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method Logout not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) RecordLoginBlocked(context.Context, *RecordLoginBlockedRequest) (*RecordLoginBlockedResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RecordLoginBlocked not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RecordLoginBlocked not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) AppHeartbeat(context.Context, *AppHeartbeatRequest) (*AppHeartbeatResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AppHeartbeat not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AppHeartbeat not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
|
||||
func (UnimplementedAuthServiceServer) testEmbeddedByValue() {}
|
||||
@ -192,7 +192,7 @@ type UnsafeAuthServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAuthServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAuthServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.0
|
||||
// source: proto/user/v1/host.proto
|
||||
|
||||
@ -301,61 +301,61 @@ type UserHostServiceServer interface {
|
||||
type UnimplementedUserHostServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserHostServiceServer) SearchAgencies(context.Context, *SearchAgenciesRequest) (*SearchAgenciesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SearchAgencies not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SearchAgencies not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) ApplyToAgency(context.Context, *ApplyToAgencyRequest) (*ApplyToAgencyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ApplyToAgency not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ApplyToAgency not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) ReviewAgencyApplication(context.Context, *ReviewAgencyApplicationRequest) (*ReviewAgencyApplicationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ReviewAgencyApplication not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ReviewAgencyApplication not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) KickAgencyHost(context.Context, *KickAgencyHostRequest) (*KickAgencyHostResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method KickAgencyHost not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method KickAgencyHost not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) InviteAgency(context.Context, *InviteAgencyRequest) (*InviteAgencyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method InviteAgency not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method InviteAgency not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) InviteBD(context.Context, *InviteBDRequest) (*InviteBDResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method InviteBD not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method InviteBD not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) ListBDLeaderBDs(context.Context, *ListBDLeaderBDsRequest) (*ListBDLeaderBDsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListBDLeaderBDs not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListBDLeaderBDs not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) ListBDLeaderAgencies(context.Context, *ListBDLeaderAgenciesRequest) (*ListBDLeaderAgenciesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListBDLeaderAgencies not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListBDLeaderAgencies not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) ListBDAgencies(context.Context, *ListBDAgenciesRequest) (*ListBDAgenciesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListBDAgencies not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListBDAgencies not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) ProcessRoleInvitation(context.Context, *ProcessRoleInvitationRequest) (*ProcessRoleInvitationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessRoleInvitation not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessRoleInvitation not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) GetHostProfile(context.Context, *GetHostProfileRequest) (*GetHostProfileResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetHostProfile not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetHostProfile not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) GetBDProfile(context.Context, *GetBDProfileRequest) (*GetBDProfileResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetBDProfile not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetBDProfile not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) GetCoinSellerProfile(context.Context, *GetCoinSellerProfileRequest) (*GetCoinSellerProfileResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetCoinSellerProfile not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetCoinSellerProfile not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) ListActiveCoinSellersInMyRegion(context.Context, *ListActiveCoinSellersInMyRegionRequest) (*ListActiveCoinSellersInMyRegionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListActiveCoinSellersInMyRegion not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListActiveCoinSellersInMyRegion not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) GetUserRoleSummary(context.Context, *GetUserRoleSummaryRequest) (*GetUserRoleSummaryResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetUserRoleSummary not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetUserRoleSummary not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) GetAgency(context.Context, *GetAgencyRequest) (*GetAgencyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAgency not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetAgency not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) CheckBusinessCapability(context.Context, *CheckBusinessCapabilityRequest) (*CheckBusinessCapabilityResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CheckBusinessCapability not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CheckBusinessCapability not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) GetAgencyMembers(context.Context, *GetAgencyMembersRequest) (*GetAgencyMembersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAgencyMembers not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetAgencyMembers not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) GetAgencyApplications(context.Context, *GetAgencyApplicationsRequest) (*GetAgencyApplicationsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAgencyApplications not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetAgencyApplications not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostServiceServer) mustEmbedUnimplementedUserHostServiceServer() {}
|
||||
func (UnimplementedUserHostServiceServer) testEmbeddedByValue() {}
|
||||
@ -368,7 +368,7 @@ type UnsafeUserHostServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserHostServiceServer(s grpc.ServiceRegistrar, srv UserHostServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserHostServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserHostServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -961,31 +961,31 @@ type UserHostAdminServiceServer interface {
|
||||
type UnimplementedUserHostAdminServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserHostAdminServiceServer) CreateBDLeader(context.Context, *CreateBDLeaderRequest) (*CreateBDLeaderResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateBDLeader not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateBDLeader not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) CreateBD(context.Context, *CreateBDRequest) (*CreateBDResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateBD not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateBD not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) SetBDStatus(context.Context, *SetBDStatusRequest) (*SetBDStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetBDStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetBDStatus not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) CreateCoinSeller(context.Context, *CreateCoinSellerRequest) (*CreateCoinSellerResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateCoinSeller not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateCoinSeller not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) SetCoinSellerStatus(context.Context, *SetCoinSellerStatusRequest) (*SetCoinSellerStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetCoinSellerStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetCoinSellerStatus not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) CreateAgency(context.Context, *CreateAgencyRequest) (*CreateAgencyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateAgency not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateAgency not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) CloseAgency(context.Context, *CloseAgencyRequest) (*CloseAgencyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CloseAgency not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CloseAgency not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) DeleteAgency(context.Context, *DeleteAgencyRequest) (*DeleteAgencyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteAgency not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteAgency not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) SetAgencyJoinEnabled(context.Context, *SetAgencyJoinEnabledRequest) (*SetAgencyJoinEnabledResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetAgencyJoinEnabled not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetAgencyJoinEnabled not implemented")
|
||||
}
|
||||
func (UnimplementedUserHostAdminServiceServer) mustEmbedUnimplementedUserHostAdminServiceServer() {}
|
||||
func (UnimplementedUserHostAdminServiceServer) testEmbeddedByValue() {}
|
||||
@ -998,7 +998,7 @@ type UnsafeUserHostAdminServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserHostAdminServiceServer(s grpc.ServiceRegistrar, srv UserHostAdminServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserHostAdminServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserHostAdminServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -408,6 +408,11 @@ message CPRelationship {
|
||||
reserved "equipped";
|
||||
int64 formed_at_ms = 9;
|
||||
int64 updated_at_ms = 10;
|
||||
int64 current_level_threshold = 11;
|
||||
int64 next_level_threshold = 12;
|
||||
int64 needed_for_next_level = 13;
|
||||
int32 level_progress_percent = 14;
|
||||
bool max_level = 15;
|
||||
}
|
||||
|
||||
message ListCPApplicationsRequest {
|
||||
@ -619,6 +624,58 @@ message SetUserStatusResponse {
|
||||
string access_token_revoke_error = 11;
|
||||
}
|
||||
|
||||
message ManagerUserBlock {
|
||||
string block_id = 1;
|
||||
int64 manager_user_id = 2;
|
||||
int64 target_user_id = 3;
|
||||
string target_display_user_id = 4;
|
||||
string target_username = 5;
|
||||
string target_avatar = 6;
|
||||
string country = 7;
|
||||
int64 blocked_until_ms = 8;
|
||||
string status = 9;
|
||||
string reason = 10;
|
||||
int64 created_at_ms = 11;
|
||||
int64 updated_at_ms = 12;
|
||||
}
|
||||
|
||||
message CreateManagerUserBlockRequest {
|
||||
RequestMeta meta = 1;
|
||||
string command_id = 2;
|
||||
int64 manager_user_id = 3;
|
||||
int64 target_user_id = 4;
|
||||
int64 blocked_until_ms = 5;
|
||||
string reason = 6;
|
||||
}
|
||||
|
||||
message CreateManagerUserBlockResponse {
|
||||
ManagerUserBlock block = 1;
|
||||
SetUserStatusResponse status = 2;
|
||||
}
|
||||
|
||||
message ListManagerUserBlocksRequest {
|
||||
RequestMeta meta = 1;
|
||||
int64 manager_user_id = 2;
|
||||
string status = 3;
|
||||
int32 page_size = 4;
|
||||
}
|
||||
|
||||
message ListManagerUserBlocksResponse {
|
||||
repeated ManagerUserBlock blocks = 1;
|
||||
}
|
||||
|
||||
message UnblockManagerUserRequest {
|
||||
RequestMeta meta = 1;
|
||||
int64 manager_user_id = 2;
|
||||
string block_id = 3;
|
||||
string reason = 4;
|
||||
}
|
||||
|
||||
message UnblockManagerUserResponse {
|
||||
ManagerUserBlock block = 1;
|
||||
SetUserStatusResponse status = 2;
|
||||
}
|
||||
|
||||
// CompleteOnboardingRequest 是注册页唯一资料提交入口。
|
||||
message CompleteOnboardingRequest {
|
||||
RequestMeta meta = 1;
|
||||
@ -874,6 +931,9 @@ service UserService {
|
||||
rpc ChangeUserCountry(ChangeUserCountryRequest) returns (ChangeUserCountryResponse);
|
||||
rpc AdminChangeUserCountry(AdminChangeUserCountryRequest) returns (ChangeUserCountryResponse);
|
||||
rpc SetUserStatus(SetUserStatusRequest) returns (SetUserStatusResponse);
|
||||
rpc CreateManagerUserBlock(CreateManagerUserBlockRequest) returns (CreateManagerUserBlockResponse);
|
||||
rpc ListManagerUserBlocks(ListManagerUserBlocksRequest) returns (ListManagerUserBlocksResponse);
|
||||
rpc UnblockManagerUser(UnblockManagerUserRequest) returns (UnblockManagerUserResponse);
|
||||
rpc CompleteOnboarding(CompleteOnboardingRequest) returns (CompleteOnboardingResponse);
|
||||
}
|
||||
|
||||
@ -910,6 +970,7 @@ service UserCronService {
|
||||
rpc ProcessLoginIPRiskBatch(CronBatchRequest) returns (CronBatchResponse);
|
||||
rpc ProcessRegionRebuildBatch(CronBatchRequest) returns (CronBatchResponse);
|
||||
rpc CompensateMicOpenSessions(CronBatchRequest) returns (CronBatchResponse);
|
||||
rpc ExpireManagerUserBlocks(CronBatchRequest) returns (CronBatchResponse);
|
||||
}
|
||||
|
||||
// UserDeviceService 承载 App 设备推送 token 的绑定和失效。
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.0
|
||||
// source: proto/user/v1/user.proto
|
||||
|
||||
@ -29,6 +29,9 @@ const (
|
||||
UserService_ChangeUserCountry_FullMethodName = "/hyapp.user.v1.UserService/ChangeUserCountry"
|
||||
UserService_AdminChangeUserCountry_FullMethodName = "/hyapp.user.v1.UserService/AdminChangeUserCountry"
|
||||
UserService_SetUserStatus_FullMethodName = "/hyapp.user.v1.UserService/SetUserStatus"
|
||||
UserService_CreateManagerUserBlock_FullMethodName = "/hyapp.user.v1.UserService/CreateManagerUserBlock"
|
||||
UserService_ListManagerUserBlocks_FullMethodName = "/hyapp.user.v1.UserService/ListManagerUserBlocks"
|
||||
UserService_UnblockManagerUser_FullMethodName = "/hyapp.user.v1.UserService/UnblockManagerUser"
|
||||
UserService_CompleteOnboarding_FullMethodName = "/hyapp.user.v1.UserService/CompleteOnboarding"
|
||||
)
|
||||
|
||||
@ -48,6 +51,9 @@ type UserServiceClient interface {
|
||||
ChangeUserCountry(ctx context.Context, in *ChangeUserCountryRequest, opts ...grpc.CallOption) (*ChangeUserCountryResponse, error)
|
||||
AdminChangeUserCountry(ctx context.Context, in *AdminChangeUserCountryRequest, opts ...grpc.CallOption) (*ChangeUserCountryResponse, error)
|
||||
SetUserStatus(ctx context.Context, in *SetUserStatusRequest, opts ...grpc.CallOption) (*SetUserStatusResponse, error)
|
||||
CreateManagerUserBlock(ctx context.Context, in *CreateManagerUserBlockRequest, opts ...grpc.CallOption) (*CreateManagerUserBlockResponse, error)
|
||||
ListManagerUserBlocks(ctx context.Context, in *ListManagerUserBlocksRequest, opts ...grpc.CallOption) (*ListManagerUserBlocksResponse, error)
|
||||
UnblockManagerUser(ctx context.Context, in *UnblockManagerUserRequest, opts ...grpc.CallOption) (*UnblockManagerUserResponse, error)
|
||||
CompleteOnboarding(ctx context.Context, in *CompleteOnboardingRequest, opts ...grpc.CallOption) (*CompleteOnboardingResponse, error)
|
||||
}
|
||||
|
||||
@ -159,6 +165,36 @@ func (c *userServiceClient) SetUserStatus(ctx context.Context, in *SetUserStatus
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) CreateManagerUserBlock(ctx context.Context, in *CreateManagerUserBlockRequest, opts ...grpc.CallOption) (*CreateManagerUserBlockResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreateManagerUserBlockResponse)
|
||||
err := c.cc.Invoke(ctx, UserService_CreateManagerUserBlock_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) ListManagerUserBlocks(ctx context.Context, in *ListManagerUserBlocksRequest, opts ...grpc.CallOption) (*ListManagerUserBlocksResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListManagerUserBlocksResponse)
|
||||
err := c.cc.Invoke(ctx, UserService_ListManagerUserBlocks_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) UnblockManagerUser(ctx context.Context, in *UnblockManagerUserRequest, opts ...grpc.CallOption) (*UnblockManagerUserResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UnblockManagerUserResponse)
|
||||
err := c.cc.Invoke(ctx, UserService_UnblockManagerUser_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) CompleteOnboarding(ctx context.Context, in *CompleteOnboardingRequest, opts ...grpc.CallOption) (*CompleteOnboardingResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CompleteOnboardingResponse)
|
||||
@ -185,6 +221,9 @@ type UserServiceServer interface {
|
||||
ChangeUserCountry(context.Context, *ChangeUserCountryRequest) (*ChangeUserCountryResponse, error)
|
||||
AdminChangeUserCountry(context.Context, *AdminChangeUserCountryRequest) (*ChangeUserCountryResponse, error)
|
||||
SetUserStatus(context.Context, *SetUserStatusRequest) (*SetUserStatusResponse, error)
|
||||
CreateManagerUserBlock(context.Context, *CreateManagerUserBlockRequest) (*CreateManagerUserBlockResponse, error)
|
||||
ListManagerUserBlocks(context.Context, *ListManagerUserBlocksRequest) (*ListManagerUserBlocksResponse, error)
|
||||
UnblockManagerUser(context.Context, *UnblockManagerUserRequest) (*UnblockManagerUserResponse, error)
|
||||
CompleteOnboarding(context.Context, *CompleteOnboardingRequest) (*CompleteOnboardingResponse, error)
|
||||
mustEmbedUnimplementedUserServiceServer()
|
||||
}
|
||||
@ -197,37 +236,46 @@ type UserServiceServer interface {
|
||||
type UnimplementedUserServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetUser not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) BusinessUserLookup(context.Context, *BusinessUserLookupRequest) (*BusinessUserLookupResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BusinessUserLookup not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method BusinessUserLookup not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) GetMyProfileStats(context.Context, *GetMyProfileStatsRequest) (*GetMyProfileStatsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetMyProfileStats not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetMyProfileStats not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) BatchGetUsers(context.Context, *BatchGetUsersRequest) (*BatchGetUsersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BatchGetUsers not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method BatchGetUsers not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) ListUserIDs(context.Context, *ListUserIDsRequest) (*ListUserIDsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListUserIDs not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListUserIDs not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) GetUserMicLifetimeStats(context.Context, *GetUserMicLifetimeStatsRequest) (*GetUserMicLifetimeStatsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetUserMicLifetimeStats not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetUserMicLifetimeStats not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) UpdateUserProfile(context.Context, *UpdateUserProfileRequest) (*UpdateUserProfileResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateUserProfile not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateUserProfile not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) ChangeUserCountry(context.Context, *ChangeUserCountryRequest) (*ChangeUserCountryResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ChangeUserCountry not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ChangeUserCountry not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) AdminChangeUserCountry(context.Context, *AdminChangeUserCountryRequest) (*ChangeUserCountryResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminChangeUserCountry not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminChangeUserCountry not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) SetUserStatus(context.Context, *SetUserStatusRequest) (*SetUserStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetUserStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetUserStatus not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) CreateManagerUserBlock(context.Context, *CreateManagerUserBlockRequest) (*CreateManagerUserBlockResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateManagerUserBlock not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) ListManagerUserBlocks(context.Context, *ListManagerUserBlocksRequest) (*ListManagerUserBlocksResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListManagerUserBlocks not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) UnblockManagerUser(context.Context, *UnblockManagerUserRequest) (*UnblockManagerUserResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method UnblockManagerUser not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) CompleteOnboarding(context.Context, *CompleteOnboardingRequest) (*CompleteOnboardingResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CompleteOnboarding not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CompleteOnboarding not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {}
|
||||
func (UnimplementedUserServiceServer) testEmbeddedByValue() {}
|
||||
@ -240,7 +288,7 @@ type UnsafeUserServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -430,6 +478,60 @@ func _UserService_SetUserStatus_Handler(srv interface{}, ctx context.Context, de
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_CreateManagerUserBlock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateManagerUserBlockRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserServiceServer).CreateManagerUserBlock(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserService_CreateManagerUserBlock_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserServiceServer).CreateManagerUserBlock(ctx, req.(*CreateManagerUserBlockRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_ListManagerUserBlocks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListManagerUserBlocksRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserServiceServer).ListManagerUserBlocks(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserService_ListManagerUserBlocks_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserServiceServer).ListManagerUserBlocks(ctx, req.(*ListManagerUserBlocksRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_UnblockManagerUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UnblockManagerUserRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserServiceServer).UnblockManagerUser(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserService_UnblockManagerUser_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserServiceServer).UnblockManagerUser(ctx, req.(*UnblockManagerUserRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_CompleteOnboarding_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CompleteOnboardingRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -495,6 +597,18 @@ var UserService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "SetUserStatus",
|
||||
Handler: _UserService_SetUserStatus_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateManagerUserBlock",
|
||||
Handler: _UserService_CreateManagerUserBlock_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListManagerUserBlocks",
|
||||
Handler: _UserService_ListManagerUserBlocks_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UnblockManagerUser",
|
||||
Handler: _UserService_UnblockManagerUser_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CompleteOnboarding",
|
||||
Handler: _UserService_CompleteOnboarding_Handler,
|
||||
@ -683,37 +797,37 @@ type UserSocialServiceServer interface {
|
||||
type UnimplementedUserSocialServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserSocialServiceServer) RecordProfileVisit(context.Context, *RecordProfileVisitRequest) (*RecordProfileVisitResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RecordProfileVisit not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RecordProfileVisit not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) ListProfileVisitors(context.Context, *ListProfileVisitorsRequest) (*ListProfileVisitorsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListProfileVisitors not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListProfileVisitors not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) FollowUser(context.Context, *FollowUserRequest) (*FollowUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method FollowUser not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method FollowUser not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) UnfollowUser(context.Context, *UnfollowUserRequest) (*UnfollowUserResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UnfollowUser not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UnfollowUser not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) ListFollowing(context.Context, *ListFollowingRequest) (*ListFollowingResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListFollowing not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListFollowing not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) ApplyFriend(context.Context, *ApplyFriendRequest) (*ApplyFriendResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ApplyFriend not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ApplyFriend not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) AcceptFriendApplication(context.Context, *AcceptFriendApplicationRequest) (*AcceptFriendApplicationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AcceptFriendApplication not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AcceptFriendApplication not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) DeleteFriend(context.Context, *DeleteFriendRequest) (*DeleteFriendResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteFriend not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteFriend not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) ListFriends(context.Context, *ListFriendsRequest) (*ListFriendsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListFriends not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListFriends not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) ListFriendApplications(context.Context, *ListFriendApplicationsRequest) (*ListFriendApplicationsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListFriendApplications not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListFriendApplications not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) SubmitReport(context.Context, *SubmitReportRequest) (*SubmitReportResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SubmitReport not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SubmitReport not implemented")
|
||||
}
|
||||
func (UnimplementedUserSocialServiceServer) mustEmbedUnimplementedUserSocialServiceServer() {}
|
||||
func (UnimplementedUserSocialServiceServer) testEmbeddedByValue() {}
|
||||
@ -726,7 +840,7 @@ type UnsafeUserSocialServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserSocialServiceServer(s grpc.ServiceRegistrar, srv UserSocialServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserSocialServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserSocialServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1078,16 +1192,16 @@ type UserCPServiceServer interface {
|
||||
type UnimplementedUserCPServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserCPServiceServer) ListCPApplications(context.Context, *ListCPApplicationsRequest) (*ListCPApplicationsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListCPApplications not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListCPApplications not implemented")
|
||||
}
|
||||
func (UnimplementedUserCPServiceServer) AcceptCPApplication(context.Context, *AcceptCPApplicationRequest) (*AcceptCPApplicationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AcceptCPApplication not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AcceptCPApplication not implemented")
|
||||
}
|
||||
func (UnimplementedUserCPServiceServer) RejectCPApplication(context.Context, *RejectCPApplicationRequest) (*RejectCPApplicationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RejectCPApplication not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RejectCPApplication not implemented")
|
||||
}
|
||||
func (UnimplementedUserCPServiceServer) ListCPRelationships(context.Context, *ListCPRelationshipsRequest) (*ListCPRelationshipsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListCPRelationships not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListCPRelationships not implemented")
|
||||
}
|
||||
func (UnimplementedUserCPServiceServer) mustEmbedUnimplementedUserCPServiceServer() {}
|
||||
func (UnimplementedUserCPServiceServer) testEmbeddedByValue() {}
|
||||
@ -1100,7 +1214,7 @@ type UnsafeUserCPServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserCPServiceServer(s grpc.ServiceRegistrar, srv UserCPServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserCPServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserCPServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1259,7 +1373,7 @@ type UserCPInternalServiceServer interface {
|
||||
type UnimplementedUserCPInternalServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserCPInternalServiceServer) ConsumeRoomGiftCPEvent(context.Context, *ConsumeRoomGiftCPEventRequest) (*ConsumeRoomGiftCPEventResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConsumeRoomGiftCPEvent not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConsumeRoomGiftCPEvent not implemented")
|
||||
}
|
||||
func (UnimplementedUserCPInternalServiceServer) mustEmbedUnimplementedUserCPInternalServiceServer() {}
|
||||
func (UnimplementedUserCPInternalServiceServer) testEmbeddedByValue() {}
|
||||
@ -1272,7 +1386,7 @@ type UnsafeUserCPInternalServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserCPInternalServiceServer(s grpc.ServiceRegistrar, srv UserCPInternalServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserCPInternalServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserCPInternalServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1320,6 +1434,7 @@ const (
|
||||
UserCronService_ProcessLoginIPRiskBatch_FullMethodName = "/hyapp.user.v1.UserCronService/ProcessLoginIPRiskBatch"
|
||||
UserCronService_ProcessRegionRebuildBatch_FullMethodName = "/hyapp.user.v1.UserCronService/ProcessRegionRebuildBatch"
|
||||
UserCronService_CompensateMicOpenSessions_FullMethodName = "/hyapp.user.v1.UserCronService/CompensateMicOpenSessions"
|
||||
UserCronService_ExpireManagerUserBlocks_FullMethodName = "/hyapp.user.v1.UserCronService/ExpireManagerUserBlocks"
|
||||
)
|
||||
|
||||
// UserCronServiceClient is the client API for UserCronService service.
|
||||
@ -1331,6 +1446,7 @@ type UserCronServiceClient interface {
|
||||
ProcessLoginIPRiskBatch(ctx context.Context, in *CronBatchRequest, opts ...grpc.CallOption) (*CronBatchResponse, error)
|
||||
ProcessRegionRebuildBatch(ctx context.Context, in *CronBatchRequest, opts ...grpc.CallOption) (*CronBatchResponse, error)
|
||||
CompensateMicOpenSessions(ctx context.Context, in *CronBatchRequest, opts ...grpc.CallOption) (*CronBatchResponse, error)
|
||||
ExpireManagerUserBlocks(ctx context.Context, in *CronBatchRequest, opts ...grpc.CallOption) (*CronBatchResponse, error)
|
||||
}
|
||||
|
||||
type userCronServiceClient struct {
|
||||
@ -1371,6 +1487,16 @@ func (c *userCronServiceClient) CompensateMicOpenSessions(ctx context.Context, i
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userCronServiceClient) ExpireManagerUserBlocks(ctx context.Context, in *CronBatchRequest, opts ...grpc.CallOption) (*CronBatchResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CronBatchResponse)
|
||||
err := c.cc.Invoke(ctx, UserCronService_ExpireManagerUserBlocks_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// UserCronServiceServer is the server API for UserCronService service.
|
||||
// All implementations must embed UnimplementedUserCronServiceServer
|
||||
// for forward compatibility.
|
||||
@ -1380,6 +1506,7 @@ type UserCronServiceServer interface {
|
||||
ProcessLoginIPRiskBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error)
|
||||
ProcessRegionRebuildBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error)
|
||||
CompensateMicOpenSessions(context.Context, *CronBatchRequest) (*CronBatchResponse, error)
|
||||
ExpireManagerUserBlocks(context.Context, *CronBatchRequest) (*CronBatchResponse, error)
|
||||
mustEmbedUnimplementedUserCronServiceServer()
|
||||
}
|
||||
|
||||
@ -1391,13 +1518,16 @@ type UserCronServiceServer interface {
|
||||
type UnimplementedUserCronServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserCronServiceServer) ProcessLoginIPRiskBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessLoginIPRiskBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessLoginIPRiskBatch not implemented")
|
||||
}
|
||||
func (UnimplementedUserCronServiceServer) ProcessRegionRebuildBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessRegionRebuildBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessRegionRebuildBatch not implemented")
|
||||
}
|
||||
func (UnimplementedUserCronServiceServer) CompensateMicOpenSessions(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CompensateMicOpenSessions not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CompensateMicOpenSessions not implemented")
|
||||
}
|
||||
func (UnimplementedUserCronServiceServer) ExpireManagerUserBlocks(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ExpireManagerUserBlocks not implemented")
|
||||
}
|
||||
func (UnimplementedUserCronServiceServer) mustEmbedUnimplementedUserCronServiceServer() {}
|
||||
func (UnimplementedUserCronServiceServer) testEmbeddedByValue() {}
|
||||
@ -1410,7 +1540,7 @@ type UnsafeUserCronServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserCronServiceServer(s grpc.ServiceRegistrar, srv UserCronServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserCronServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserCronServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1474,6 +1604,24 @@ func _UserCronService_CompensateMicOpenSessions_Handler(srv interface{}, ctx con
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserCronService_ExpireManagerUserBlocks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CronBatchRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserCronServiceServer).ExpireManagerUserBlocks(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserCronService_ExpireManagerUserBlocks_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserCronServiceServer).ExpireManagerUserBlocks(ctx, req.(*CronBatchRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// UserCronService_ServiceDesc is the grpc.ServiceDesc for UserCronService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -1493,6 +1641,10 @@ var UserCronService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "CompensateMicOpenSessions",
|
||||
Handler: _UserCronService_CompensateMicOpenSessions_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ExpireManagerUserBlocks",
|
||||
Handler: _UserCronService_ExpireManagerUserBlocks_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "proto/user/v1/user.proto",
|
||||
@ -1560,10 +1712,10 @@ type UserDeviceServiceServer interface {
|
||||
type UnimplementedUserDeviceServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserDeviceServiceServer) BindPushToken(context.Context, *BindPushTokenRequest) (*BindPushTokenResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BindPushToken not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method BindPushToken not implemented")
|
||||
}
|
||||
func (UnimplementedUserDeviceServiceServer) DeletePushToken(context.Context, *DeletePushTokenRequest) (*DeletePushTokenResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeletePushToken not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method DeletePushToken not implemented")
|
||||
}
|
||||
func (UnimplementedUserDeviceServiceServer) mustEmbedUnimplementedUserDeviceServiceServer() {}
|
||||
func (UnimplementedUserDeviceServiceServer) testEmbeddedByValue() {}
|
||||
@ -1576,7 +1728,7 @@ type UnsafeUserDeviceServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserDeviceServiceServer(s grpc.ServiceRegistrar, srv UserDeviceServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserDeviceServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserDeviceServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1691,7 +1843,7 @@ type AppRegistryServiceServer interface {
|
||||
type UnimplementedAppRegistryServiceServer struct{}
|
||||
|
||||
func (UnimplementedAppRegistryServiceServer) ResolveApp(context.Context, *ResolveAppRequest) (*ResolveAppResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ResolveApp not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ResolveApp not implemented")
|
||||
}
|
||||
func (UnimplementedAppRegistryServiceServer) mustEmbedUnimplementedAppRegistryServiceServer() {}
|
||||
func (UnimplementedAppRegistryServiceServer) testEmbeddedByValue() {}
|
||||
@ -1704,7 +1856,7 @@ type UnsafeAppRegistryServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAppRegistryServiceServer(s grpc.ServiceRegistrar, srv AppRegistryServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAppRegistryServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedAppRegistryServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1812,10 +1964,10 @@ type CountryAdminServiceServer interface {
|
||||
type UnimplementedCountryAdminServiceServer struct{}
|
||||
|
||||
func (UnimplementedCountryAdminServiceServer) ListCountries(context.Context, *ListCountriesRequest) (*ListCountriesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListCountries not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListCountries not implemented")
|
||||
}
|
||||
func (UnimplementedCountryAdminServiceServer) UpdateCountry(context.Context, *UpdateCountryRequest) (*CountryResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateCountry not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateCountry not implemented")
|
||||
}
|
||||
func (UnimplementedCountryAdminServiceServer) mustEmbedUnimplementedCountryAdminServiceServer() {}
|
||||
func (UnimplementedCountryAdminServiceServer) testEmbeddedByValue() {}
|
||||
@ -1828,7 +1980,7 @@ type UnsafeCountryAdminServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterCountryAdminServiceServer(s grpc.ServiceRegistrar, srv CountryAdminServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedCountryAdminServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedCountryAdminServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1956,10 +2108,10 @@ type CountryQueryServiceServer interface {
|
||||
type UnimplementedCountryQueryServiceServer struct{}
|
||||
|
||||
func (UnimplementedCountryQueryServiceServer) ListRegistrationCountries(context.Context, *ListRegistrationCountriesRequest) (*ListRegistrationCountriesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRegistrationCountries not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRegistrationCountries not implemented")
|
||||
}
|
||||
func (UnimplementedCountryQueryServiceServer) ListLoginRiskBlockedCountries(context.Context, *ListLoginRiskBlockedCountriesRequest) (*ListLoginRiskBlockedCountriesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListLoginRiskBlockedCountries not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListLoginRiskBlockedCountries not implemented")
|
||||
}
|
||||
func (UnimplementedCountryQueryServiceServer) mustEmbedUnimplementedCountryQueryServiceServer() {}
|
||||
func (UnimplementedCountryQueryServiceServer) testEmbeddedByValue() {}
|
||||
@ -1972,7 +2124,7 @@ type UnsafeCountryQueryServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterCountryQueryServiceServer(s grpc.ServiceRegistrar, srv CountryQueryServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedCountryQueryServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedCountryQueryServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -2128,16 +2280,16 @@ type RegionAdminServiceServer interface {
|
||||
type UnimplementedRegionAdminServiceServer struct{}
|
||||
|
||||
func (UnimplementedRegionAdminServiceServer) ListRegions(context.Context, *ListRegionsRequest) (*ListRegionsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRegions not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRegions not implemented")
|
||||
}
|
||||
func (UnimplementedRegionAdminServiceServer) GetRegion(context.Context, *GetRegionRequest) (*RegionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRegion not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRegion not implemented")
|
||||
}
|
||||
func (UnimplementedRegionAdminServiceServer) UpdateRegion(context.Context, *UpdateRegionRequest) (*RegionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateRegion not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateRegion not implemented")
|
||||
}
|
||||
func (UnimplementedRegionAdminServiceServer) ReplaceRegionCountries(context.Context, *ReplaceRegionCountriesRequest) (*RegionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ReplaceRegionCountries not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ReplaceRegionCountries not implemented")
|
||||
}
|
||||
func (UnimplementedRegionAdminServiceServer) mustEmbedUnimplementedRegionAdminServiceServer() {}
|
||||
func (UnimplementedRegionAdminServiceServer) testEmbeddedByValue() {}
|
||||
@ -2150,7 +2302,7 @@ type UnsafeRegionAdminServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterRegionAdminServiceServer(s grpc.ServiceRegistrar, srv RegionAdminServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRegionAdminServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedRegionAdminServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -2361,19 +2513,19 @@ type UserIdentityServiceServer interface {
|
||||
type UnimplementedUserIdentityServiceServer struct{}
|
||||
|
||||
func (UnimplementedUserIdentityServiceServer) GetUserIdentity(context.Context, *GetUserIdentityRequest) (*GetUserIdentityResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetUserIdentity not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetUserIdentity not implemented")
|
||||
}
|
||||
func (UnimplementedUserIdentityServiceServer) ResolveDisplayUserID(context.Context, *ResolveDisplayUserIDRequest) (*ResolveDisplayUserIDResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ResolveDisplayUserID not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ResolveDisplayUserID not implemented")
|
||||
}
|
||||
func (UnimplementedUserIdentityServiceServer) ChangeDisplayUserID(context.Context, *ChangeDisplayUserIDRequest) (*ChangeDisplayUserIDResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ChangeDisplayUserID not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ChangeDisplayUserID not implemented")
|
||||
}
|
||||
func (UnimplementedUserIdentityServiceServer) ApplyPrettyDisplayUserID(context.Context, *ApplyPrettyDisplayUserIDRequest) (*ApplyPrettyDisplayUserIDResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ApplyPrettyDisplayUserID not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ApplyPrettyDisplayUserID not implemented")
|
||||
}
|
||||
func (UnimplementedUserIdentityServiceServer) ExpirePrettyDisplayUserID(context.Context, *ExpirePrettyDisplayUserIDRequest) (*ExpirePrettyDisplayUserIDResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ExpirePrettyDisplayUserID not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ExpirePrettyDisplayUserID not implemented")
|
||||
}
|
||||
func (UnimplementedUserIdentityServiceServer) mustEmbedUnimplementedUserIdentityServiceServer() {}
|
||||
func (UnimplementedUserIdentityServiceServer) testEmbeddedByValue() {}
|
||||
@ -2386,7 +2538,7 @@ type UnsafeUserIdentityServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterUserIdentityServiceServer(s grpc.ServiceRegistrar, srv UserIdentityServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedUserIdentityServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedUserIdentityServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.0
|
||||
// source: proto/wallet/v1/wallet.proto
|
||||
|
||||
@ -93,13 +93,13 @@ type WalletCronServiceServer interface {
|
||||
type UnimplementedWalletCronServiceServer struct{}
|
||||
|
||||
func (UnimplementedWalletCronServiceServer) ProcessHostSalaryDailySettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessHostSalaryDailySettlementBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessHostSalaryDailySettlementBatch not implemented")
|
||||
}
|
||||
func (UnimplementedWalletCronServiceServer) ProcessHostSalaryHalfMonthSettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessHostSalaryHalfMonthSettlementBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessHostSalaryHalfMonthSettlementBatch not implemented")
|
||||
}
|
||||
func (UnimplementedWalletCronServiceServer) ProcessHostSalaryMonthEndBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessHostSalaryMonthEndBatch not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ProcessHostSalaryMonthEndBatch not implemented")
|
||||
}
|
||||
func (UnimplementedWalletCronServiceServer) mustEmbedUnimplementedWalletCronServiceServer() {}
|
||||
func (UnimplementedWalletCronServiceServer) testEmbeddedByValue() {}
|
||||
@ -112,7 +112,7 @@ type UnsafeWalletCronServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterWalletCronServiceServer(s grpc.ServiceRegistrar, srv WalletCronServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedWalletCronServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedWalletCronServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
@ -1120,208 +1120,208 @@ type WalletServiceServer interface {
|
||||
type UnimplementedWalletServiceServer struct{}
|
||||
|
||||
func (UnimplementedWalletServiceServer) DebitGift(context.Context, *DebitGiftRequest) (*DebitGiftResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DebitGift not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method DebitGift not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) BatchDebitGift(context.Context, *BatchDebitGiftRequest) (*BatchDebitGiftResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BatchDebitGift not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method BatchDebitGift not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetBalances(context.Context, *GetBalancesRequest) (*GetBalancesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetBalances not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetBalances not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetActiveHostSalaryPolicy(context.Context, *GetActiveHostSalaryPolicyRequest) (*GetActiveHostSalaryPolicyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetActiveHostSalaryPolicy not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetActiveHostSalaryPolicy not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetHostSalaryProgress(context.Context, *GetHostSalaryProgressRequest) (*GetHostSalaryProgressResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetHostSalaryProgress not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetHostSalaryProgress not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) AdminCreditAsset(context.Context, *AdminCreditAssetRequest) (*AdminCreditAssetResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminCreditAsset not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminCreditAsset not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) AdminCreditCoinSellerStock(context.Context, *AdminCreditCoinSellerStockRequest) (*AdminCreditCoinSellerStockResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AdminCreditCoinSellerStock not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method AdminCreditCoinSellerStock not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) TransferCoinFromSeller(context.Context, *TransferCoinFromSellerRequest) (*TransferCoinFromSellerResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method TransferCoinFromSeller not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method TransferCoinFromSeller not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListCoinSellerSalaryExchangeRateTiers(context.Context, *ListCoinSellerSalaryExchangeRateTiersRequest) (*ListCoinSellerSalaryExchangeRateTiersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListCoinSellerSalaryExchangeRateTiers not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListCoinSellerSalaryExchangeRateTiers not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ExchangeSalaryToCoin(context.Context, *ExchangeSalaryToCoinRequest) (*ExchangeSalaryToCoinResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ExchangeSalaryToCoin not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ExchangeSalaryToCoin not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) TransferSalaryToCoinSeller(context.Context, *TransferSalaryToCoinSellerRequest) (*TransferSalaryToCoinSellerResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method TransferSalaryToCoinSeller not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method TransferSalaryToCoinSeller not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListResources(context.Context, *ListResourcesRequest) (*ListResourcesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListResources not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListResources not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetResource(context.Context, *GetResourceRequest) (*GetResourceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetResource not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetResource not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreateResource(context.Context, *CreateResourceRequest) (*ResourceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateResource not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateResource not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UpdateResource(context.Context, *UpdateResourceRequest) (*ResourceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateResource not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateResource not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) SetResourceStatus(context.Context, *SetResourceStatusRequest) (*ResourceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetResourceStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetResourceStatus not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListResourceGroups(context.Context, *ListResourceGroupsRequest) (*ListResourceGroupsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListResourceGroups not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListResourceGroups not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetResourceGroup(context.Context, *GetResourceGroupRequest) (*GetResourceGroupResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetResourceGroup not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetResourceGroup not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreateResourceGroup(context.Context, *CreateResourceGroupRequest) (*ResourceGroupResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateResourceGroup not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateResourceGroup not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UpdateResourceGroup(context.Context, *UpdateResourceGroupRequest) (*ResourceGroupResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateResourceGroup not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateResourceGroup not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) SetResourceGroupStatus(context.Context, *SetResourceGroupStatusRequest) (*ResourceGroupResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetResourceGroupStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetResourceGroupStatus not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListGiftConfigs(context.Context, *ListGiftConfigsRequest) (*ListGiftConfigsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListGiftConfigs not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListGiftConfigs not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListGiftTypeConfigs(context.Context, *ListGiftTypeConfigsRequest) (*ListGiftTypeConfigsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListGiftTypeConfigs not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListGiftTypeConfigs not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreateGiftConfig(context.Context, *CreateGiftConfigRequest) (*GiftConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateGiftConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateGiftConfig not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UpdateGiftConfig(context.Context, *UpdateGiftConfigRequest) (*GiftConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateGiftConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateGiftConfig not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) SetGiftConfigStatus(context.Context, *SetGiftConfigStatusRequest) (*GiftConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetGiftConfigStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetGiftConfigStatus not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UpsertGiftTypeConfig(context.Context, *UpsertGiftTypeConfigRequest) (*GiftTypeConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertGiftTypeConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertGiftTypeConfig not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GrantResource(context.Context, *GrantResourceRequest) (*ResourceGrantResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GrantResource not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GrantResource not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GrantResourceGroup(context.Context, *GrantResourceGroupRequest) (*ResourceGrantResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GrantResourceGroup not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GrantResourceGroup not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListUserResources(context.Context, *ListUserResourcesRequest) (*ListUserResourcesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListUserResources not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListUserResources not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) EquipUserResource(context.Context, *EquipUserResourceRequest) (*EquipUserResourceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method EquipUserResource not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method EquipUserResource not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UnequipUserResource(context.Context, *UnequipUserResourceRequest) (*UnequipUserResourceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UnequipUserResource not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UnequipUserResource not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) BatchGetUserEquippedResources(context.Context, *BatchGetUserEquippedResourcesRequest) (*BatchGetUserEquippedResourcesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BatchGetUserEquippedResources not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method BatchGetUserEquippedResources not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListResourceGrants(context.Context, *ListResourceGrantsRequest) (*ListResourceGrantsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListResourceGrants not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListResourceGrants not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListResourceShopItems(context.Context, *ListResourceShopItemsRequest) (*ListResourceShopItemsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListResourceShopItems not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListResourceShopItems not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UpsertResourceShopItems(context.Context, *UpsertResourceShopItemsRequest) (*UpsertResourceShopItemsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpsertResourceShopItems not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpsertResourceShopItems not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) SetResourceShopItemStatus(context.Context, *SetResourceShopItemStatusRequest) (*ResourceShopItemResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetResourceShopItemStatus not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method SetResourceShopItemStatus not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) PurchaseResourceShopItem(context.Context, *PurchaseResourceShopItemRequest) (*PurchaseResourceShopItemResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PurchaseResourceShopItem not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method PurchaseResourceShopItem not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListRechargeBills(context.Context, *ListRechargeBillsRequest) (*ListRechargeBillsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRechargeBills not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRechargeBills not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetWalletOverview(context.Context, *GetWalletOverviewRequest) (*GetWalletOverviewResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetWalletOverview not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetWalletOverview not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetWalletValueSummary(context.Context, *GetWalletValueSummaryRequest) (*GetWalletValueSummaryResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetWalletValueSummary not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetWalletValueSummary not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetUserGiftWall(context.Context, *GetUserGiftWallRequest) (*GetUserGiftWallResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetUserGiftWall not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetUserGiftWall not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListRechargeProducts(context.Context, *ListRechargeProductsRequest) (*ListRechargeProductsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRechargeProducts not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRechargeProducts not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ConfirmGooglePayment(context.Context, *ConfirmGooglePaymentRequest) (*ConfirmGooglePaymentResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConfirmGooglePayment not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ConfirmGooglePayment not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListAdminRechargeProducts(context.Context, *ListAdminRechargeProductsRequest) (*ListAdminRechargeProductsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListAdminRechargeProducts not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListAdminRechargeProducts not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreateRechargeProduct(context.Context, *CreateRechargeProductRequest) (*RechargeProductResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateRechargeProduct not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateRechargeProduct not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UpdateRechargeProduct(context.Context, *UpdateRechargeProductRequest) (*RechargeProductResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateRechargeProduct not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateRechargeProduct not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) DeleteRechargeProduct(context.Context, *DeleteRechargeProductRequest) (*DeleteRechargeProductResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteRechargeProduct not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteRechargeProduct not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetDiamondExchangeConfig(context.Context, *GetDiamondExchangeConfigRequest) (*GetDiamondExchangeConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetDiamondExchangeConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetDiamondExchangeConfig not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListWalletTransactions(context.Context, *ListWalletTransactionsRequest) (*ListWalletTransactionsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListWalletTransactions not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListWalletTransactions not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListVipPackages(context.Context, *ListVipPackagesRequest) (*ListVipPackagesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListVipPackages not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListVipPackages not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetMyVip(context.Context, *GetMyVipRequest) (*GetMyVipResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetMyVip not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetMyVip not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) PurchaseVip(context.Context, *PurchaseVipRequest) (*PurchaseVipResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PurchaseVip not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method PurchaseVip not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GrantVip(context.Context, *GrantVipRequest) (*GrantVipResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GrantVip not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GrantVip not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListAdminVipLevels(context.Context, *ListAdminVipLevelsRequest) (*ListAdminVipLevelsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListAdminVipLevels not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListAdminVipLevels not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UpdateAdminVipLevels(context.Context, *UpdateAdminVipLevelsRequest) (*UpdateAdminVipLevelsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateAdminVipLevels not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateAdminVipLevels not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreditTaskReward(context.Context, *CreditTaskRewardRequest) (*CreditTaskRewardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreditTaskReward not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreditTaskReward not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreditLuckyGiftReward(context.Context, *CreditLuckyGiftRewardRequest) (*CreditLuckyGiftRewardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreditLuckyGiftReward not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreditLuckyGiftReward not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreditRoomTurnoverReward(context.Context, *CreditRoomTurnoverRewardRequest) (*CreditRoomTurnoverRewardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreditRoomTurnoverReward not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreditRoomTurnoverReward not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ApplyGameCoinChange(context.Context, *ApplyGameCoinChangeRequest) (*ApplyGameCoinChangeResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ApplyGameCoinChange not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ApplyGameCoinChange not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetRedPacketConfig(context.Context, *GetRedPacketConfigRequest) (*GetRedPacketConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRedPacketConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRedPacketConfig not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) UpdateRedPacketConfig(context.Context, *UpdateRedPacketConfigRequest) (*UpdateRedPacketConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateRedPacketConfig not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateRedPacketConfig not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreateRedPacket(context.Context, *CreateRedPacketRequest) (*CreateRedPacketResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateRedPacket not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateRedPacket not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ClaimRedPacket(context.Context, *ClaimRedPacketRequest) (*ClaimRedPacketResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ClaimRedPacket not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ClaimRedPacket not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListRedPackets(context.Context, *ListRedPacketsRequest) (*ListRedPacketsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRedPackets not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ListRedPackets not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetRedPacket(context.Context, *GetRedPacketRequest) (*GetRedPacketResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRedPacket not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRedPacket not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ExpireRedPackets(context.Context, *ExpireRedPacketsRequest) (*ExpireRedPacketsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ExpireRedPackets not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method ExpireRedPackets not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) RetryRedPacketRefund(context.Context, *RetryRedPacketRefundRequest) (*RetryRedPacketRefundResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RetryRedPacketRefund not implemented")
|
||||
return nil, status.Error(codes.Unimplemented, "method RetryRedPacketRefund not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) mustEmbedUnimplementedWalletServiceServer() {}
|
||||
func (UnimplementedWalletServiceServer) testEmbeddedByValue() {}
|
||||
@ -1334,7 +1334,7 @@ type UnsafeWalletServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterWalletServiceServer(s grpc.ServiceRegistrar, srv WalletServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedWalletServiceServer was
|
||||
// If the following call panics, it indicates UnimplementedWalletServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
|
||||
@ -12,11 +12,12 @@
|
||||
|
||||
规则:
|
||||
|
||||
- 每个用户同时只能有一个 active 关系,不按类型拆数量,也不需要后台配置数量。
|
||||
- CP 关系每个用户最多 1 个,不提供可调数量。
|
||||
- 兄弟和姐妹的每人 active 数量由后台 CP 配置控制。
|
||||
- A 和 B 同时只能存在一种 active 关系。
|
||||
- A 可以给 B 发送 `cp`、`brother`、`sister` 多种 CP 礼物,形成多条 pending 申请。
|
||||
- B 接受其中一个申请后,同一对用户其他 pending 申请会被置为 `blocked`,不能再接受。
|
||||
- 申请默认 24 小时过期,当前不提供后台配置入口。
|
||||
- 申请默认 24 小时过期。
|
||||
- 不提供佩戴 CP 功能;资料卡如果要展示关系,直接展示用户当前 active 关系。
|
||||
|
||||
## 2. 服务归属
|
||||
@ -118,6 +119,7 @@ sequenceDiagram
|
||||
U-->>N: UserCPApplicationAccepted MQ
|
||||
U-->>N: UserCPRelationshipCreated MQ
|
||||
N->>IM: B -> A C2C cp_application_accepted
|
||||
N->>IM: A -> B C2C cp_application_accepted
|
||||
N->>IM: room cp_application_accepted, recipient_user_id=A
|
||||
N->>IM: region cp_relationship_created
|
||||
```
|
||||
@ -128,7 +130,9 @@ sequenceDiagram
|
||||
- pending 申请过期后不能接受,gateway envelope 返回 `CONFLICT`;内部 gRPC 语义是 FailedPrecondition。
|
||||
- 接受时同时校验 A 和 B 是否已经有任意 active 关系;任一方已有关系就返回 `CONFLICT`。
|
||||
- 同意成功后写 active 关系,关闭同一对用户其他 pending 申请。
|
||||
- 同意或拒绝都向 A 发送 C2C IM 和房间 IM。
|
||||
- 同意会发两条 C2C:`B -> A` 表示“我同意了你”,`A -> B` 表示“对方已同意你的申请”。
|
||||
- 同意和拒绝都会向 A 发送房间 IM,用 `recipient_user_id=A` 限定展示对象。
|
||||
- 拒绝仍只向 A 发送一条 C2C 和一条房间 IM。
|
||||
- 同意成功后额外发送区域 IM,区域取申请来源房间的 `visible_region_id`。
|
||||
|
||||
## 7. 亲密值和升级
|
||||
@ -140,9 +144,11 @@ sequenceDiagram
|
||||
- 普通礼物按 100% 热度值增加亲密值。
|
||||
- 幸运礼物、超级幸运礼物直接使用钱包回执里的最终 `heat_value`,不重复计算比例。
|
||||
- 多目标送礼时按每个目标的账务回执分别增加对应关系亲密值。
|
||||
- 等级范围 1 到 5;当前使用 user-service 默认等级规则,不提供后台配置入口。
|
||||
- 等级范围 1 到 5;等级亲密值阈值和奖励资源组由后台 CP 配置维护。
|
||||
- 每个等级可绑定奖励资源组,升级时调用 `wallet-service` 给双方发放资源。
|
||||
- 奖励发放幂等键为 `cp_level_reward:{relationship_id}:{level}:{user_id}`。
|
||||
- App 关系查询返回当前等级阈值、下一等级阈值、距离下一级和进度百分比。
|
||||
- 资料卡弹窗只能使用 `/api/v1/cp/relationships` 返回的阈值字段展示进度;客户端不能读取后台配置或硬编码等级表。
|
||||
|
||||
## 8. App HTTP接口
|
||||
|
||||
@ -155,6 +161,27 @@ sequenceDiagram
|
||||
| `POST` | `/api/v1/cp/applications/{application_id}/reject` | 拒绝申请 |
|
||||
| `GET` | `/api/v1/cp/relationships` | 查询我的 active 关系 |
|
||||
|
||||
`/api/v1/cp/relationships` 的 relationship item 包含:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `relationship_id` | 关系 ID |
|
||||
| `relation_type` | `cp`、`brother`、`sister` |
|
||||
| `status` | 当前为 `active` |
|
||||
| `me` | 当前用户快照 |
|
||||
| `partner` | 对方用户快照 |
|
||||
| `intimacy_value` | 当前亲密值 |
|
||||
| `level` | 当前等级 |
|
||||
| `current_level_threshold` | 当前等级起始亲密值 |
|
||||
| `next_level_threshold` | 下一等级所需亲密值;满级时为 0 |
|
||||
| `needed_for_next_level` | 距离下一级还需要多少亲密值;满级时为 0 |
|
||||
| `level_progress_percent` | 当前等级内进度百分比,0 到 100 |
|
||||
| `max_level` | 是否已经没有下一等级 |
|
||||
| `formed_at_ms` | 关系形成时间 |
|
||||
| `updated_at_ms` | 最近更新时间 |
|
||||
|
||||
这些字段由 user-service 从 `user_cp_level_rules` 计算,gateway 只做透传。客户端资料卡不能根据本地表推算这些值。
|
||||
|
||||
申请列表参数:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
@ -184,8 +211,8 @@ sequenceDiagram
|
||||
|
||||
| 表 | 说明 |
|
||||
| --- | --- |
|
||||
| `user_cp_relation_configs` | 历史兼容表;当前固定 `max_count_per_user=1`,不提供后台配置 |
|
||||
| `user_cp_level_rules` | 默认等级阈值和奖励资源组 |
|
||||
| `user_cp_relation_configs` | CP/兄弟/姐妹数量与申请过期配置;CP 数量服务端固定为 1,兄弟/姐妹读取后台配置 |
|
||||
| `user_cp_level_rules` | 等级阈值和奖励资源组 |
|
||||
| `user_cp_gift_event_consumption` | `RoomGiftSent` 消费幂等 |
|
||||
| `user_cp_applications` | CP 关系申请 |
|
||||
| `user_cp_relationships` | 双人关系事实 |
|
||||
@ -195,7 +222,8 @@ sequenceDiagram
|
||||
关键唯一约束:
|
||||
|
||||
- active 关系按用户对唯一:`(app_code, user_a_id, user_b_id, status='active')`。
|
||||
- active 关系按单用户唯一:任一用户已有 active 关系就不能再接受新关系。
|
||||
- CP active 关系按单用户唯一:任一用户已有 CP 关系就不能再接受新的 CP 关系。
|
||||
- 兄弟/姐妹 active 关系按后台配置做单用户数量上限校验。
|
||||
- pending 申请按用户对和类型唯一:`(app_code, requester_user_id, target_user_id, relation_type, status='pending')`。
|
||||
|
||||
## 10. 相关IM
|
||||
@ -204,13 +232,14 @@ sequenceDiagram
|
||||
| --- | --- | --- |
|
||||
| `cp_application_created` | C2C | A 送 CP 礼物触发申请后,A 发给 B |
|
||||
| `cp_application_created` | 房间群 | A 送 CP 礼物触发申请后,发到来源房间,payload 带 `recipient_user_id=B` |
|
||||
| `cp_application_accepted` | C2C | B 同意后,B 发给 A |
|
||||
| `cp_application_accepted` | C2C | B 同意后,B 发给 A,payload 带 `c2c_notice_role=accepted_to_requester`、`message_text=我同意了你` |
|
||||
| `cp_application_accepted` | C2C | B 同意后,A 发给 B,payload 带 `c2c_notice_role=accepted_to_acceptor`、`message_text=对方已同意你的申请` |
|
||||
| `cp_application_accepted` | 房间群 | B 同意后,发到来源房间,payload 带 `recipient_user_id=A` |
|
||||
| `cp_application_rejected` | C2C | B 拒绝后,B 发给 A |
|
||||
| `cp_application_rejected` | 房间群 | B 拒绝后,发到来源房间,payload 带 `recipient_user_id=A` |
|
||||
| `cp_relationship_created` | 区域群 | 关系建立后发送区域播报 |
|
||||
|
||||
C2C 使用腾讯云 IM `From_Account` 表达真实操作人:申请为 A,处理结果为 B。区域 IM 群 ID 使用 `hy_<app_code>_bc_r_<region_id>`,本地测试可通过 `group_id_prefix` 加前缀。
|
||||
C2C 使用腾讯云 IM `From_Account` 表达会话方向:申请为 A,拒绝为 B;同意会发 `B -> A` 和 `A -> B` 两条。区域 IM 群 ID 使用 `hy_<app_code>_bc_r_<region_id>`,本地测试可通过 `group_id_prefix` 加前缀。
|
||||
|
||||
## 11. 错误码
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# CP关系Flutter对接
|
||||
|
||||
本文只写 App 需要对接的地址、参数、返回值和相关 IM。CP 关系包含 `cp`、`brother`、`sister` 三种类型;每个用户同时只能有一个 active 关系,不需要佩戴接口,也没有后台数量配置。
|
||||
本文只写 App 需要对接的地址、参数、返回值和相关 IM。CP 关系包含 `cp`、`brother`、`sister` 三种类型;CP 关系每个用户最多 1 个,兄弟和姐妹数量由后台 CP 配置控制;不需要佩戴接口。
|
||||
|
||||
## 1. 礼物面板CP Tab
|
||||
|
||||
@ -274,6 +274,11 @@ X-App-Code: lalu
|
||||
},
|
||||
"intimacy_value": 1888,
|
||||
"level": 2,
|
||||
"current_level_threshold": 1000,
|
||||
"next_level_threshold": 3000,
|
||||
"needed_for_next_level": 1112,
|
||||
"level_progress_percent": 44,
|
||||
"max_level": false,
|
||||
"formed_at_ms": 1779259100000,
|
||||
"updated_at_ms": 1779259200000
|
||||
}
|
||||
@ -284,8 +289,12 @@ X-App-Code: lalu
|
||||
|
||||
说明:
|
||||
|
||||
- 每个用户同时只能有一个 active 关系。
|
||||
- CP 关系每个用户最多 1 个;兄弟和姐妹可拥有数量以后台配置为准。
|
||||
- A/B 两个用户之间同一时间只能存在一种 active 关系,不能同时是 CP、兄弟或姐妹。
|
||||
- 不需要佩戴接口,资料卡直接展示当前 active 关系。
|
||||
- 资料卡弹窗只使用后端返回的 `intimacy_value`、`level`、`current_level_threshold`、`next_level_threshold`、`needed_for_next_level`、`level_progress_percent` 和 `max_level`。
|
||||
- `max_level=true` 或 `next_level_threshold=0` 时表示没有下一等级,隐藏“距离下一级”和进度条。
|
||||
- Flutter 不要用本地常量、礼物价格或后台配置接口自行推算进度条和“距离下一级”。
|
||||
|
||||
## 7. 相关IM
|
||||
|
||||
@ -347,7 +356,7 @@ Data:
|
||||
|
||||
### 7.2 申请被同意
|
||||
|
||||
C2C 和房间 IM 都会收到:
|
||||
C2C 会收到双方互发的两条消息,房间 IM 仍然只给申请发起人 A 展示:
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
@ -362,6 +371,13 @@ Data 字段和申请消息一致,差异是:
|
||||
| `decided_at_ms` | 处理时间 |
|
||||
| `recipient_user_id` | 房间 IM 中为 A 的 user_id |
|
||||
|
||||
C2C 差异:
|
||||
|
||||
| 方向 | `c2c_notice_role` | `message_text` |
|
||||
| --- | --- | --- |
|
||||
| B -> A | `accepted_to_requester` | `我同意了你` |
|
||||
| A -> B | `accepted_to_acceptor` | `对方已同意你的申请` |
|
||||
|
||||
处理:
|
||||
|
||||
- A 收到后刷新 `/api/v1/cp/relationships`。
|
||||
@ -453,3 +469,4 @@ Data:
|
||||
- 同一个 `application_id` 在房间和 C2C 里可能都出现,按钮状态要共享。
|
||||
- 申请过期时间以 `expires_at_ms` 为准。
|
||||
- 亲密值和等级以后端关系接口返回为准,不在 Flutter 里按礼物价格推算。
|
||||
- 进度条和距离下一级只使用关系接口返回的阈值字段;字段缺失时不展示,不要伪造 `next_level_threshold`、`needed_for_next_level` 或进度百分比。
|
||||
|
||||
@ -1824,7 +1824,7 @@ paths:
|
||||
- manager-center
|
||||
summary: 经理中心赠送单个资源
|
||||
operationId: grantManagerResource
|
||||
description: 客户端只提交命令 ID、目标用户和资源 ID;数量固定为 1,有效期固定为 0,`grant_source` 固定为 `manager_center`。
|
||||
description: 客户端提交命令 ID、目标用户、资源 ID 和可选有效期;数量固定为 1,有效期只能是 7/30/90 天,未传默认 7 天,`grant_source` 固定为 `manager_center`。
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
@ -3575,10 +3575,16 @@ definitions:
|
||||
resource_id:
|
||||
type: string
|
||||
description: 资源 ID;wallet-service 会在事务内复验 `manager_grant_enabled`。
|
||||
duration_ms:
|
||||
type: integer
|
||||
format: int64
|
||||
enum: [604800000, 2592000000, 7776000000]
|
||||
default: 604800000
|
||||
description: 资源有效期,仅允许 7/30/90 天;未传时 gateway 默认 7 天。
|
||||
reason:
|
||||
type: string
|
||||
default: manager_center
|
||||
description: 不接受 `quantity`、`duration_ms`、`wallet_asset_amount` 等客户端计算字段。
|
||||
description: 不接受 `quantity`、`wallet_asset_amount` 等客户端计算字段。
|
||||
ManagerResourceGrantData:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@ -195,6 +195,29 @@ type EventResult struct {
|
||||
RewardJobCount int64
|
||||
}
|
||||
|
||||
// SetUserLevelCommand 描述经理中心直接设置用户等级的事实输入。
|
||||
// TotalValue 不由调用方提交,activity-service 会读取目标等级阈值后在事务内写入。
|
||||
type SetUserLevelCommand struct {
|
||||
CommandID string
|
||||
UserID int64
|
||||
Track string
|
||||
Level int32
|
||||
OperatorUserID int64
|
||||
Reason string
|
||||
}
|
||||
|
||||
// SetUserLevelResult 返回经理设置等级后的账户事实和补发奖励数量。
|
||||
type SetUserLevelResult struct {
|
||||
EventID string
|
||||
Status string
|
||||
Track string
|
||||
PreviousLevel int32
|
||||
NewLevel int32
|
||||
TotalValue int64
|
||||
RewardJobCount int64
|
||||
ServerTimeMS int64
|
||||
}
|
||||
|
||||
// RewardJob 是等级奖励资源组的异步发放任务。
|
||||
type RewardJob struct {
|
||||
AppCode string
|
||||
|
||||
@ -32,6 +32,7 @@ type Repository interface {
|
||||
ListLevelConfig(ctx context.Context, query domain.ConfigQuery, nowMS int64) (domain.Config, error)
|
||||
ListLevelRewards(ctx context.Context, query domain.RewardQuery) ([]domain.RewardJob, int64, error)
|
||||
ConsumeLevelEvent(ctx context.Context, event domain.ValueEvent, nowMS int64) (domain.EventResult, error)
|
||||
SetUserLevel(ctx context.Context, command domain.SetUserLevelCommand, nowMS int64) (domain.SetUserLevelResult, error)
|
||||
UpsertLevelTrack(ctx context.Context, command domain.TrackCommand, nowMS int64) (domain.Track, bool, error)
|
||||
UpsertLevelRule(ctx context.Context, command domain.RuleCommand, nowMS int64) (domain.Rule, bool, error)
|
||||
UpsertLevelTier(ctx context.Context, command domain.TierCommand, nowMS int64) (domain.Tier, bool, error)
|
||||
@ -220,6 +221,30 @@ func (s *Service) ConsumeLevelEvent(ctx context.Context, event domain.ValueEvent
|
||||
return s.repository.ConsumeLevelEvent(ctx, event, s.now().UnixMilli())
|
||||
}
|
||||
|
||||
// SetUserLevel 是经理中心的直接等级调整入口。
|
||||
// 它不接收累计值,避免调用方伪造进度;service 只校验轨道、等级和操作者,阈值读取与奖励补发在 repository 事务里完成。
|
||||
func (s *Service) SetUserLevel(ctx context.Context, command domain.SetUserLevelCommand) (domain.SetUserLevelResult, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
command.CommandID = strings.TrimSpace(command.CommandID)
|
||||
command.Track = normalizeTrack(command.Track)
|
||||
command.Reason = strings.TrimSpace(command.Reason)
|
||||
if command.CommandID == "" || command.UserID <= 0 || command.OperatorUserID <= 0 {
|
||||
return domain.SetUserLevelResult{}, xerr.New(xerr.InvalidArgument, "set user level command is incomplete")
|
||||
}
|
||||
if !validTrack(command.Track) {
|
||||
return domain.SetUserLevelResult{}, xerr.New(xerr.InvalidArgument, "track is invalid")
|
||||
}
|
||||
if command.Level < 1 || command.Level > 11 {
|
||||
return domain.SetUserLevelResult{}, xerr.New(xerr.InvalidArgument, "level must be between 1 and 11")
|
||||
}
|
||||
if command.Reason == "" {
|
||||
command.Reason = "manager_center_level"
|
||||
}
|
||||
return s.repository.SetUserLevel(ctx, command, s.now().UnixMilli())
|
||||
}
|
||||
|
||||
// HandleRoomEvent 把 room-service 已提交送礼事实映射为财富和魅力两条等级增量。
|
||||
func (s *Service) HandleRoomEvent(ctx context.Context, envelope *roomeventsv1.EventEnvelope) (int32, error) {
|
||||
if envelope == nil {
|
||||
|
||||
@ -265,6 +265,112 @@ func (r *Repository) ConsumeLevelEvent(ctx context.Context, event domain.ValueEv
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetUserLevel 在一个事务里把用户某条轨道直接设置到目标等级阈值。
|
||||
// 经理中心需要支持降级,所以这里不能复用只接受正增量的 ConsumeLevelEvent;但仍写 growth_level_value_events 保留幂等事件和审计来源。
|
||||
func (r *Repository) SetUserLevel(ctx context.Context, command domain.SetUserLevelCommand, nowMS int64) (domain.SetUserLevelResult, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return domain.SetUserLevelResult{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
eventID := "manager_level:" + command.CommandID
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
account, err := r.ensureLevelAccountForUpdate(ctx, tx, command.UserID, command.Track, nowMS)
|
||||
if err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
rules, err := r.listActiveLevelRules(ctx, tx, command.Track)
|
||||
if err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
targetValue, ok := requiredValueForLevel(rules, command.Level)
|
||||
if !ok {
|
||||
return domain.SetUserLevelResult{}, xerr.New(xerr.NotFound, "level rule not found")
|
||||
}
|
||||
tiers, err := r.listActiveLevelTiers(ctx, tx, command.Track)
|
||||
if err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
delta := targetValue - account.TotalValue
|
||||
inserted, err := r.insertLevelValueEvent(ctx, tx, domain.ValueEvent{
|
||||
EventID: eventID,
|
||||
SourceEventID: command.CommandID,
|
||||
SourceService: "manager_center",
|
||||
SourceEventType: "ManagerSetUserLevel",
|
||||
UserID: command.UserID,
|
||||
Track: command.Track,
|
||||
MetricType: "manager_set_level",
|
||||
ValueDelta: delta,
|
||||
OccurredAtMS: nowMS,
|
||||
DimensionsJSON: normalizeJSONMap(map[string]any{
|
||||
"operator_user_id": command.OperatorUserID,
|
||||
"target_level": command.Level,
|
||||
"reason": command.Reason,
|
||||
}),
|
||||
}, nowMS)
|
||||
if err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
if !inserted {
|
||||
if err := tx.Commit(); err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
return domain.SetUserLevelResult{
|
||||
EventID: eventID,
|
||||
Status: domain.EventStatusDuplicate,
|
||||
Track: command.Track,
|
||||
NewLevel: account.CurrentLevel,
|
||||
TotalValue: account.TotalValue,
|
||||
ServerTimeMS: nowMS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
previousLevel := account.CurrentLevel
|
||||
previousTierID := account.CurrentTierID
|
||||
nextLevel := levelForValue(rules, targetValue)
|
||||
nextTier := tierForLevel(tiers, nextLevel)
|
||||
nextTierID := nextTier.TierID
|
||||
levelUpdatedAtMS := account.LevelUpdatedAtMS
|
||||
if nextLevel != previousLevel {
|
||||
levelUpdatedAtMS = nowMS
|
||||
}
|
||||
tierUpdatedAtMS := account.TierUpdatedAtMS
|
||||
if nextTierID != previousTierID {
|
||||
tierUpdatedAtMS = nowMS
|
||||
}
|
||||
if err := r.updateLevelAccount(ctx, tx, command.UserID, command.Track, targetValue, nextLevel, nextTierID, levelUpdatedAtMS, tierUpdatedAtMS, nowMS); err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
if err := r.insertLevelHistory(ctx, tx, domain.ValueEvent{EventID: eventID, UserID: command.UserID, Track: command.Track}, previousLevel, nextLevel, previousTierID, nextTierID, targetValue, nowMS); err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
// 经理直接设置等级时要补齐从 1 级到目标等级之间缺失的奖励;唯一键保证已发过的等级不会重复入队。
|
||||
rewardJobCount, err := r.createLevelRewardJobs(ctx, tx, command.UserID, command.Track, 0, nextLevel, 0, nextTier, rules, nowMS)
|
||||
if err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
badgeResourceID, badgeSourceLevel := levelRuleBadgeForLevel(rules, nextLevel)
|
||||
if err := r.upsertLevelDisplayProfile(ctx, tx, command.UserID, command.Track, nextLevel, nextTier, badgeResourceID, badgeSourceLevel, nowMS); err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return domain.SetUserLevelResult{}, err
|
||||
}
|
||||
return domain.SetUserLevelResult{
|
||||
EventID: eventID,
|
||||
Status: domain.EventStatusConsumed,
|
||||
Track: command.Track,
|
||||
PreviousLevel: previousLevel,
|
||||
NewLevel: nextLevel,
|
||||
TotalValue: targetValue,
|
||||
RewardJobCount: rewardJobCount,
|
||||
ServerTimeMS: nowMS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) UpsertLevelTrack(ctx context.Context, command domain.TrackCommand, nowMS int64) (domain.Track, bool, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return domain.Track{}, false, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
@ -844,6 +950,15 @@ func levelForValue(rules []domain.Rule, totalValue int64) int32 {
|
||||
return level
|
||||
}
|
||||
|
||||
func requiredValueForLevel(rules []domain.Rule, level int32) (int64, bool) {
|
||||
for _, rule := range rules {
|
||||
if rule.Level == level && rule.Status == domain.StatusActive {
|
||||
return rule.RequiredValue, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func tierForLevel(tiers []domain.Tier, level int32) domain.Tier {
|
||||
if level < 0 {
|
||||
return domain.Tier{}
|
||||
@ -856,6 +971,14 @@ func tierForLevel(tiers []domain.Tier, level int32) domain.Tier {
|
||||
return domain.Tier{}
|
||||
}
|
||||
|
||||
func normalizeJSONMap(value map[string]any) string {
|
||||
data, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return "{}"
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func tierByID(tiers []domain.Tier, tierID int64) domain.Tier {
|
||||
if tierID <= 0 {
|
||||
return domain.Tier{}
|
||||
|
||||
@ -120,6 +120,31 @@ func (s *GrowthLevelServer) ConsumeLevelEvent(ctx context.Context, req *activity
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *GrowthLevelServer) SetUserLevel(ctx context.Context, req *activityv1.SetUserLevelRequest) (*activityv1.SetUserLevelResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
result, err := s.svc.SetUserLevel(ctx, domain.SetUserLevelCommand{
|
||||
CommandID: req.GetCommandId(),
|
||||
UserID: req.GetUserId(),
|
||||
Track: req.GetTrack(),
|
||||
Level: req.GetLevel(),
|
||||
OperatorUserID: req.GetOperatorUserId(),
|
||||
Reason: req.GetReason(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &activityv1.SetUserLevelResponse{
|
||||
EventId: result.EventID,
|
||||
Status: result.Status,
|
||||
Track: result.Track,
|
||||
PreviousLevel: result.PreviousLevel,
|
||||
NewLevel: result.NewLevel,
|
||||
TotalValue: result.TotalValue,
|
||||
RewardJobCount: result.RewardJobCount,
|
||||
ServerTimeMs: result.ServerTimeMS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *GrowthLevelServer) IssueRegistrationLevelBadges(ctx context.Context, req *activityv1.IssueRegistrationLevelBadgesRequest) (*activityv1.IssueRegistrationLevelBadgesResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
grants, err := s.svc.IssueRegistrationLevelBadges(ctx, req.GetUserId(), req.GetCommandId())
|
||||
|
||||
@ -116,6 +116,7 @@ func New(cfg config.Config) (*App, error) {
|
||||
"login_ip_risk": userCron.ProcessLoginIPRiskBatch,
|
||||
"user_region_rebuild": userCron.ProcessRegionRebuildBatch,
|
||||
"mic_open_session_compensation": userCron.CompensateMicOpenSessions,
|
||||
"manager_user_block_expiry": userCron.ExpireManagerUserBlocks,
|
||||
"message_fanout": activityCron.ProcessMessageFanoutBatch,
|
||||
"growth_level_reward": activityCron.ProcessLevelRewardBatch,
|
||||
"achievement_reward": activityCron.ProcessAchievementRewardBatch,
|
||||
|
||||
@ -222,6 +222,14 @@ func defaultTasks() map[string]TaskConfig {
|
||||
PendingPublishMaxAge: "2m",
|
||||
PublishingSessionMaxAge: "12h",
|
||||
},
|
||||
"manager_user_block_expiry": {
|
||||
Enabled: true,
|
||||
Interval: "30s",
|
||||
Timeout: "10s",
|
||||
LockTTL: "30s",
|
||||
BatchSize: 100,
|
||||
AppCodes: []string{defaultAppCode},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -38,6 +38,12 @@ func (c *UserCronClient) CompensateMicOpenSessions(ctx context.Context, req sche
|
||||
return userCronResult(resp), err
|
||||
}
|
||||
|
||||
// ExpireManagerUserBlocks handles timed manager-center bans after their unblock time.
|
||||
func (c *UserCronClient) ExpireManagerUserBlocks(ctx context.Context, req scheduler.BatchRequest) (scheduler.BatchResult, error) {
|
||||
resp, err := c.client.ExpireManagerUserBlocks(ctx, userCronRequest(req))
|
||||
return userCronResult(resp), err
|
||||
}
|
||||
|
||||
func userCronRequest(req scheduler.BatchRequest) *userv1.CronBatchRequest {
|
||||
return &userv1.CronBatchRequest{
|
||||
Meta: &userv1.RequestMeta{
|
||||
|
||||
@ -80,6 +80,7 @@ CREATE TABLE IF NOT EXISTS game_launch_sessions (
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY(app_code, session_id),
|
||||
KEY idx_game_launch_user(app_code, user_id, created_at_ms),
|
||||
KEY idx_game_launch_recent(app_code, user_id, scene, created_at_ms, game_id),
|
||||
KEY idx_game_launch_token(app_code, launch_token_hash)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏启动会话表';
|
||||
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
gamedomain "hyapp/services/game-service/internal/domain/game"
|
||||
)
|
||||
|
||||
type bridgeScriptConfig struct {
|
||||
URL string `json:"bridge_script_url"`
|
||||
URLAlias string `json:"bridgeScriptUrl"`
|
||||
Version string `json:"bridge_script_version"`
|
||||
VersionAlias string `json:"bridgeScriptVersion"`
|
||||
SHA256 string `json:"bridge_script_sha256"`
|
||||
SHA256Alias string `json:"bridgeScriptSha256"`
|
||||
SHA256AltAlias string `json:"bridge_script_hash"`
|
||||
}
|
||||
|
||||
func bridgeScriptConfigFromPlatform(value any) bridgeScriptConfig {
|
||||
var raw string
|
||||
switch typed := value.(type) {
|
||||
case gamedomain.Platform:
|
||||
raw = typed.AdapterConfigJSON
|
||||
case gamedomain.LaunchableGame:
|
||||
raw = typed.AdapterConfigJSON
|
||||
}
|
||||
var config bridgeScriptConfig
|
||||
_ = json.Unmarshal([]byte(strings.TrimSpace(raw)), &config)
|
||||
config.URL = firstBridgeScriptValue(config.URL, config.URLAlias)
|
||||
config.Version = firstBridgeScriptValue(config.Version, config.VersionAlias)
|
||||
config.SHA256 = firstBridgeScriptValue(config.SHA256, config.SHA256Alias, config.SHA256AltAlias)
|
||||
return config
|
||||
}
|
||||
|
||||
func firstBridgeScriptValue(values ...string) string {
|
||||
for _, value := range values {
|
||||
normalized := strings.TrimSpace(value)
|
||||
if normalized != "" {
|
||||
return normalized
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func appendBridgeScriptQuery(query url.Values, game gamedomain.LaunchableGame) {
|
||||
config := bridgeScriptConfigFromPlatform(game)
|
||||
if config.URL == "" {
|
||||
return
|
||||
}
|
||||
// Flutter 从启动 URL 还原 bridgeConfig;同时写 snake/camel 别名,避免 H5 或老客户端只识别其中一种命名。
|
||||
query.Set("bridge_script_url", config.URL)
|
||||
query.Set("bridgeScriptUrl", config.URL)
|
||||
if config.Version != "" {
|
||||
query.Set("bridge_script_version", config.Version)
|
||||
query.Set("bridgeScriptVersion", config.Version)
|
||||
}
|
||||
if config.SHA256 != "" {
|
||||
query.Set("bridge_script_sha256", config.SHA256)
|
||||
query.Set("bridgeScriptSha256", config.SHA256)
|
||||
}
|
||||
appendBridgeKeys(query, "bridge_script_url", "bridge_script_version", "bridge_script_sha256")
|
||||
}
|
||||
|
||||
func appendBridgeKeys(query url.Values, keys ...string) {
|
||||
seen := make(map[string]bool)
|
||||
values := make([]string, 0, len(keys)+1)
|
||||
for _, raw := range strings.Split(query.Get("bridge_keys"), ",") {
|
||||
key := strings.TrimSpace(raw)
|
||||
if key == "" || seen[key] {
|
||||
continue
|
||||
}
|
||||
seen[key] = true
|
||||
values = append(values, key)
|
||||
}
|
||||
for _, raw := range keys {
|
||||
key := strings.TrimSpace(raw)
|
||||
if key == "" || seen[key] {
|
||||
continue
|
||||
}
|
||||
seen[key] = true
|
||||
values = append(values, key)
|
||||
}
|
||||
if len(values) > 0 {
|
||||
query.Set("bridge_keys", strings.Join(values, ","))
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -29,6 +30,7 @@ const defaultScene = gamedomain.SceneVoiceRoom
|
||||
type Repository interface {
|
||||
Ping(ctx context.Context) error
|
||||
ListGames(ctx context.Context, query ListGamesQuery) ([]gamedomain.AppGame, error)
|
||||
ListRecentGames(ctx context.Context, query ListRecentGamesQuery) ([]gamedomain.AppGame, error)
|
||||
GetLaunchableGame(ctx context.Context, appCode string, gameID string) (gamedomain.LaunchableGame, error)
|
||||
GetPlatform(ctx context.Context, appCode string, platformCode string) (gamedomain.Platform, error)
|
||||
CreateLaunchSession(ctx context.Context, session gamedomain.LaunchSession) error
|
||||
@ -91,6 +93,17 @@ type ListGamesQuery struct {
|
||||
ClientPlatform string
|
||||
}
|
||||
|
||||
type ListRecentGamesQuery struct {
|
||||
AppCode string
|
||||
UserID int64
|
||||
Scene string
|
||||
RoomID string
|
||||
RegionID int64
|
||||
Language string
|
||||
ClientPlatform string
|
||||
PageSize int32
|
||||
}
|
||||
|
||||
type ListCatalogQuery struct {
|
||||
AppCode string
|
||||
PlatformCode string
|
||||
@ -120,6 +133,13 @@ type LaunchResult struct {
|
||||
ServerTimeMS int64
|
||||
}
|
||||
|
||||
type BridgeScriptResult struct {
|
||||
URL string
|
||||
Version string
|
||||
SHA256 string
|
||||
ServerTimeMS int64
|
||||
}
|
||||
|
||||
// New 创建 game-service 用例层。
|
||||
func New(config Config, repository Repository, wallet WalletClient, user UserClient, activity ...ActivityClient) *Service {
|
||||
if config.LaunchSessionTTL <= 0 {
|
||||
@ -167,6 +187,62 @@ func (s *Service) ListGames(ctx context.Context, query ListGamesQuery) ([]gamedo
|
||||
return games, s.now().UnixMilli(), err
|
||||
}
|
||||
|
||||
// ListRecentGames 返回当前用户最近启动过的语音房游戏,供 App 的 My Games tab 直接展示。
|
||||
func (s *Service) ListRecentGames(ctx context.Context, query ListRecentGamesQuery) ([]gamedomain.AppGame, int64, error) {
|
||||
if query.UserID <= 0 {
|
||||
return nil, 0, xerr.New(xerr.InvalidArgument, "user_id is required")
|
||||
}
|
||||
if s.repository == nil {
|
||||
return nil, 0, xerr.New(xerr.Unavailable, "game repository is not configured")
|
||||
}
|
||||
query.AppCode = appcode.Normalize(query.AppCode)
|
||||
query.Scene = normalizeScene(query.Scene)
|
||||
query.Language = strings.ToLower(strings.TrimSpace(query.Language))
|
||||
query.ClientPlatform = strings.ToLower(strings.TrimSpace(query.ClientPlatform))
|
||||
query.PageSize = normalizeRecentGamesPageSize(query.PageSize)
|
||||
ctx = appcode.WithContext(ctx, query.AppCode)
|
||||
|
||||
// 最近常玩只信任 game_launch_sessions 的真实启动事实,同时在仓储层重新套当前展示规则;
|
||||
// 这样旧游戏下架、维护、区域不可见后不会继续出现在 My Games tab。
|
||||
games, err := s.repository.ListRecentGames(ctx, query)
|
||||
return games, s.now().UnixMilli(), err
|
||||
}
|
||||
|
||||
// GetBridgeScript 返回 App 通用游戏桥接脚本配置,供客户端启动预热和打开游戏面板时做轻量刷新。
|
||||
func (s *Service) GetBridgeScript(ctx context.Context, appCode string) (BridgeScriptResult, error) {
|
||||
if s.repository == nil {
|
||||
return BridgeScriptResult{}, xerr.New(xerr.Unavailable, "game repository is not configured")
|
||||
}
|
||||
appCode = appcode.Normalize(appCode)
|
||||
ctx = appcode.WithContext(ctx, appCode)
|
||||
|
||||
platforms, err := s.repository.ListPlatforms(ctx, appCode, gamedomain.StatusActive)
|
||||
if err != nil {
|
||||
return BridgeScriptResult{}, err
|
||||
}
|
||||
// admin 会把通用桥接脚本同步写入所有平台;这里仍按 sort/code 排序后读取第一份有效配置,
|
||||
// 避免数据库返回顺序变化导致 App 在相同配置之间来回切换。
|
||||
sort.SliceStable(platforms, func(left, right int) bool {
|
||||
if platforms[left].SortOrder != platforms[right].SortOrder {
|
||||
return platforms[left].SortOrder < platforms[right].SortOrder
|
||||
}
|
||||
return strings.Compare(platforms[left].PlatformCode, platforms[right].PlatformCode) < 0
|
||||
})
|
||||
for _, platform := range platforms {
|
||||
config := bridgeScriptConfigFromPlatform(platform)
|
||||
if strings.TrimSpace(config.URL) == "" {
|
||||
continue
|
||||
}
|
||||
return BridgeScriptResult{
|
||||
URL: strings.TrimSpace(config.URL),
|
||||
Version: strings.TrimSpace(config.Version),
|
||||
SHA256: strings.TrimSpace(config.SHA256),
|
||||
ServerTimeMS: s.now().UnixMilli(),
|
||||
}, nil
|
||||
}
|
||||
return BridgeScriptResult{ServerTimeMS: s.now().UnixMilli()}, nil
|
||||
}
|
||||
|
||||
// LaunchGame 创建短期 H5 启动会话,并把原始钱包能力限制在服务端。
|
||||
func (s *Service) LaunchGame(ctx context.Context, command LaunchCommand) (LaunchResult, error) {
|
||||
if command.UserID <= 0 || strings.TrimSpace(command.GameID) == "" {
|
||||
@ -602,6 +678,16 @@ func normalizeScene(scene string) string {
|
||||
return scene
|
||||
}
|
||||
|
||||
func normalizeRecentGamesPageSize(pageSize int32) int32 {
|
||||
if pageSize <= 0 {
|
||||
return 4
|
||||
}
|
||||
if pageSize > 20 {
|
||||
return 20
|
||||
}
|
||||
return pageSize
|
||||
}
|
||||
|
||||
func buildLaunchURL(game gamedomain.LaunchableGame, session gamedomain.LaunchSession, token string) (string, error) {
|
||||
base := strings.TrimSpace(game.APIBaseURL)
|
||||
if strings.EqualFold(game.AdapterType, gamedomain.AdapterLeaderCCV1) && base == "" {
|
||||
@ -670,6 +756,7 @@ func buildLaunchURL(game gamedomain.LaunchableGame, session gamedomain.LaunchSes
|
||||
if session.RoomID != "" {
|
||||
query.Set("platRoomId", session.RoomID)
|
||||
}
|
||||
appendBridgeScriptQuery(query, game)
|
||||
parsed.RawQuery = query.Encode()
|
||||
return parsed.String(), nil
|
||||
}
|
||||
@ -686,6 +773,7 @@ func buildLaunchURL(game gamedomain.LaunchableGame, session gamedomain.LaunchSes
|
||||
if session.RoomID != "" {
|
||||
query.Set("roomid", session.RoomID)
|
||||
}
|
||||
appendBridgeScriptQuery(query, game)
|
||||
parsed.RawQuery = query.Encode()
|
||||
return parsed.String(), nil
|
||||
}
|
||||
@ -713,6 +801,7 @@ func buildLaunchURL(game gamedomain.LaunchableGame, session gamedomain.LaunchSes
|
||||
if config.Extra != "" {
|
||||
query.Set("extra", config.Extra)
|
||||
}
|
||||
appendBridgeScriptQuery(query, game)
|
||||
parsed.RawQuery = query.Encode()
|
||||
return parsed.String(), nil
|
||||
}
|
||||
@ -737,6 +826,7 @@ func buildLaunchURL(game gamedomain.LaunchableGame, session gamedomain.LaunchSes
|
||||
query.Set("currencyIcon", config.CurrencyIcon)
|
||||
}
|
||||
query.Set("gsp", strconv.FormatInt(config.GSP, 10))
|
||||
appendBridgeScriptQuery(query, game)
|
||||
parsed.RawQuery = query.Encode()
|
||||
return parsed.String(), nil
|
||||
}
|
||||
@ -760,6 +850,7 @@ func buildLaunchURL(game gamedomain.LaunchableGame, session gamedomain.LaunchSes
|
||||
query.Set("currencyIcon", config.CurrencyIcon)
|
||||
query.Set("gameConfig", vivaGamesGameConfigQuery(config.CurrencyIcon))
|
||||
}
|
||||
appendBridgeScriptQuery(query, game)
|
||||
parsed.RawQuery = query.Encode()
|
||||
return parsed.String(), nil
|
||||
}
|
||||
@ -773,6 +864,7 @@ func buildLaunchURL(game gamedomain.LaunchableGame, session gamedomain.LaunchSes
|
||||
query.Set("display_user_id", session.DisplayUserID)
|
||||
query.Set("scene", session.Scene)
|
||||
query.Set("room_id", session.RoomID)
|
||||
appendBridgeScriptQuery(query, game)
|
||||
parsed.RawQuery = query.Encode()
|
||||
return parsed.String(), nil
|
||||
}
|
||||
|
||||
@ -68,6 +68,66 @@ func TestLaunchGameCreatesSessionAndRejectsMaintenance(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRecentGamesNormalizesQueryAndDefaultsLimit(t *testing.T) {
|
||||
repo := &fakeRepository{
|
||||
recentGames: []gamedomain.AppGame{
|
||||
{GameID: "viva_2", Name: "Rich Forever"},
|
||||
},
|
||||
}
|
||||
svc := New(Config{LaunchSessionTTL: 15 * time.Minute}, repo, &fakeWallet{}, &fakeUser{})
|
||||
svc.now = func() time.Time { return time.UnixMilli(1700000000000) }
|
||||
|
||||
games, serverTimeMS, err := svc.ListRecentGames(context.Background(), ListRecentGamesQuery{
|
||||
UserID: 42,
|
||||
Scene: "",
|
||||
Language: " EN-US ",
|
||||
ClientPlatform: " Android ",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("ListRecentGames failed: %v", err)
|
||||
}
|
||||
if serverTimeMS != 1700000000000 || len(games) != 1 || games[0].GameID != "viva_2" {
|
||||
t.Fatalf("recent games response mismatch: time=%d games=%+v", serverTimeMS, games)
|
||||
}
|
||||
if repo.lastRecentQuery.AppCode != "lalu" || repo.lastRecentQuery.Scene != gamedomain.SceneVoiceRoom || repo.lastRecentQuery.PageSize != 4 || repo.lastRecentQuery.Language != "en-us" || repo.lastRecentQuery.ClientPlatform != "android" {
|
||||
t.Fatalf("recent query normalization mismatch: %+v", repo.lastRecentQuery)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBridgeScriptUsesFirstActivePlatformConfig(t *testing.T) {
|
||||
repo := &fakeRepository{
|
||||
platforms: []gamedomain.Platform{
|
||||
{
|
||||
AppCode: "lalu",
|
||||
PlatformCode: "vivagames",
|
||||
Status: gamedomain.StatusActive,
|
||||
SortOrder: 20,
|
||||
AdapterConfigJSON: `{"bridge_script_url":"https://cdn.example.test/bridge-viva.js","bridge_script_version":"20260608.2","bridge_script_sha256":"def"}`,
|
||||
},
|
||||
{
|
||||
AppCode: "lalu",
|
||||
PlatformCode: "baishun",
|
||||
Status: gamedomain.StatusActive,
|
||||
SortOrder: 10,
|
||||
AdapterConfigJSON: `{"bridgeScriptUrl":"https://cdn.example.test/bridge.js","bridgeScriptVersion":"20260608.1","bridgeScriptSha256":"abc"}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
svc := New(Config{LaunchSessionTTL: 15 * time.Minute}, repo, &fakeWallet{}, &fakeUser{})
|
||||
svc.now = func() time.Time { return time.UnixMilli(1700000000000) }
|
||||
|
||||
result, err := svc.GetBridgeScript(context.Background(), " LALU ")
|
||||
if err != nil {
|
||||
t.Fatalf("GetBridgeScript failed: %v", err)
|
||||
}
|
||||
if result.URL != "https://cdn.example.test/bridge.js" || result.Version != "20260608.1" || result.SHA256 != "abc" || result.ServerTimeMS != 1700000000000 {
|
||||
t.Fatalf("bridge script mismatch: %+v", result)
|
||||
}
|
||||
if repo.lastListPlatformsAppCode != "lalu" || repo.lastListPlatformsStatus != gamedomain.StatusActive {
|
||||
t.Fatalf("ListPlatforms query mismatch: app=%q status=%q", repo.lastListPlatformsAppCode, repo.lastListPlatformsStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLaunchGameBuildsYomiAuthURL(t *testing.T) {
|
||||
repo := &fakeRepository{
|
||||
launchable: gamedomain.LaunchableGame{
|
||||
@ -359,6 +419,9 @@ func TestLaunchGameBuildsVivaGamesURL(t *testing.T) {
|
||||
"bgm_switch":0,
|
||||
"gsp":101,
|
||||
"currency_icon":"https://cdn.example/coin.png",
|
||||
"bridge_script_url":"https://cdn.example/game-bridge/voice-room-game-bridge.v1.js",
|
||||
"bridge_script_version":"20260608.1",
|
||||
"bridge_script_sha256":"78f0d2d0b52d5711c1f2a9e8d3af8a9d3db7e03c83f5bd8d2b8e629f1f5b6c13",
|
||||
"game_urls":{"2":"https://dev-rich2.s3.ap-southeast-1.amazonaws.com/richForever.html?game_id=2&isShow=1"}
|
||||
}`,
|
||||
},
|
||||
@ -389,19 +452,25 @@ func TestLaunchGameBuildsVivaGamesURL(t *testing.T) {
|
||||
}
|
||||
query := parsed.Query()
|
||||
expected := map[string]string{
|
||||
"appId": "1012127974",
|
||||
"userId": "420001",
|
||||
"code": "app_access_token_viva",
|
||||
"gameId": "2",
|
||||
"metadata": `{"room_id":"room_1"}`,
|
||||
"language": "en-US",
|
||||
"coinType": "0",
|
||||
"amountRate": "1",
|
||||
"bgmSwitch": "0",
|
||||
"gsp": "101",
|
||||
"currencyIcon": "https://cdn.example/coin.png",
|
||||
"gameConfig": `{"currencyIcon":"https://cdn.example/coin.png"}`,
|
||||
"bridge_keys": "appId,userId,code,metadata,language,coinType,amountRate,bgmSwitch,gsp,currencyIcon,gameConfig,gameId",
|
||||
"appId": "1012127974",
|
||||
"userId": "420001",
|
||||
"code": "app_access_token_viva",
|
||||
"gameId": "2",
|
||||
"metadata": `{"room_id":"room_1"}`,
|
||||
"language": "en-US",
|
||||
"coinType": "0",
|
||||
"amountRate": "1",
|
||||
"bgmSwitch": "0",
|
||||
"gsp": "101",
|
||||
"currencyIcon": "https://cdn.example/coin.png",
|
||||
"gameConfig": `{"currencyIcon":"https://cdn.example/coin.png"}`,
|
||||
"bridge_keys": "appId,userId,code,metadata,language,coinType,amountRate,bgmSwitch,gsp,currencyIcon,gameConfig,gameId,bridge_script_url,bridge_script_version,bridge_script_sha256",
|
||||
"bridge_script_url": "https://cdn.example/game-bridge/voice-room-game-bridge.v1.js",
|
||||
"bridgeScriptUrl": "https://cdn.example/game-bridge/voice-room-game-bridge.v1.js",
|
||||
"bridge_script_version": "20260608.1",
|
||||
"bridgeScriptVersion": "20260608.1",
|
||||
"bridge_script_sha256": "78f0d2d0b52d5711c1f2a9e8d3af8a9d3db7e03c83f5bd8d2b8e629f1f5b6c13",
|
||||
"bridgeScriptSha256": "78f0d2d0b52d5711c1f2a9e8d3af8a9d3db7e03c83f5bd8d2b8e629f1f5b6c13",
|
||||
}
|
||||
for key, want := range expected {
|
||||
if got := query.Get(key); got != want {
|
||||
@ -1359,21 +1428,33 @@ func TestProcessLevelEventOutboxBatchRelaysGameSpend(t *testing.T) {
|
||||
}
|
||||
|
||||
type fakeRepository struct {
|
||||
launchable gamedomain.LaunchableGame
|
||||
platform gamedomain.Platform
|
||||
session gamedomain.LaunchSession
|
||||
order gamedomain.GameOrder
|
||||
orders []gamedomain.GameOrder
|
||||
repair gamedomain.RepairOrder
|
||||
levelEvents []gamedomain.LevelEventOutbox
|
||||
deliveredEvents []string
|
||||
failedEvents []string
|
||||
launchable gamedomain.LaunchableGame
|
||||
platform gamedomain.Platform
|
||||
session gamedomain.LaunchSession
|
||||
order gamedomain.GameOrder
|
||||
orders []gamedomain.GameOrder
|
||||
repair gamedomain.RepairOrder
|
||||
levelEvents []gamedomain.LevelEventOutbox
|
||||
recentGames []gamedomain.AppGame
|
||||
lastRecentQuery ListRecentGamesQuery
|
||||
platforms []gamedomain.Platform
|
||||
lastListPlatformsAppCode string
|
||||
lastListPlatformsStatus string
|
||||
deliveredEvents []string
|
||||
failedEvents []string
|
||||
}
|
||||
|
||||
func (f *fakeRepository) Ping(context.Context) error { return nil }
|
||||
func (f *fakeRepository) ListGames(context.Context, ListGamesQuery) ([]gamedomain.AppGame, error) {
|
||||
return []gamedomain.AppGame{{GameID: "demo_rocket_001"}}, nil
|
||||
}
|
||||
func (f *fakeRepository) ListRecentGames(_ context.Context, query ListRecentGamesQuery) ([]gamedomain.AppGame, error) {
|
||||
f.lastRecentQuery = query
|
||||
if f.recentGames != nil {
|
||||
return f.recentGames, nil
|
||||
}
|
||||
return []gamedomain.AppGame{{GameID: "demo_recent_001"}}, nil
|
||||
}
|
||||
func (f *fakeRepository) GetLaunchableGame(context.Context, string, string) (gamedomain.LaunchableGame, error) {
|
||||
return f.launchable, nil
|
||||
}
|
||||
@ -1472,7 +1553,12 @@ func (f *fakeRepository) MarkLevelEventFailed(_ context.Context, eventID string,
|
||||
f.failedEvents = append(f.failedEvents, eventID)
|
||||
return nil
|
||||
}
|
||||
func (f *fakeRepository) ListPlatforms(context.Context, string, string) ([]gamedomain.Platform, error) {
|
||||
func (f *fakeRepository) ListPlatforms(_ context.Context, appCode string, status string) ([]gamedomain.Platform, error) {
|
||||
f.lastListPlatformsAppCode = appCode
|
||||
f.lastListPlatformsStatus = status
|
||||
if f.platforms != nil {
|
||||
return f.platforms, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
func (f *fakeRepository) UpsertPlatform(context.Context, gamedomain.Platform) (gamedomain.Platform, error) {
|
||||
|
||||
@ -404,6 +404,67 @@ func (r *Repository) ListGames(ctx context.Context, query gameservice.ListGamesQ
|
||||
return items, rows.Err()
|
||||
}
|
||||
|
||||
func (r *Repository) ListRecentGames(ctx context.Context, query gameservice.ListRecentGamesQuery) ([]gamedomain.AppGame, error) {
|
||||
pageSize := int(query.PageSize)
|
||||
if pageSize <= 0 {
|
||||
pageSize = 4
|
||||
}
|
||||
// My Games 先按当前用户的启动会话聚合出每个游戏的最后一次启动时间,
|
||||
// 再套当前 catalog、platform 和 display_rules,保证最近玩过但已下架或当前区域不可见的游戏不会返回。
|
||||
rows, err := r.db.QueryContext(ctx,
|
||||
`SELECT c.game_id, c.platform_code, c.game_name, c.icon_url, c.cover_url, c.category,
|
||||
c.launch_mode, c.orientation, c.safe_height, c.min_coin, c.status, p.status,
|
||||
MIN(CASE WHEN r.sort_order = 0 THEN c.sort_order ELSE r.sort_order END) AS display_sort,
|
||||
recent.last_played_at_ms
|
||||
FROM (
|
||||
SELECT game_id, MAX(created_at_ms) AS last_played_at_ms
|
||||
FROM game_launch_sessions
|
||||
WHERE app_code = ?
|
||||
AND user_id = ?
|
||||
AND scene = ?
|
||||
GROUP BY game_id
|
||||
) recent
|
||||
JOIN game_catalog c ON c.app_code = ? AND c.game_id = recent.game_id
|
||||
JOIN game_platforms p ON p.app_code = c.app_code AND p.platform_code = c.platform_code
|
||||
JOIN game_display_rules r ON r.app_code = c.app_code AND r.game_id = c.game_id
|
||||
WHERE c.status IN ('active', 'maintenance')
|
||||
AND p.status IN ('active', 'maintenance')
|
||||
AND r.scene = ?
|
||||
AND r.enabled = 1
|
||||
AND r.visible = 1
|
||||
AND (r.region_id = 0 OR r.region_id = ?)
|
||||
AND (r.language = '' OR r.language = ?)
|
||||
AND (r.platform = '' OR r.platform = ?)
|
||||
GROUP BY c.game_id, c.platform_code, c.game_name, c.icon_url, c.cover_url, c.category,
|
||||
c.launch_mode, c.orientation, c.safe_height, c.min_coin, c.status, p.status,
|
||||
c.sort_order, p.sort_order, recent.last_played_at_ms
|
||||
ORDER BY recent.last_played_at_ms DESC, display_sort ASC, p.sort_order ASC, c.sort_order ASC, c.game_id ASC
|
||||
LIMIT ?`,
|
||||
appcode.Normalize(query.AppCode), query.UserID, query.Scene,
|
||||
appcode.Normalize(query.AppCode), query.Scene, query.RegionID, query.Language, query.ClientPlatform, pageSize,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []gamedomain.AppGame{}
|
||||
for rows.Next() {
|
||||
var item gamedomain.AppGame
|
||||
var gameStatus, platformStatus string
|
||||
var displaySort int32
|
||||
var lastPlayedAtMS int64
|
||||
if err := rows.Scan(&item.GameID, &item.PlatformCode, &item.Name, &item.IconURL, &item.CoverURL, &item.Category, &item.LaunchMode, &item.Orientation, &item.SafeHeight, &item.MinCoin, &gameStatus, &platformStatus, &displaySort, &lastPlayedAtMS); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item.NameKey = "game." + item.GameID + ".name"
|
||||
item.SortOrder = displaySort
|
||||
item.Enabled = gameStatus == gamedomain.StatusActive && platformStatus == gamedomain.StatusActive
|
||||
item.Maintenance = gameStatus == gamedomain.StatusMaintenance || platformStatus == gamedomain.StatusMaintenance
|
||||
items = append(items, item)
|
||||
}
|
||||
return items, rows.Err()
|
||||
}
|
||||
|
||||
func (r *Repository) GetLaunchableGame(ctx context.Context, appCode string, gameID string) (gamedomain.LaunchableGame, error) {
|
||||
// 启动游戏时一次性取出 catalog + platform 配置,避免拿到游戏后再查平台导致配置不一致。
|
||||
row := r.db.QueryRowContext(ctx,
|
||||
|
||||
@ -47,6 +47,44 @@ func (s *Server) ListGames(ctx context.Context, req *gamev1.ListGamesRequest) (*
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListRecentGames(ctx context.Context, req *gamev1.ListRecentGamesRequest) (*gamev1.ListGamesResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
items, serverTimeMS, err := s.svc.ListRecentGames(ctx, gameservice.ListRecentGamesQuery{
|
||||
AppCode: req.GetMeta().GetAppCode(),
|
||||
UserID: req.GetUserId(),
|
||||
Scene: req.GetScene(),
|
||||
RoomID: req.GetRoomId(),
|
||||
RegionID: req.GetRegionId(),
|
||||
Language: req.GetLanguage(),
|
||||
ClientPlatform: req.GetClientPlatform(),
|
||||
PageSize: req.GetPageSize(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
resp := &gamev1.ListGamesResponse{ServerTimeMs: serverTimeMS, Games: make([]*gamev1.AppGame, 0, len(items))}
|
||||
for _, item := range items {
|
||||
resp.Games = append(resp.Games, appGameToProto(item))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetBridgeScript(ctx context.Context, req *gamev1.GetBridgeScriptRequest) (*gamev1.GetBridgeScriptResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
result, err := s.svc.GetBridgeScript(ctx, req.GetMeta().GetAppCode())
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &gamev1.GetBridgeScriptResponse{
|
||||
Config: &gamev1.GameBridgeScriptConfig{
|
||||
BridgeScriptUrl: result.URL,
|
||||
BridgeScriptVersion: result.Version,
|
||||
BridgeScriptSha256: result.SHA256,
|
||||
},
|
||||
ServerTimeMs: result.ServerTimeMS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) LaunchGame(ctx context.Context, req *gamev1.LaunchGameRequest) (*gamev1.LaunchGameResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
result, err := s.svc.LaunchGame(ctx, gameservice.LaunchCommand{
|
||||
@ -195,6 +233,9 @@ func (unavailableRepository) Ping(context.Context) error {
|
||||
func (unavailableRepository) ListGames(context.Context, gameservice.ListGamesQuery) ([]gamedomain.AppGame, error) {
|
||||
return nil, xerr.New(xerr.Unavailable, "game repository is not configured")
|
||||
}
|
||||
func (unavailableRepository) ListRecentGames(context.Context, gameservice.ListRecentGamesQuery) ([]gamedomain.AppGame, error) {
|
||||
return nil, xerr.New(xerr.Unavailable, "game repository is not configured")
|
||||
}
|
||||
func (unavailableRepository) GetLaunchableGame(context.Context, string, string) (gamedomain.LaunchableGame, error) {
|
||||
return gamedomain.LaunchableGame{}, xerr.New(xerr.Unavailable, "game repository is not configured")
|
||||
}
|
||||
|
||||
@ -89,6 +89,7 @@ func New(cfg config.Config) (*App, error) {
|
||||
var userProfileClient client.UserProfileClient = client.NewGRPCUserProfileClient(userConn)
|
||||
var userDeviceClient client.UserDeviceClient = client.NewGRPCUserDeviceClient(userConn)
|
||||
var userCountryQueryClient client.UserCountryQueryClient = client.NewGRPCUserCountryQueryClient(userConn)
|
||||
var userRegionClient client.UserRegionClient = client.NewGRPCUserRegionClient(userConn)
|
||||
var userHostClient client.UserHostClient = client.NewGRPCUserHostClient(userConn)
|
||||
var userSocialClient client.UserSocialClient = client.NewGRPCUserSocialClient(userConn)
|
||||
var userCPClient client.UserCPClient = client.NewGRPCUserCPClient(userConn)
|
||||
@ -157,6 +158,7 @@ func New(cfg config.Config) (*App, error) {
|
||||
handler.SetRoomQueryClient(roomQueryClient)
|
||||
handler.SetUserDeviceClient(userDeviceClient)
|
||||
handler.SetUserCountryQueryClient(userCountryQueryClient)
|
||||
handler.SetUserRegionClient(userRegionClient)
|
||||
handler.SetUserHostClient(userHostClient)
|
||||
handler.SetUserSocialClient(userSocialClient)
|
||||
handler.SetUserCPClient(userCPClient)
|
||||
|
||||
@ -10,6 +10,8 @@ import (
|
||||
// GameClient 抽象 gateway 对 game-service App 与回调 RPC 的依赖。
|
||||
type GameClient interface {
|
||||
ListGames(ctx context.Context, req *gamev1.ListGamesRequest) (*gamev1.ListGamesResponse, error)
|
||||
ListRecentGames(ctx context.Context, req *gamev1.ListRecentGamesRequest) (*gamev1.ListGamesResponse, error)
|
||||
GetBridgeScript(ctx context.Context, req *gamev1.GetBridgeScriptRequest) (*gamev1.GetBridgeScriptResponse, error)
|
||||
LaunchGame(ctx context.Context, req *gamev1.LaunchGameRequest) (*gamev1.LaunchGameResponse, error)
|
||||
HandleCallback(ctx context.Context, req *gamev1.CallbackRequest) (*gamev1.CallbackResponse, error)
|
||||
}
|
||||
@ -30,6 +32,14 @@ func (c *grpcGameClient) ListGames(ctx context.Context, req *gamev1.ListGamesReq
|
||||
return c.app.ListGames(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcGameClient) ListRecentGames(ctx context.Context, req *gamev1.ListRecentGamesRequest) (*gamev1.ListGamesResponse, error) {
|
||||
return c.app.ListRecentGames(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcGameClient) GetBridgeScript(ctx context.Context, req *gamev1.GetBridgeScriptRequest) (*gamev1.GetBridgeScriptResponse, error) {
|
||||
return c.app.GetBridgeScript(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcGameClient) LaunchGame(ctx context.Context, req *gamev1.LaunchGameRequest) (*gamev1.LaunchGameResponse, error) {
|
||||
return c.app.LaunchGame(ctx, req)
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ type GrowthLevelClient interface {
|
||||
GetLevelTrack(ctx context.Context, req *activityv1.GetLevelTrackRequest) (*activityv1.GetLevelTrackResponse, error)
|
||||
BatchGetUserLevelDisplayProfiles(ctx context.Context, req *activityv1.BatchGetUserLevelDisplayProfilesRequest) (*activityv1.BatchGetUserLevelDisplayProfilesResponse, error)
|
||||
ListLevelRewards(ctx context.Context, req *activityv1.ListLevelRewardsRequest) (*activityv1.ListLevelRewardsResponse, error)
|
||||
SetUserLevel(ctx context.Context, req *activityv1.SetUserLevelRequest) (*activityv1.SetUserLevelResponse, error)
|
||||
}
|
||||
|
||||
type grpcGrowthLevelClient struct {
|
||||
@ -38,3 +39,7 @@ func (c *grpcGrowthLevelClient) BatchGetUserLevelDisplayProfiles(ctx context.Con
|
||||
func (c *grpcGrowthLevelClient) ListLevelRewards(ctx context.Context, req *activityv1.ListLevelRewardsRequest) (*activityv1.ListLevelRewardsResponse, error) {
|
||||
return c.client.ListLevelRewards(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcGrowthLevelClient) SetUserLevel(ctx context.Context, req *activityv1.SetUserLevelRequest) (*activityv1.SetUserLevelResponse, error) {
|
||||
return c.client.SetUserLevel(ctx, req)
|
||||
}
|
||||
|
||||
@ -37,6 +37,9 @@ type UserProfileClient interface {
|
||||
CompleteOnboarding(ctx context.Context, req *userv1.CompleteOnboardingRequest) (*userv1.CompleteOnboardingResponse, error)
|
||||
UpdateUserProfile(ctx context.Context, req *userv1.UpdateUserProfileRequest) (*userv1.UpdateUserProfileResponse, error)
|
||||
ChangeUserCountry(ctx context.Context, req *userv1.ChangeUserCountryRequest) (*userv1.ChangeUserCountryResponse, error)
|
||||
CreateManagerUserBlock(ctx context.Context, req *userv1.CreateManagerUserBlockRequest) (*userv1.CreateManagerUserBlockResponse, error)
|
||||
ListManagerUserBlocks(ctx context.Context, req *userv1.ListManagerUserBlocksRequest) (*userv1.ListManagerUserBlocksResponse, error)
|
||||
UnblockManagerUser(ctx context.Context, req *userv1.UnblockManagerUserRequest) (*userv1.UnblockManagerUserResponse, error)
|
||||
}
|
||||
|
||||
// UserSocialClient 抽象 gateway 对 user-service 访问、关注和好友关系能力的依赖。
|
||||
@ -74,6 +77,11 @@ type UserCountryQueryClient interface {
|
||||
ListLoginRiskBlockedCountries(ctx context.Context, req *userv1.ListLoginRiskBlockedCountriesRequest) (*userv1.ListLoginRiskBlockedCountriesResponse, error)
|
||||
}
|
||||
|
||||
// UserRegionClient 抽象 gateway 对 user-service 区域国家归属查询的依赖。
|
||||
type UserRegionClient interface {
|
||||
GetRegion(ctx context.Context, req *userv1.GetRegionRequest) (*userv1.RegionResponse, error)
|
||||
}
|
||||
|
||||
// UserHostClient 抽象 gateway 对 user-service host domain 身份查询能力的依赖。
|
||||
type UserHostClient interface {
|
||||
SearchAgencies(ctx context.Context, req *userv1.SearchAgenciesRequest) (*userv1.SearchAgenciesResponse, error)
|
||||
@ -129,6 +137,10 @@ type grpcUserCountryQueryClient struct {
|
||||
client userv1.CountryQueryServiceClient
|
||||
}
|
||||
|
||||
type grpcUserRegionClient struct {
|
||||
client userv1.RegionAdminServiceClient
|
||||
}
|
||||
|
||||
type grpcUserHostClient struct {
|
||||
client userv1.UserHostServiceClient
|
||||
}
|
||||
@ -186,6 +198,13 @@ func NewGRPCUserCountryQueryClient(conn *grpc.ClientConn) UserCountryQueryClient
|
||||
}
|
||||
}
|
||||
|
||||
// NewGRPCUserRegionClient 用 gRPC 连接构造 user-service 区域查询 client。
|
||||
func NewGRPCUserRegionClient(conn *grpc.ClientConn) UserRegionClient {
|
||||
return &grpcUserRegionClient{
|
||||
client: userv1.NewRegionAdminServiceClient(conn),
|
||||
}
|
||||
}
|
||||
|
||||
// NewGRPCUserHostClient 用 gRPC 连接构造 user-service host domain client。
|
||||
func NewGRPCUserHostClient(conn *grpc.ClientConn) UserHostClient {
|
||||
return &grpcUserHostClient{
|
||||
@ -276,6 +295,18 @@ func (c *grpcUserProfileClient) ChangeUserCountry(ctx context.Context, req *user
|
||||
return c.client.ChangeUserCountry(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserProfileClient) CreateManagerUserBlock(ctx context.Context, req *userv1.CreateManagerUserBlockRequest) (*userv1.CreateManagerUserBlockResponse, error) {
|
||||
return c.client.CreateManagerUserBlock(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserProfileClient) ListManagerUserBlocks(ctx context.Context, req *userv1.ListManagerUserBlocksRequest) (*userv1.ListManagerUserBlocksResponse, error) {
|
||||
return c.client.ListManagerUserBlocks(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserProfileClient) UnblockManagerUser(ctx context.Context, req *userv1.UnblockManagerUserRequest) (*userv1.UnblockManagerUserResponse, error) {
|
||||
return c.client.UnblockManagerUser(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserSocialClient) RecordProfileVisit(ctx context.Context, req *userv1.RecordProfileVisitRequest) (*userv1.RecordProfileVisitResponse, error) {
|
||||
return c.client.RecordProfileVisit(ctx, req)
|
||||
}
|
||||
@ -352,6 +383,10 @@ func (c *grpcUserCountryQueryClient) ListLoginRiskBlockedCountries(ctx context.C
|
||||
return c.client.ListLoginRiskBlockedCountries(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserRegionClient) GetRegion(ctx context.Context, req *userv1.GetRegionRequest) (*userv1.RegionResponse, error) {
|
||||
return c.client.GetRegion(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcUserHostClient) SearchAgencies(ctx context.Context, req *userv1.SearchAgenciesRequest) (*userv1.SearchAgenciesResponse, error) {
|
||||
return c.client.SearchAgencies(ctx, req)
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ type WalletClient interface {
|
||||
ListVipPackages(ctx context.Context, req *walletv1.ListVipPackagesRequest) (*walletv1.ListVipPackagesResponse, error)
|
||||
GetMyVip(ctx context.Context, req *walletv1.GetMyVipRequest) (*walletv1.GetMyVipResponse, error)
|
||||
PurchaseVip(ctx context.Context, req *walletv1.PurchaseVipRequest) (*walletv1.PurchaseVipResponse, error)
|
||||
GrantVip(ctx context.Context, req *walletv1.GrantVipRequest) (*walletv1.GrantVipResponse, error)
|
||||
TransferCoinFromSeller(ctx context.Context, req *walletv1.TransferCoinFromSellerRequest) (*walletv1.TransferCoinFromSellerResponse, error)
|
||||
ListCoinSellerSalaryExchangeRateTiers(ctx context.Context, req *walletv1.ListCoinSellerSalaryExchangeRateTiersRequest) (*walletv1.ListCoinSellerSalaryExchangeRateTiersResponse, error)
|
||||
ExchangeSalaryToCoin(ctx context.Context, req *walletv1.ExchangeSalaryToCoinRequest) (*walletv1.ExchangeSalaryToCoinResponse, error)
|
||||
@ -107,6 +108,10 @@ func (c *grpcWalletClient) PurchaseVip(ctx context.Context, req *walletv1.Purcha
|
||||
return c.client.PurchaseVip(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) GrantVip(ctx context.Context, req *walletv1.GrantVipRequest) (*walletv1.GrantVipResponse, error) {
|
||||
return c.client.GrantVip(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) TransferCoinFromSeller(ctx context.Context, req *walletv1.TransferCoinFromSellerRequest) (*walletv1.TransferCoinFromSellerResponse, error) {
|
||||
return c.client.TransferCoinFromSeller(ctx, req)
|
||||
}
|
||||
|
||||
@ -54,6 +54,81 @@ func TestListGamesUsesAuthenticatedUserRegionAndReturnsEnvelope(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRecentGamesUsesAuthenticatedUserRegionAndLimit(t *testing.T) {
|
||||
gameClient := &fakeGatewayGameClient{recentResp: &gamev1.ListGamesResponse{
|
||||
Games: []*gamev1.AppGame{{
|
||||
GameId: "viva_2",
|
||||
PlatformCode: "vivagames",
|
||||
Name: "Rich Forever",
|
||||
LaunchMode: "h5_popup",
|
||||
Orientation: "portrait",
|
||||
Enabled: true,
|
||||
}},
|
||||
ServerTimeMs: 1700000000000,
|
||||
}}
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{regionID: 1001})
|
||||
handler.SetGameClient(gameClient)
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/games/recent?scene=voice_room&room_id=room-1&limit=4", nil)
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-App-Language", "en")
|
||||
request.Header.Set("X-App-Platform", "android")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if gameClient.lastRecent.GetUserId() != 42 || gameClient.lastRecent.GetRegionId() != 1001 || gameClient.lastRecent.GetScene() != "voice_room" || gameClient.lastRecent.GetRoomId() != "room-1" || gameClient.lastRecent.GetPageSize() != 4 || gameClient.lastRecent.GetClientPlatform() != "android" {
|
||||
t.Fatalf("ListRecentGames request mismatch: %+v", gameClient.lastRecent)
|
||||
}
|
||||
var envelope httpkit.ResponseEnvelope
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&envelope); err != nil {
|
||||
t.Fatalf("decode response failed: %v", err)
|
||||
}
|
||||
data := envelope.Data.(map[string]any)
|
||||
games := data["games"].([]any)
|
||||
first := games[0].(map[string]any)
|
||||
if first["platform_code"] != "vivagames" || first["game_id"] != "viva_2" {
|
||||
t.Fatalf("recent game response mismatch: %+v", first)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBridgeScriptReturnsUniversalScriptConfig(t *testing.T) {
|
||||
gameClient := &fakeGatewayGameClient{bridgeResp: &gamev1.GetBridgeScriptResponse{
|
||||
Config: &gamev1.GameBridgeScriptConfig{
|
||||
BridgeScriptUrl: "https://cdn.example.test/game-bridge.js",
|
||||
BridgeScriptVersion: "20260608.1",
|
||||
BridgeScriptSha256: "abc",
|
||||
},
|
||||
ServerTimeMs: 1700000000000,
|
||||
}}
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{regionID: 1001})
|
||||
handler.SetGameClient(gameClient)
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/games/bridge-script", nil)
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
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 gameClient.lastBridge.GetMeta().GetActorUserId() != 42 {
|
||||
t.Fatalf("GetBridgeScript request mismatch: %+v", gameClient.lastBridge)
|
||||
}
|
||||
var envelope httpkit.ResponseEnvelope
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&envelope); err != nil {
|
||||
t.Fatalf("decode response failed: %v", err)
|
||||
}
|
||||
data := envelope.Data.(map[string]any)
|
||||
if data["bridge_script_url"] != "https://cdn.example.test/game-bridge.js" || data["bridgeScriptUrl"] != "https://cdn.example.test/game-bridge.js" || data["bridge_script_version"] != "20260608.1" || data["bridge_script_sha256"] != "abc" {
|
||||
t.Fatalf("bridge script response mismatch: %+v", data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLaunchGameForwardsDisplayUserID(t *testing.T) {
|
||||
gameClient := &fakeGatewayGameClient{launchResp: &gamev1.LaunchGameResponse{
|
||||
SessionId: "game_sess_1",
|
||||
@ -100,9 +175,13 @@ func TestGameCallbackIsRawPublicResponse(t *testing.T) {
|
||||
|
||||
type fakeGatewayGameClient struct {
|
||||
listResp *gamev1.ListGamesResponse
|
||||
recentResp *gamev1.ListGamesResponse
|
||||
bridgeResp *gamev1.GetBridgeScriptResponse
|
||||
launchResp *gamev1.LaunchGameResponse
|
||||
callbackResp *gamev1.CallbackResponse
|
||||
lastList *gamev1.ListGamesRequest
|
||||
lastRecent *gamev1.ListRecentGamesRequest
|
||||
lastBridge *gamev1.GetBridgeScriptRequest
|
||||
lastLaunch *gamev1.LaunchGameRequest
|
||||
lastCallback *gamev1.CallbackRequest
|
||||
}
|
||||
@ -115,6 +194,22 @@ func (f *fakeGatewayGameClient) ListGames(_ context.Context, req *gamev1.ListGam
|
||||
return &gamev1.ListGamesResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeGatewayGameClient) ListRecentGames(_ context.Context, req *gamev1.ListRecentGamesRequest) (*gamev1.ListGamesResponse, error) {
|
||||
f.lastRecent = req
|
||||
if f.recentResp != nil {
|
||||
return f.recentResp, nil
|
||||
}
|
||||
return &gamev1.ListGamesResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeGatewayGameClient) GetBridgeScript(_ context.Context, req *gamev1.GetBridgeScriptRequest) (*gamev1.GetBridgeScriptResponse, error) {
|
||||
f.lastBridge = req
|
||||
if f.bridgeResp != nil {
|
||||
return f.bridgeResp, nil
|
||||
}
|
||||
return &gamev1.GetBridgeScriptResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeGatewayGameClient) LaunchGame(_ context.Context, req *gamev1.LaunchGameRequest) (*gamev1.LaunchGameResponse, error) {
|
||||
f.lastLaunch = req
|
||||
if f.launchResp != nil {
|
||||
|
||||
@ -40,6 +40,52 @@ func (h *Handler) listGames(writer http.ResponseWriter, request *http.Request) {
|
||||
httpkit.Write(writer, request, gameListDataFromProto(resp), err)
|
||||
}
|
||||
|
||||
func (h *Handler) listRecentGames(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.gameClient == nil || h.userProfileClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
pageSize, ok := recentGamePageSize(request)
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
userID := auth.UserIDFromContext(request.Context())
|
||||
userResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
UserId: userID,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
// 最近常玩仍传 scene、room、region、language 和 platform,让 game-service 在真实启动记录之外,
|
||||
// 继续按当前房间场景和用户区域过滤,避免 App 展示用户已不能进入的游戏。
|
||||
resp, err := h.gameClient.ListRecentGames(request.Context(), &gamev1.ListRecentGamesRequest{
|
||||
Meta: gameMeta(request),
|
||||
UserId: userID,
|
||||
Scene: strings.TrimSpace(request.URL.Query().Get("scene")),
|
||||
RoomId: strings.TrimSpace(request.URL.Query().Get("room_id")),
|
||||
RegionId: userResp.GetUser().GetRegionId(),
|
||||
Language: requestLanguage(request),
|
||||
ClientPlatform: httpkit.FirstHeader(request, "X-App-Platform", "X-Platform"),
|
||||
PageSize: pageSize,
|
||||
})
|
||||
httpkit.Write(writer, request, gameListDataFromProto(resp), err)
|
||||
}
|
||||
|
||||
func (h *Handler) getBridgeScript(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.gameClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
// 桥接脚本配置是 App 级启动预热信息,不依赖房间和用户区域;保持接口轻量,避免拖慢进 App 主流程。
|
||||
resp, err := h.gameClient.GetBridgeScript(request.Context(), &gamev1.GetBridgeScriptRequest{
|
||||
Meta: gameMeta(request),
|
||||
})
|
||||
httpkit.Write(writer, request, gameBridgeScriptDataFromProto(resp), err)
|
||||
}
|
||||
|
||||
func (h *Handler) launchGame(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.gameClient == nil || h.userProfileClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
@ -133,6 +179,13 @@ func requestLanguage(request *http.Request) string {
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
|
||||
func recentGamePageSize(request *http.Request) (int32, bool) {
|
||||
if strings.TrimSpace(request.URL.Query().Get("limit")) != "" {
|
||||
return httpkit.PositiveInt32Query(request, "limit", 4)
|
||||
}
|
||||
return httpkit.PositiveInt32Query(request, "page_size", 4)
|
||||
}
|
||||
|
||||
func bearerAccessToken(request *http.Request) string {
|
||||
header := strings.TrimSpace(request.Header.Get("Authorization"))
|
||||
if !strings.HasPrefix(header, "Bearer ") {
|
||||
|
||||
@ -35,6 +35,16 @@ type gameLaunchData struct {
|
||||
ServerTimeMS int64 `json:"server_time_ms"`
|
||||
}
|
||||
|
||||
type gameBridgeScriptData struct {
|
||||
BridgeScriptURL string `json:"bridge_script_url"`
|
||||
BridgeScriptURLV2 string `json:"bridgeScriptUrl"`
|
||||
BridgeScriptVersion string `json:"bridge_script_version"`
|
||||
BridgeScriptVersionV2 string `json:"bridgeScriptVersion"`
|
||||
BridgeScriptSHA256 string `json:"bridge_script_sha256"`
|
||||
BridgeScriptSHA256V2 string `json:"bridgeScriptSha256"`
|
||||
ServerTimeMS int64 `json:"server_time_ms"`
|
||||
}
|
||||
|
||||
func gameListDataFromProto(resp *gamev1.ListGamesResponse) gameListData {
|
||||
if resp == nil {
|
||||
return gameListData{}
|
||||
@ -76,3 +86,19 @@ func gameLaunchDataFromProto(resp *gamev1.LaunchGameResponse) gameLaunchData {
|
||||
ServerTimeMS: resp.GetServerTimeMs(),
|
||||
}
|
||||
}
|
||||
|
||||
func gameBridgeScriptDataFromProto(resp *gamev1.GetBridgeScriptResponse) gameBridgeScriptData {
|
||||
if resp == nil {
|
||||
return gameBridgeScriptData{}
|
||||
}
|
||||
config := resp.GetConfig()
|
||||
return gameBridgeScriptData{
|
||||
BridgeScriptURL: config.GetBridgeScriptUrl(),
|
||||
BridgeScriptURLV2: config.GetBridgeScriptUrl(),
|
||||
BridgeScriptVersion: config.GetBridgeScriptVersion(),
|
||||
BridgeScriptVersionV2: config.GetBridgeScriptVersion(),
|
||||
BridgeScriptSHA256: config.GetBridgeScriptSha256(),
|
||||
BridgeScriptSHA256V2: config.GetBridgeScriptSha256(),
|
||||
ServerTimeMS: resp.GetServerTimeMs(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,9 +28,11 @@ func New(config Config) *Handler {
|
||||
|
||||
func (h *Handler) Handlers() httproutes.GameHandlers {
|
||||
return httproutes.GameHandlers{
|
||||
ListGames: h.listGames,
|
||||
LaunchGame: h.launchGame,
|
||||
HandleCallback: h.handleGameCallback,
|
||||
ListGames: h.listGames,
|
||||
ListRecentGames: h.listRecentGames,
|
||||
GetBridgeScript: h.getBridgeScript,
|
||||
LaunchGame: h.launchGame,
|
||||
HandleCallback: h.handleGameCallback,
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +40,14 @@ func (h *Handler) ListGames(writer http.ResponseWriter, request *http.Request) {
|
||||
h.listGames(writer, request)
|
||||
}
|
||||
|
||||
func (h *Handler) ListRecentGames(writer http.ResponseWriter, request *http.Request) {
|
||||
h.listRecentGames(writer, request)
|
||||
}
|
||||
|
||||
func (h *Handler) GetBridgeScript(writer http.ResponseWriter, request *http.Request) {
|
||||
h.getBridgeScript(writer, request)
|
||||
}
|
||||
|
||||
func (h *Handler) LaunchGame(writer http.ResponseWriter, request *http.Request) {
|
||||
h.launchGame(writer, request)
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ type Handler struct {
|
||||
userCPClient client.UserCPClient
|
||||
userDeviceClient client.UserDeviceClient
|
||||
userCountryClient client.UserCountryQueryClient
|
||||
userRegionClient client.UserRegionClient
|
||||
userHostClient client.UserHostClient
|
||||
appRegistryClient client.AppRegistryClient
|
||||
walletClient client.WalletClient
|
||||
@ -161,6 +162,11 @@ func (h *Handler) SetUserCountryQueryClient(userCountryClient client.UserCountry
|
||||
h.userCountryClient = userCountryClient
|
||||
}
|
||||
|
||||
// SetUserRegionClient 注入 user-service 区域国家归属查询 client。
|
||||
func (h *Handler) SetUserRegionClient(userRegionClient client.UserRegionClient) {
|
||||
h.userRegionClient = userRegionClient
|
||||
}
|
||||
|
||||
// SetUserDeviceClient 注入 user-service 设备推送 token client。
|
||||
func (h *Handler) SetUserDeviceClient(userDeviceClient client.UserDeviceClient) {
|
||||
h.userDeviceClient = userDeviceClient
|
||||
|
||||
@ -116,6 +116,14 @@ type ManagerHandlers struct {
|
||||
ListManagerGrantResources http.HandlerFunc
|
||||
GrantManagerResource http.HandlerFunc
|
||||
LookupBusinessUsers http.HandlerFunc
|
||||
GetManagerOverview http.HandlerFunc
|
||||
SearchManagerUsers http.HandlerFunc
|
||||
GrantManagerVIP http.HandlerFunc
|
||||
ManagerBlocks http.HandlerFunc
|
||||
ListManagerBlocks http.HandlerFunc
|
||||
CreateManagerBlock http.HandlerFunc
|
||||
UnblockManagerBlock http.HandlerFunc
|
||||
SetManagerUserLevel http.HandlerFunc
|
||||
}
|
||||
|
||||
type RoomHandlers struct {
|
||||
@ -227,9 +235,11 @@ type VIPHandlers struct {
|
||||
}
|
||||
|
||||
type GameHandlers struct {
|
||||
ListGames http.HandlerFunc
|
||||
LaunchGame http.HandlerFunc
|
||||
HandleCallback http.HandlerFunc
|
||||
ListGames http.HandlerFunc
|
||||
ListRecentGames http.HandlerFunc
|
||||
GetBridgeScript http.HandlerFunc
|
||||
LaunchGame http.HandlerFunc
|
||||
HandleCallback http.HandlerFunc
|
||||
}
|
||||
|
||||
type routes struct {
|
||||
@ -368,8 +378,14 @@ func (r routes) registerUserRoutes() {
|
||||
|
||||
func (r routes) registerManagerRoutes() {
|
||||
h := r.config.Manager
|
||||
r.profile("/manager-center/overview", http.MethodGet, h.GetManagerOverview)
|
||||
r.profile("/manager-center/users/search", http.MethodGet, h.SearchManagerUsers)
|
||||
r.profile("/manager-center/resource-grants/resources", http.MethodGet, h.ListManagerGrantResources)
|
||||
r.profile("/manager-center/resource-grants", http.MethodPost, h.GrantManagerResource)
|
||||
r.profile("/manager-center/vip-grants", http.MethodPost, h.GrantManagerVIP)
|
||||
r.profile("/manager-center/blocks", "", h.ManagerBlocks)
|
||||
r.profile("/manager-center/blocks/{block_id}/unblock", http.MethodPost, h.UnblockManagerBlock)
|
||||
r.profile("/manager-center/levels", http.MethodPost, h.SetManagerUserLevel)
|
||||
r.profile("/business/users/lookup", http.MethodGet, h.LookupBusinessUsers)
|
||||
}
|
||||
|
||||
@ -493,6 +509,8 @@ func (r routes) registerVIPRoutes() {
|
||||
func (r routes) registerGameRoutes() {
|
||||
h := r.config.Game
|
||||
r.profile("/games", http.MethodGet, h.ListGames)
|
||||
r.profile("/games/recent", http.MethodGet, h.ListRecentGames)
|
||||
r.profile("/games/bridge-script", http.MethodGet, h.GetBridgeScript)
|
||||
r.profile("/games/{game_id}/launch", http.MethodPost, h.LaunchGame)
|
||||
r.public("/game-callbacks/{platform_code}/{operation}", http.MethodPost, h.HandleCallback)
|
||||
}
|
||||
|
||||
@ -2,12 +2,14 @@ package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"hyapp/services/gateway-service/internal/transport/http/httpkit"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
userv1 "hyapp.local/api/proto/user/v1"
|
||||
walletv1 "hyapp.local/api/proto/wallet/v1"
|
||||
"hyapp/services/gateway-service/internal/auth"
|
||||
@ -20,6 +22,14 @@ func newManagerCenterTestRouter(walletClient *fakeWalletClient, hostClient *fake
|
||||
return handler.Routes(auth.NewVerifier("secret"))
|
||||
}
|
||||
|
||||
func newManagerCenterTestRouterWithGrowth(walletClient *fakeWalletClient, hostClient *fakeUserHostClient, profileClient *fakeUserProfileClient, growthClient *fakeGrowthLevelClient) http.Handler {
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, profileClient)
|
||||
handler.SetWalletClient(walletClient)
|
||||
handler.SetUserHostClient(hostClient)
|
||||
handler.SetGrowthLevelClient(growthClient)
|
||||
return handler.Routes(auth.NewVerifier("secret"))
|
||||
}
|
||||
|
||||
func TestListManagerGrantResourcesChecksCapabilityAndFiltersWalletRequest(t *testing.T) {
|
||||
walletClient := &fakeWalletClient{
|
||||
listResourcesResp: &walletv1.ListResourcesResponse{
|
||||
@ -164,24 +174,190 @@ func TestGrantManagerResourceUsesServerControlledGrantShape(t *testing.T) {
|
||||
if profileClient.lastGet == nil || profileClient.lastGet.GetUserId() != 900001 {
|
||||
t.Fatalf("target user lookup mismatch: %+v", profileClient.lastGet)
|
||||
}
|
||||
if req := walletClient.lastGrantResource; req == nil || req.GetCommandId() != "mgr-grant-1" || req.GetTargetUserId() != 900001 || req.GetResourceId() != 101 || req.GetQuantity() != 1 || req.GetDurationMs() != 0 || req.GetOperatorUserId() != 42 || req.GetGrantSource() != "manager_center" || req.GetReason() != "manager_center" {
|
||||
if req := walletClient.lastGrantResource; req == nil || req.GetCommandId() != "mgr-grant-1" || req.GetTargetUserId() != 900001 || req.GetResourceId() != 101 || req.GetQuantity() != 1 || req.GetDurationMs() != 604800000 || req.GetOperatorUserId() != 42 || req.GetGrantSource() != "manager_center" || req.GetReason() != "manager_center" {
|
||||
t.Fatalf("wallet GrantResource request mismatch: %+v", req)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantManagerResourceRejectsClientComputedQuantityOrDuration(t *testing.T) {
|
||||
func TestGrantManagerResourceAllowsConfiguredDuration(t *testing.T) {
|
||||
walletClient := &fakeWalletClient{}
|
||||
router := newManagerCenterTestRouter(walletClient, &fakeUserHostClient{}, &fakeUserProfileClient{})
|
||||
body := []byte(`{"command_id":"mgr-grant-1","target_user_id":"900001","resource_id":"101","quantity":9}`)
|
||||
body := []byte(`{"command_id":"mgr-grant-30","target_user_id":"900001","resource_id":"101","duration_ms":2592000000}`)
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/manager-center/resource-grants", bytes.NewReader(body))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-manager-grant-shape")
|
||||
request.Header.Set("X-Request-ID", "req-manager-grant-duration")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
assertEnvelope(t, recorder, http.StatusBadRequest, httpkit.CodeInvalidArgument, "req-manager-grant-shape")
|
||||
if walletClient.lastGrantResource != nil {
|
||||
t.Fatalf("client computed grant shape must not reach wallet-service: %+v", walletClient.lastGrantResource)
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if req := walletClient.lastGrantResource; req == nil || req.GetDurationMs() != 2592000000 {
|
||||
t.Fatalf("manager grant duration was not forwarded: %+v", req)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantManagerResourceRejectsClientComputedQuantityOrInvalidDuration(t *testing.T) {
|
||||
walletClient := &fakeWalletClient{}
|
||||
router := newManagerCenterTestRouter(walletClient, &fakeUserHostClient{}, &fakeUserProfileClient{})
|
||||
cases := []struct {
|
||||
name string
|
||||
body string
|
||||
}{
|
||||
{name: "quantity", body: `{"command_id":"mgr-grant-1","target_user_id":"900001","resource_id":"101","quantity":9}`},
|
||||
{name: "duration", body: `{"command_id":"mgr-grant-1","target_user_id":"900001","resource_id":"101","duration_ms":86400000}`},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
walletClient.lastGrantResource = nil
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/manager-center/resource-grants", bytes.NewReader([]byte(tc.body)))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-manager-grant-shape")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
assertEnvelope(t, recorder, http.StatusBadRequest, httpkit.CodeInvalidArgument, "req-manager-grant-shape")
|
||||
if walletClient.lastGrantResource != nil {
|
||||
t.Fatalf("client computed grant shape must not reach wallet-service: %+v", walletClient.lastGrantResource)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantManagerResourceRejectsCrossCountryTarget(t *testing.T) {
|
||||
walletClient := &fakeWalletClient{}
|
||||
profileClient := &fakeUserProfileClient{
|
||||
usersByID: map[int64]*userv1.User{
|
||||
42: {UserId: 42, Status: userv1.UserStatus_USER_STATUS_ACTIVE, Country: "US"},
|
||||
900001: {UserId: 900001, Status: userv1.UserStatus_USER_STATUS_ACTIVE, Country: "CA"},
|
||||
},
|
||||
}
|
||||
router := newManagerCenterTestRouter(walletClient, &fakeUserHostClient{}, profileClient)
|
||||
body := []byte(`{"command_id":"mgr-grant-cross","target_user_id":"900001","resource_id":"101"}`)
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/manager-center/resource-grants", bytes.NewReader(body))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-manager-cross-country")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
assertEnvelope(t, recorder, http.StatusForbidden, httpkit.CodePermissionDenied, "req-manager-cross-country")
|
||||
if walletClient.lastGrantResource != nil {
|
||||
t.Fatalf("cross-country target must not reach wallet-service: %+v", walletClient.lastGrantResource)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantManagerVIPLimitsToVipOneToThree(t *testing.T) {
|
||||
walletClient := &fakeWalletClient{}
|
||||
router := newManagerCenterTestRouter(walletClient, &fakeUserHostClient{}, &fakeUserProfileClient{})
|
||||
body := []byte(`{"command_id":"mgr-vip-4","target_user_id":"900001","level":4}`)
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/manager-center/vip-grants", bytes.NewReader(body))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-manager-vip4")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
assertEnvelope(t, recorder, http.StatusBadRequest, httpkit.CodeInvalidArgument, "req-manager-vip4")
|
||||
if walletClient.lastGrantVip != nil {
|
||||
t.Fatalf("VIP4 must not reach wallet-service: %+v", walletClient.lastGrantVip)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantManagerVIPUsesManagerCenterGrantSource(t *testing.T) {
|
||||
walletClient := &fakeWalletClient{}
|
||||
router := newManagerCenterTestRouter(walletClient, &fakeUserHostClient{}, &fakeUserProfileClient{})
|
||||
body := []byte(`{"command_id":"mgr-vip-3","target_user_id":"900001","level":3}`)
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/manager-center/vip-grants", bytes.NewReader(body))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-manager-vip3")
|
||||
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 req := walletClient.lastGrantVip; req == nil || req.GetCommandId() != "mgr-vip-3" || req.GetTargetUserId() != 900001 || req.GetLevel() != 3 || req.GetGrantSource() != "manager_center" || req.GetOperatorUserId() != 42 {
|
||||
t.Fatalf("wallet GrantVip request mismatch: %+v", req)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagerBlockAndUnblockCallUserService(t *testing.T) {
|
||||
profileClient := &fakeUserProfileClient{}
|
||||
router := newManagerCenterTestRouter(&fakeWalletClient{}, &fakeUserHostClient{}, profileClient)
|
||||
body := []byte(`{"command_id":"block-163006","target_user_id":"900001","blocked_until_ms":1780000000000}`)
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/manager-center/blocks", bytes.NewReader(body))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-manager-block")
|
||||
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 req := profileClient.lastCreateBlock; req == nil || req.GetCommandId() != "block-163006" || req.GetManagerUserId() != 42 || req.GetTargetUserId() != 900001 || req.GetBlockedUntilMs() != 1780000000000 {
|
||||
t.Fatalf("CreateManagerUserBlock request mismatch: %+v", req)
|
||||
}
|
||||
|
||||
unblockReq := httptest.NewRequest(http.MethodPost, "/api/v1/manager-center/blocks/block-1/unblock", nil)
|
||||
unblockReq.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
unblockReq.Header.Set("X-Request-ID", "req-manager-unblock")
|
||||
unblockRecorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(unblockRecorder, unblockReq)
|
||||
|
||||
if unblockRecorder.Code != http.StatusOK {
|
||||
t.Fatalf("unblock status mismatch: got %d body=%s", unblockRecorder.Code, unblockRecorder.Body.String())
|
||||
}
|
||||
if req := profileClient.lastUnblock; req == nil || req.GetManagerUserId() != 42 || req.GetBlockId() != "block-1" {
|
||||
t.Fatalf("UnblockManagerUser request mismatch: %+v", req)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetManagerUserLevelCallsGrowthService(t *testing.T) {
|
||||
growthClient := &fakeGrowthLevelClient{}
|
||||
router := newManagerCenterTestRouterWithGrowth(&fakeWalletClient{}, &fakeUserHostClient{}, &fakeUserProfileClient{}, growthClient)
|
||||
body := []byte(`{"command_id":"level-wealth-5","target_user_id":"900001","track":"wealth","level":5}`)
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/manager-center/levels", bytes.NewReader(body))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-manager-level")
|
||||
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 req := growthClient.lastSet; req == nil || req.GetCommandId() != "level-wealth-5" || req.GetUserId() != 900001 || req.GetTrack() != "wealth" || req.GetLevel() != 5 || req.GetOperatorUserId() != 42 {
|
||||
t.Fatalf("SetUserLevel request mismatch: %+v", req)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeGrowthLevelClient struct {
|
||||
lastSet *activityv1.SetUserLevelRequest
|
||||
}
|
||||
|
||||
func (f *fakeGrowthLevelClient) GetMyLevelOverview(context.Context, *activityv1.GetMyLevelOverviewRequest) (*activityv1.GetMyLevelOverviewResponse, error) {
|
||||
return &activityv1.GetMyLevelOverviewResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeGrowthLevelClient) GetLevelTrack(context.Context, *activityv1.GetLevelTrackRequest) (*activityv1.GetLevelTrackResponse, error) {
|
||||
return &activityv1.GetLevelTrackResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeGrowthLevelClient) BatchGetUserLevelDisplayProfiles(context.Context, *activityv1.BatchGetUserLevelDisplayProfilesRequest) (*activityv1.BatchGetUserLevelDisplayProfilesResponse, error) {
|
||||
return &activityv1.BatchGetUserLevelDisplayProfilesResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeGrowthLevelClient) ListLevelRewards(context.Context, *activityv1.ListLevelRewardsRequest) (*activityv1.ListLevelRewardsResponse, error) {
|
||||
return &activityv1.ListLevelRewardsResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeGrowthLevelClient) SetUserLevel(_ context.Context, req *activityv1.SetUserLevelRequest) (*activityv1.SetUserLevelResponse, error) {
|
||||
f.lastSet = req
|
||||
return &activityv1.SetUserLevelResponse{EventId: "event-1", Status: "applied", Track: req.GetTrack(), NewLevel: req.GetLevel(), TotalValue: 1000}, nil
|
||||
}
|
||||
|
||||
@ -11,12 +11,14 @@ type Handler struct {
|
||||
walletClient client.WalletClient
|
||||
userHostClient client.UserHostClient
|
||||
userProfileClient client.UserProfileClient
|
||||
growthLevelClient client.GrowthLevelClient
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
WalletClient client.WalletClient
|
||||
UserHostClient client.UserHostClient
|
||||
UserProfileClient client.UserProfileClient
|
||||
GrowthLevelClient client.GrowthLevelClient
|
||||
}
|
||||
|
||||
func New(config Config) *Handler {
|
||||
@ -24,6 +26,7 @@ func New(config Config) *Handler {
|
||||
walletClient: config.WalletClient,
|
||||
userHostClient: config.UserHostClient,
|
||||
userProfileClient: config.UserProfileClient,
|
||||
growthLevelClient: config.GrowthLevelClient,
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,5 +35,13 @@ func (h *Handler) ManagerHandlers() httproutes.ManagerHandlers {
|
||||
ListManagerGrantResources: h.listManagerGrantResources,
|
||||
GrantManagerResource: h.grantManagerResource,
|
||||
LookupBusinessUsers: h.lookupBusinessUsers,
|
||||
GetManagerOverview: h.getManagerOverview,
|
||||
SearchManagerUsers: h.searchManagerUsers,
|
||||
GrantManagerVIP: h.grantManagerVIP,
|
||||
ManagerBlocks: h.managerBlocks,
|
||||
ListManagerBlocks: h.listManagerBlocks,
|
||||
CreateManagerBlock: h.createManagerBlock,
|
||||
UnblockManagerBlock: h.unblockManagerBlock,
|
||||
SetManagerUserLevel: h.setManagerUserLevel,
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
userv1 "hyapp.local/api/proto/user/v1"
|
||||
walletv1 "hyapp.local/api/proto/wallet/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
@ -15,7 +16,10 @@ import (
|
||||
"hyapp/services/gateway-service/internal/auth"
|
||||
)
|
||||
|
||||
const managerCenterCapability = "manager_center"
|
||||
const managerResourceGrantCapability = "manager_resource_grant"
|
||||
const managerGrantDayMS int64 = 24 * 60 * 60 * 1000
|
||||
const managerGrantDefaultDurationMS int64 = 7 * managerGrantDayMS
|
||||
|
||||
type managerGrantResourceData struct {
|
||||
ResourceID string `json:"resource_id"`
|
||||
@ -39,6 +43,25 @@ type businessUserLookupData struct {
|
||||
RegionName string `json:"region_name,omitempty"`
|
||||
}
|
||||
|
||||
type managerUserData struct {
|
||||
UserID string `json:"user_id"`
|
||||
DisplayUserID string `json:"display_user_id"`
|
||||
Username string `json:"username"`
|
||||
Avatar string `json:"avatar"`
|
||||
Status string `json:"status"`
|
||||
Country string `json:"country"`
|
||||
RegionID int64 `json:"region_id,omitempty"`
|
||||
RegionCode string `json:"region_code,omitempty"`
|
||||
RegionName string `json:"region_name,omitempty"`
|
||||
Levels map[string]managerLevelData `json:"levels"`
|
||||
}
|
||||
|
||||
type managerLevelData struct {
|
||||
Track string `json:"track"`
|
||||
Level int32 `json:"level"`
|
||||
TierID string `json:"tier_id,omitempty"`
|
||||
}
|
||||
|
||||
type managerResourceGrantData struct {
|
||||
GrantID string `json:"grant_id"`
|
||||
CommandID string `json:"command_id"`
|
||||
@ -50,11 +73,124 @@ type managerResourceGrantData struct {
|
||||
CreatedAtMS int64 `json:"created_at_ms"`
|
||||
}
|
||||
|
||||
func (h *Handler) listManagerGrantResources(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.walletClient == nil || h.userHostClient == nil {
|
||||
type managerBlockData struct {
|
||||
BlockID string `json:"block_id"`
|
||||
TargetUserID string `json:"target_user_id"`
|
||||
TargetDisplayUserID string `json:"target_display_user_id"`
|
||||
TargetUsername string `json:"target_username"`
|
||||
TargetAvatar string `json:"target_avatar"`
|
||||
Country string `json:"country"`
|
||||
BlockedUntilMS int64 `json:"blocked_until_ms"`
|
||||
Status string `json:"status"`
|
||||
Reason string `json:"reason"`
|
||||
CreatedAtMS int64 `json:"created_at_ms"`
|
||||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||||
}
|
||||
|
||||
type managerLevelUpdateData struct {
|
||||
EventID string `json:"event_id"`
|
||||
Status string `json:"status"`
|
||||
Track string `json:"track"`
|
||||
PreviousLevel int32 `json:"previous_level"`
|
||||
NewLevel int32 `json:"new_level"`
|
||||
TotalValue int64 `json:"total_value"`
|
||||
RewardJobCount int64 `json:"reward_job_count"`
|
||||
ServerTimeMS int64 `json:"server_time_ms"`
|
||||
}
|
||||
|
||||
func (h *Handler) getManagerOverview(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.userHostClient == nil || h.userProfileClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
// 经理中心首页只信 user-service 的角色事实;前端传 is_manager 或 identity 都不能绕过这里。
|
||||
actor, ok := h.requireManagerCenterActor(writer, request)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{
|
||||
"is_manager": true,
|
||||
"user_id": httpkit.UserIDString(actor.GetUserId()),
|
||||
"display_user_id": actor.GetDisplayUserId(),
|
||||
"username": actor.GetUsername(),
|
||||
"avatar": actor.GetAvatar(),
|
||||
"country": actor.GetCountry(),
|
||||
"region_id": actor.GetRegionId(),
|
||||
"region_code": actor.GetRegionCode(),
|
||||
"region_name": actor.GetRegionName(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) searchManagerUsers(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.userProfileClient == nil || h.userHostClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
// 搜索先走已有 business lookup 保持短号/昵称解析一致,再用 BatchGetUsers 拿国家和等级投影做最终过滤。
|
||||
actor, ok := h.requireManagerCenterActor(writer, request)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
pageSize, ok := httpkit.PositiveInt32Query(request, "page_size", 20)
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
if pageSize > 20 {
|
||||
pageSize = 20
|
||||
}
|
||||
lookupResp, err := h.userProfileClient.BusinessUserLookup(request.Context(), &userv1.BusinessUserLookupRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
ActorUserId: actor.GetUserId(),
|
||||
Scene: "manager_resource_grant",
|
||||
Keyword: strings.TrimSpace(request.URL.Query().Get("keyword")),
|
||||
PageSize: pageSize,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
userIDs := make([]int64, 0, len(lookupResp.GetUsers()))
|
||||
seen := map[int64]bool{}
|
||||
for _, item := range lookupResp.GetUsers() {
|
||||
if id := item.GetUserId(); id > 0 && !seen[id] {
|
||||
seen[id] = true
|
||||
userIDs = append(userIDs, id)
|
||||
}
|
||||
}
|
||||
if len(userIDs) == 0 {
|
||||
httpkit.WriteOK(writer, request, map[string]any{"items": []managerUserData{}, "total": 0, "page_size": pageSize})
|
||||
return
|
||||
}
|
||||
usersResp, err := h.userProfileClient.BatchGetUsers(request.Context(), &userv1.BatchGetUsersRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
UserIds: userIDs,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
levels := h.managerLevelsByUser(request, userIDs)
|
||||
items := make([]managerUserData, 0, len(userIDs))
|
||||
for _, userID := range userIDs {
|
||||
user := usersResp.GetUsers()[userID]
|
||||
// 同国家限制必须放在 gateway 写入口和读入口都做,避免 H5 通过短号枚举跨国家用户。
|
||||
if user == nil || user.GetStatus() != userv1.UserStatus_USER_STATUS_ACTIVE || !sameCountry(actor.GetCountry(), user.GetCountry()) {
|
||||
continue
|
||||
}
|
||||
items = append(items, managerUserFromProto(user, levels[userID]))
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items), "page_size": pageSize})
|
||||
}
|
||||
|
||||
func (h *Handler) listManagerGrantResources(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.walletClient == nil || h.userHostClient == nil || h.userProfileClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
if _, ok := h.requireManagerCenterActor(writer, request); !ok {
|
||||
return
|
||||
}
|
||||
if !h.requireManagerResourceGrantCapability(writer, request) {
|
||||
return
|
||||
}
|
||||
@ -134,7 +270,12 @@ func (h *Handler) grantManagerResource(writer http.ResponseWriter, request *http
|
||||
if !httpkit.Decode(writer, request, &body) {
|
||||
return
|
||||
}
|
||||
if body.Quantity != nil || body.DurationMS != nil || body.DurationMSAlt != nil {
|
||||
if body.Quantity != nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
durationMS, durationOK := managerGrantDurationMS(body.DurationMS, body.DurationMSAlt)
|
||||
if !durationOK {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
@ -151,16 +292,8 @@ func (h *Handler) grantManagerResource(writer http.ResponseWriter, request *http
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
targetResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
UserId: targetUserID,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
if target := targetResp.GetUser(); target == nil || target.GetStatus() != userv1.UserStatus_USER_STATUS_ACTIVE {
|
||||
httpkit.WriteError(writer, request, http.StatusNotFound, httpkit.CodeNotFound, "not found")
|
||||
// 赠送资源前先确认目标用户仍然 active 且与经理同国家;wallet-service 还会在事务内复验资源白名单。
|
||||
if _, ok := h.requireSameCountryTarget(writer, request, targetUserID); !ok {
|
||||
return
|
||||
}
|
||||
reason := strings.TrimSpace(body.Reason)
|
||||
@ -169,12 +302,13 @@ func (h *Handler) grantManagerResource(writer http.ResponseWriter, request *http
|
||||
}
|
||||
actorUserID := auth.UserIDFromContext(request.Context())
|
||||
resp, err := h.walletClient.GrantResource(request.Context(), &walletv1.GrantResourceRequest{
|
||||
CommandId: commandID,
|
||||
AppCode: appcode.FromContext(request.Context()),
|
||||
TargetUserId: targetUserID,
|
||||
ResourceId: resourceID,
|
||||
Quantity: 1,
|
||||
DurationMs: 0,
|
||||
CommandId: commandID,
|
||||
AppCode: appcode.FromContext(request.Context()),
|
||||
TargetUserId: targetUserID,
|
||||
ResourceId: resourceID,
|
||||
Quantity: 1,
|
||||
// 经理中心只能赠送产品允许的三个限时档位;数量、来源和操作人仍由网关固定,避免 H5 自行组装账务形状。
|
||||
DurationMs: durationMS,
|
||||
Reason: reason,
|
||||
OperatorUserId: actorUserID,
|
||||
GrantSource: "manager_center",
|
||||
@ -199,6 +333,242 @@ func (h *Handler) grantManagerResource(writer http.ResponseWriter, request *http
|
||||
httpkit.WriteOK(writer, request, grant)
|
||||
}
|
||||
|
||||
func (h *Handler) grantManagerVIP(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.walletClient == nil || h.userHostClient == nil || h.userProfileClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
CommandID string `json:"command_id"`
|
||||
CommandIDAlt string `json:"commandId"`
|
||||
TargetUserID json.RawMessage `json:"target_user_id"`
|
||||
TargetUserIDAlt json.RawMessage `json:"targetUserId"`
|
||||
Level int32 `json:"level"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
if !httpkit.Decode(writer, request, &body) {
|
||||
return
|
||||
}
|
||||
commandID := strings.TrimSpace(body.CommandID)
|
||||
if commandID == "" {
|
||||
commandID = strings.TrimSpace(body.CommandIDAlt)
|
||||
}
|
||||
targetUserID, targetOK := rawInt64(body.TargetUserID, body.TargetUserIDAlt)
|
||||
if commandID == "" || !targetOK || targetUserID <= 0 || body.Level < 1 || body.Level > 3 {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
// 经理中心复用后台 VIP 发放账务能力,但 source 固定为 manager_center,钱包侧据此保留统一 IM/outbox 行为。
|
||||
if _, ok := h.requireSameCountryTarget(writer, request, targetUserID); !ok {
|
||||
return
|
||||
}
|
||||
reason := strings.TrimSpace(body.Reason)
|
||||
if reason == "" {
|
||||
reason = "manager_center"
|
||||
}
|
||||
resp, err := h.walletClient.GrantVip(request.Context(), &walletv1.GrantVipRequest{
|
||||
CommandId: commandID,
|
||||
AppCode: appcode.FromContext(request.Context()),
|
||||
TargetUserId: targetUserID,
|
||||
Level: body.Level,
|
||||
GrantSource: "manager_center",
|
||||
OperatorUserId: auth.UserIDFromContext(request.Context()),
|
||||
Reason: reason,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{
|
||||
"transaction_id": resp.GetTransactionId(),
|
||||
"level": resp.GetVip().GetLevel(),
|
||||
"active": resp.GetVip().GetActive(),
|
||||
"expires_at_ms": resp.GetVip().GetExpiresAtMs(),
|
||||
"server_time_ms": resp.GetServerTimeMs(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) managerBlocks(writer http.ResponseWriter, request *http.Request) {
|
||||
switch request.Method {
|
||||
case http.MethodGet:
|
||||
h.listManagerBlocks(writer, request)
|
||||
case http.MethodPost:
|
||||
h.createManagerBlock(writer, request)
|
||||
default:
|
||||
httpkit.WriteError(writer, request, http.StatusMethodNotAllowed, httpkit.CodeInvalidArgument, "method not allowed")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) listManagerBlocks(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.userProfileClient == nil || h.userHostClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
actor, ok := h.requireManagerCenterActor(writer, request)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
pageSize, ok := httpkit.PositiveInt32Query(request, "page_size", 50)
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
if pageSize > 100 {
|
||||
pageSize = 100
|
||||
}
|
||||
status := strings.TrimSpace(request.URL.Query().Get("status"))
|
||||
resp, err := h.userProfileClient.ListManagerUserBlocks(request.Context(), &userv1.ListManagerUserBlocksRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
ManagerUserId: actor.GetUserId(),
|
||||
Status: status,
|
||||
PageSize: pageSize,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
items := make([]managerBlockData, 0, len(resp.GetBlocks()))
|
||||
for _, block := range resp.GetBlocks() {
|
||||
items = append(items, managerBlockFromProto(block))
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items), "page_size": pageSize})
|
||||
}
|
||||
|
||||
func (h *Handler) createManagerBlock(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.userProfileClient == nil || h.userHostClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
CommandID string `json:"command_id"`
|
||||
CommandIDAlt string `json:"commandId"`
|
||||
TargetUserID json.RawMessage `json:"target_user_id"`
|
||||
TargetUserIDAlt json.RawMessage `json:"targetUserId"`
|
||||
BlockedUntilMS int64 `json:"blocked_until_ms"`
|
||||
BlockedUntilMSAlt int64 `json:"blockedUntilMs"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
if !httpkit.Decode(writer, request, &body) {
|
||||
return
|
||||
}
|
||||
actor, ok := h.requireManagerCenterActor(writer, request)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
commandID := strings.TrimSpace(body.CommandID)
|
||||
if commandID == "" {
|
||||
commandID = strings.TrimSpace(body.CommandIDAlt)
|
||||
}
|
||||
targetUserID, targetOK := rawInt64(body.TargetUserID, body.TargetUserIDAlt)
|
||||
blockedUntilMS := body.BlockedUntilMS
|
||||
if blockedUntilMS <= 0 {
|
||||
blockedUntilMS = body.BlockedUntilMSAlt
|
||||
}
|
||||
if commandID == "" || !targetOK || targetUserID <= 0 || blockedUntilMS <= 0 {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
// user-service 会再次读取双方用户并校验同国家,这里保留 gateway 早拒绝以减少无效封禁事务。
|
||||
if _, ok := h.requireSameCountryTargetWithActor(writer, request, actor, targetUserID); !ok {
|
||||
return
|
||||
}
|
||||
resp, err := h.userProfileClient.CreateManagerUserBlock(request.Context(), &userv1.CreateManagerUserBlockRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
CommandId: commandID,
|
||||
ManagerUserId: actor.GetUserId(),
|
||||
TargetUserId: targetUserID,
|
||||
BlockedUntilMs: blockedUntilMS,
|
||||
Reason: strings.TrimSpace(body.Reason),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, managerBlockFromProto(resp.GetBlock()))
|
||||
}
|
||||
|
||||
func (h *Handler) unblockManagerBlock(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.userProfileClient == nil || h.userHostClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
actor, ok := h.requireManagerCenterActor(writer, request)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
if request.Body != nil && request.ContentLength != 0 {
|
||||
if !httpkit.Decode(writer, request, &body) {
|
||||
return
|
||||
}
|
||||
}
|
||||
blockID := strings.TrimSpace(request.PathValue("block_id"))
|
||||
if blockID == "" {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
resp, err := h.userProfileClient.UnblockManagerUser(request.Context(), &userv1.UnblockManagerUserRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
ManagerUserId: actor.GetUserId(),
|
||||
BlockId: blockID,
|
||||
Reason: strings.TrimSpace(body.Reason),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, managerBlockFromProto(resp.GetBlock()))
|
||||
}
|
||||
|
||||
func (h *Handler) setManagerUserLevel(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.growthLevelClient == nil || h.userProfileClient == nil || h.userHostClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
CommandID string `json:"command_id"`
|
||||
CommandIDAlt string `json:"commandId"`
|
||||
TargetUserID json.RawMessage `json:"target_user_id"`
|
||||
TargetUserIDAlt json.RawMessage `json:"targetUserId"`
|
||||
Track string `json:"track"`
|
||||
Level int32 `json:"level"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
if !httpkit.Decode(writer, request, &body) {
|
||||
return
|
||||
}
|
||||
commandID := strings.TrimSpace(body.CommandID)
|
||||
if commandID == "" {
|
||||
commandID = strings.TrimSpace(body.CommandIDAlt)
|
||||
}
|
||||
targetUserID, targetOK := rawInt64(body.TargetUserID, body.TargetUserIDAlt)
|
||||
track := strings.ToLower(strings.TrimSpace(body.Track))
|
||||
if commandID == "" || !targetOK || targetUserID <= 0 || !validManagerLevelTrack(track) || body.Level < 1 || body.Level > 11 {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
// 等级设置会把目标轨道 total_value 直接改到对应规则阈值,并由 activity-service 补齐 1..目标等级奖励。
|
||||
if _, ok := h.requireSameCountryTarget(writer, request, targetUserID); !ok {
|
||||
return
|
||||
}
|
||||
resp, err := h.growthLevelClient.SetUserLevel(request.Context(), &activityv1.SetUserLevelRequest{
|
||||
Meta: httpkit.ActivityMeta(request),
|
||||
CommandId: commandID,
|
||||
UserId: targetUserID,
|
||||
Track: track,
|
||||
Level: body.Level,
|
||||
OperatorUserId: auth.UserIDFromContext(request.Context()),
|
||||
Reason: strings.TrimSpace(body.Reason),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, managerLevelUpdateFromProto(resp))
|
||||
}
|
||||
|
||||
func (h *Handler) requireManagerResourceGrantCapability(writer http.ResponseWriter, request *http.Request) bool {
|
||||
resp, err := h.userHostClient.CheckBusinessCapability(request.Context(), &userv1.CheckBusinessCapabilityRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
@ -216,6 +586,76 @@ func (h *Handler) requireManagerResourceGrantCapability(writer http.ResponseWrit
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *Handler) requireManagerCenterActor(writer http.ResponseWriter, request *http.Request) (*userv1.User, bool) {
|
||||
if !h.requireManagerCapability(writer, request, managerCenterCapability) {
|
||||
return nil, false
|
||||
}
|
||||
resp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
UserId: auth.UserIDFromContext(request.Context()),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return nil, false
|
||||
}
|
||||
actor := resp.GetUser()
|
||||
if actor == nil || actor.GetStatus() != userv1.UserStatus_USER_STATUS_ACTIVE {
|
||||
httpkit.WriteError(writer, request, http.StatusForbidden, httpkit.CodePermissionDenied, "permission denied")
|
||||
return nil, false
|
||||
}
|
||||
return actor, true
|
||||
}
|
||||
|
||||
func (h *Handler) requireManagerCapability(writer http.ResponseWriter, request *http.Request, capability string) bool {
|
||||
resp, err := h.userHostClient.CheckBusinessCapability(request.Context(), &userv1.CheckBusinessCapabilityRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
ActorUserId: auth.UserIDFromContext(request.Context()),
|
||||
Capability: capability,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return false
|
||||
}
|
||||
if !resp.GetAllowed() {
|
||||
httpkit.WriteError(writer, request, http.StatusForbidden, httpkit.CodePermissionDenied, "permission denied")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *Handler) requireSameCountryTarget(writer http.ResponseWriter, request *http.Request, targetUserID int64) (*userv1.User, bool) {
|
||||
actor, ok := h.requireManagerCenterActor(writer, request)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return h.requireSameCountryTargetWithActor(writer, request, actor, targetUserID)
|
||||
}
|
||||
|
||||
func (h *Handler) requireSameCountryTargetWithActor(writer http.ResponseWriter, request *http.Request, actor *userv1.User, targetUserID int64) (*userv1.User, bool) {
|
||||
targetResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
UserId: targetUserID,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return nil, false
|
||||
}
|
||||
target := targetResp.GetUser()
|
||||
if target == nil || target.GetStatus() != userv1.UserStatus_USER_STATUS_ACTIVE {
|
||||
httpkit.WriteError(writer, request, http.StatusNotFound, httpkit.CodeNotFound, "not found")
|
||||
return nil, false
|
||||
}
|
||||
if !sameCountry(actor.GetCountry(), target.GetCountry()) {
|
||||
httpkit.WriteError(writer, request, http.StatusForbidden, httpkit.CodePermissionDenied, "permission denied")
|
||||
return nil, false
|
||||
}
|
||||
return target, true
|
||||
}
|
||||
|
||||
func sameCountry(left string, right string) bool {
|
||||
return strings.EqualFold(strings.TrimSpace(left), strings.TrimSpace(right)) && strings.TrimSpace(left) != ""
|
||||
}
|
||||
|
||||
func managerGrantResourceFromProto(resource *walletv1.Resource) managerGrantResourceData {
|
||||
if resource == nil {
|
||||
return managerGrantResourceData{}
|
||||
@ -232,6 +672,140 @@ func managerGrantResourceFromProto(resource *walletv1.Resource) managerGrantReso
|
||||
}
|
||||
}
|
||||
|
||||
func managerUserFromProto(user *userv1.User, levels map[string]managerLevelData) managerUserData {
|
||||
if user == nil {
|
||||
return managerUserData{Levels: managerDefaultLevels()}
|
||||
}
|
||||
if levels == nil {
|
||||
levels = managerDefaultLevels()
|
||||
}
|
||||
return managerUserData{
|
||||
UserID: httpkit.UserIDString(user.GetUserId()),
|
||||
DisplayUserID: user.GetDisplayUserId(),
|
||||
Username: user.GetUsername(),
|
||||
Avatar: user.GetAvatar(),
|
||||
Status: userStatusString(user.GetStatus()),
|
||||
Country: user.GetCountry(),
|
||||
RegionID: user.GetRegionId(),
|
||||
RegionCode: user.GetRegionCode(),
|
||||
RegionName: user.GetRegionName(),
|
||||
Levels: levels,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) managerLevelsByUser(request *http.Request, userIDs []int64) map[int64]map[string]managerLevelData {
|
||||
result := map[int64]map[string]managerLevelData{}
|
||||
for _, userID := range userIDs {
|
||||
result[userID] = managerDefaultLevels()
|
||||
}
|
||||
if h.growthLevelClient == nil || len(userIDs) == 0 {
|
||||
return result
|
||||
}
|
||||
resp, err := h.growthLevelClient.BatchGetUserLevelDisplayProfiles(request.Context(), &activityv1.BatchGetUserLevelDisplayProfilesRequest{
|
||||
Meta: httpkit.ActivityMeta(request),
|
||||
UserIds: userIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return result
|
||||
}
|
||||
for _, profile := range resp.GetProfiles() {
|
||||
if profile.GetUserId() <= 0 {
|
||||
continue
|
||||
}
|
||||
result[profile.GetUserId()] = map[string]managerLevelData{
|
||||
"wealth": managerLevelFromProto(profile.GetWealth()),
|
||||
"charm": managerLevelFromProto(profile.GetCharm()),
|
||||
"game": managerLevelFromProto(profile.GetGame()),
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func managerDefaultLevels() map[string]managerLevelData {
|
||||
return map[string]managerLevelData{
|
||||
"wealth": {Track: "wealth"},
|
||||
"charm": {Track: "charm"},
|
||||
"game": {Track: "game"},
|
||||
}
|
||||
}
|
||||
|
||||
func managerLevelFromProto(track *activityv1.LevelDisplayTrackProfile) managerLevelData {
|
||||
if track == nil {
|
||||
return managerLevelData{}
|
||||
}
|
||||
return managerLevelData{
|
||||
Track: track.GetTrack(),
|
||||
Level: track.GetLevel(),
|
||||
TierID: httpkit.UserIDString(track.GetTierId()),
|
||||
}
|
||||
}
|
||||
|
||||
func managerBlockFromProto(block *userv1.ManagerUserBlock) managerBlockData {
|
||||
if block == nil {
|
||||
return managerBlockData{}
|
||||
}
|
||||
return managerBlockData{
|
||||
BlockID: block.GetBlockId(),
|
||||
TargetUserID: httpkit.UserIDString(block.GetTargetUserId()),
|
||||
TargetDisplayUserID: block.GetTargetDisplayUserId(),
|
||||
TargetUsername: block.GetTargetUsername(),
|
||||
TargetAvatar: block.GetTargetAvatar(),
|
||||
Country: block.GetCountry(),
|
||||
BlockedUntilMS: block.GetBlockedUntilMs(),
|
||||
Status: block.GetStatus(),
|
||||
Reason: block.GetReason(),
|
||||
CreatedAtMS: block.GetCreatedAtMs(),
|
||||
UpdatedAtMS: block.GetUpdatedAtMs(),
|
||||
}
|
||||
}
|
||||
|
||||
func managerLevelUpdateFromProto(resp *activityv1.SetUserLevelResponse) managerLevelUpdateData {
|
||||
if resp == nil {
|
||||
return managerLevelUpdateData{}
|
||||
}
|
||||
return managerLevelUpdateData{
|
||||
EventID: resp.GetEventId(),
|
||||
Status: resp.GetStatus(),
|
||||
Track: resp.GetTrack(),
|
||||
PreviousLevel: resp.GetPreviousLevel(),
|
||||
NewLevel: resp.GetNewLevel(),
|
||||
TotalValue: resp.GetTotalValue(),
|
||||
RewardJobCount: resp.GetRewardJobCount(),
|
||||
ServerTimeMS: resp.GetServerTimeMs(),
|
||||
}
|
||||
}
|
||||
|
||||
func validManagerLevelTrack(track string) bool {
|
||||
switch track {
|
||||
case "wealth", "charm", "game":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func managerGrantDurationMS(primary *int64, alternate *int64) (int64, bool) {
|
||||
// 旧 H5 还没有 duration 字段,默认 7 天保证入口兼容;新 H5 只能在 7/30/90 天之间选择。
|
||||
if primary == nil && alternate == nil {
|
||||
return managerGrantDefaultDurationMS, true
|
||||
}
|
||||
if primary != nil && alternate != nil && *primary != *alternate {
|
||||
return 0, false
|
||||
}
|
||||
value := int64(0)
|
||||
if primary != nil {
|
||||
value = *primary
|
||||
} else {
|
||||
value = *alternate
|
||||
}
|
||||
switch value {
|
||||
case 7 * managerGrantDayMS, 30 * managerGrantDayMS, 90 * managerGrantDayMS:
|
||||
return value, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
func businessUserLookupFromProto(user *userv1.BusinessUserLookupItem) businessUserLookupData {
|
||||
if user == nil {
|
||||
return businessUserLookupData{}
|
||||
|
||||
@ -311,13 +311,20 @@ type fakeUserProfileClient struct {
|
||||
lastComplete *userv1.CompleteOnboardingRequest
|
||||
lastUpdate *userv1.UpdateUserProfileRequest
|
||||
lastCountry *userv1.ChangeUserCountryRequest
|
||||
lastCreateBlock *userv1.CreateManagerUserBlockRequest
|
||||
lastListBlocks *userv1.ListManagerUserBlocksRequest
|
||||
lastUnblock *userv1.UnblockManagerUserRequest
|
||||
getErr error
|
||||
statsResp *userv1.GetMyProfileStatsResponse
|
||||
businessLookupResp *userv1.BusinessUserLookupResponse
|
||||
businessLookupErr error
|
||||
blocksResp *userv1.ListManagerUserBlocksResponse
|
||||
createBlockResp *userv1.CreateManagerUserBlockResponse
|
||||
unblockResp *userv1.UnblockManagerUserResponse
|
||||
statsErr error
|
||||
completeErr error
|
||||
countryErr error
|
||||
blockErr error
|
||||
regionID int64
|
||||
regionByUserID map[int64]int64
|
||||
usersByID map[int64]*userv1.User
|
||||
@ -389,6 +396,12 @@ type fakeUserCountryQueryClient struct {
|
||||
blockedErr error
|
||||
}
|
||||
|
||||
type fakeUserRegionClient struct {
|
||||
last *userv1.GetRegionRequest
|
||||
resp *userv1.RegionResponse
|
||||
err error
|
||||
}
|
||||
|
||||
type fakeUserHostClient struct {
|
||||
lastSearchAgencies *userv1.SearchAgenciesRequest
|
||||
searchAgenciesResp *userv1.SearchAgenciesResponse
|
||||
@ -481,6 +494,8 @@ type fakeWalletClient struct {
|
||||
vipErr error
|
||||
lastPurchaseVip *walletv1.PurchaseVipRequest
|
||||
purchaseVipResp *walletv1.PurchaseVipResponse
|
||||
lastGrantVip *walletv1.GrantVipRequest
|
||||
grantVipResp *walletv1.GrantVipResponse
|
||||
lastTransfer *walletv1.TransferCoinFromSellerRequest
|
||||
transferResp *walletv1.TransferCoinFromSellerResponse
|
||||
transferErr error
|
||||
@ -710,6 +725,7 @@ func (f *fakeUserProfileClient) BatchGetUsers(_ context.Context, req *userv1.Bat
|
||||
}
|
||||
users[userID] = &userv1.User{
|
||||
UserId: userID,
|
||||
Status: userv1.UserStatus_USER_STATUS_ACTIVE,
|
||||
DisplayUserId: strconv.FormatInt(100000+userID, 10),
|
||||
Username: "user-" + strconv.FormatInt(userID, 10),
|
||||
Gender: "female",
|
||||
@ -784,6 +800,53 @@ func (f *fakeUserProfileClient) ChangeUserCountry(_ context.Context, req *userv1
|
||||
}, NextChangeAllowedAtMs: 3600000, OldRegionId: 1001, NewRegionId: 2002, RegionChanged: true}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserProfileClient) CreateManagerUserBlock(_ context.Context, req *userv1.CreateManagerUserBlockRequest) (*userv1.CreateManagerUserBlockResponse, error) {
|
||||
f.lastCreateBlock = req
|
||||
if f.blockErr != nil {
|
||||
return nil, f.blockErr
|
||||
}
|
||||
if f.createBlockResp != nil {
|
||||
return f.createBlockResp, nil
|
||||
}
|
||||
return &userv1.CreateManagerUserBlockResponse{Block: &userv1.ManagerUserBlock{
|
||||
BlockId: "block-1",
|
||||
ManagerUserId: req.GetManagerUserId(),
|
||||
TargetUserId: req.GetTargetUserId(),
|
||||
TargetDisplayUserId: "163006",
|
||||
TargetUsername: "blocked",
|
||||
Country: "US",
|
||||
BlockedUntilMs: req.GetBlockedUntilMs(),
|
||||
Status: "active",
|
||||
Reason: req.GetReason(),
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserProfileClient) ListManagerUserBlocks(_ context.Context, req *userv1.ListManagerUserBlocksRequest) (*userv1.ListManagerUserBlocksResponse, error) {
|
||||
f.lastListBlocks = req
|
||||
if f.blockErr != nil {
|
||||
return nil, f.blockErr
|
||||
}
|
||||
if f.blocksResp != nil {
|
||||
return f.blocksResp, nil
|
||||
}
|
||||
return &userv1.ListManagerUserBlocksResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserProfileClient) UnblockManagerUser(_ context.Context, req *userv1.UnblockManagerUserRequest) (*userv1.UnblockManagerUserResponse, error) {
|
||||
f.lastUnblock = req
|
||||
if f.blockErr != nil {
|
||||
return nil, f.blockErr
|
||||
}
|
||||
if f.unblockResp != nil {
|
||||
return f.unblockResp, nil
|
||||
}
|
||||
return &userv1.UnblockManagerUserResponse{Block: &userv1.ManagerUserBlock{
|
||||
BlockId: req.GetBlockId(),
|
||||
ManagerUserId: req.GetManagerUserId(),
|
||||
Status: "released",
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserIdentityClient) GetUserIdentity(_ context.Context, req *userv1.GetUserIdentityRequest) (*userv1.GetUserIdentityResponse, error) {
|
||||
return &userv1.GetUserIdentityResponse{Identity: &userv1.UserIdentity{
|
||||
UserId: req.GetUserId(),
|
||||
@ -974,6 +1037,18 @@ func (f *fakeUserCountryQueryClient) ListLoginRiskBlockedCountries(_ context.Con
|
||||
return &userv1.ListLoginRiskBlockedCountriesResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeUserRegionClient) GetRegion(_ context.Context, req *userv1.GetRegionRequest) (*userv1.RegionResponse, error) {
|
||||
f.last = req
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
if f.resp != nil {
|
||||
return f.resp, nil
|
||||
}
|
||||
|
||||
return &userv1.RegionResponse{Region: &userv1.Region{RegionId: req.GetRegionId(), Countries: []string{"US"}}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeMessageInboxClient) ListMessageTabs(_ context.Context, req *activityv1.ListMessageTabsRequest) (*activityv1.ListMessageTabsResponse, error) {
|
||||
f.lastTabs = req
|
||||
if f.err != nil {
|
||||
@ -1468,6 +1543,21 @@ func (f *fakeWalletClient) PurchaseVip(_ context.Context, req *walletv1.Purchase
|
||||
return &walletv1.PurchaseVipResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeWalletClient) GrantVip(_ context.Context, req *walletv1.GrantVipRequest) (*walletv1.GrantVipResponse, error) {
|
||||
f.lastGrantVip = req
|
||||
if f.vipErr != nil {
|
||||
return nil, f.vipErr
|
||||
}
|
||||
if f.grantVipResp != nil {
|
||||
return f.grantVipResp, nil
|
||||
}
|
||||
return &walletv1.GrantVipResponse{
|
||||
TransactionId: "vip-grant-tx",
|
||||
Vip: &walletv1.UserVip{UserId: req.GetTargetUserId(), Level: req.GetLevel(), Active: true},
|
||||
ServerTimeMs: 1_780_000_000_000,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *fakeWalletClient) TransferCoinFromSeller(_ context.Context, req *walletv1.TransferCoinFromSellerRequest) (*walletv1.TransferCoinFromSellerResponse, error) {
|
||||
f.lastTransfer = req
|
||||
if f.transferErr != nil {
|
||||
@ -1773,6 +1863,9 @@ func TestRoutesWriteUnifiedEnvelopeAndGenerateRequestID(t *testing.T) {
|
||||
if profileClient.lastGet == nil || profileClient.lastGet.GetUserId() != 42 || client.lastCreate.GetVisibleRegionId() != 1001 {
|
||||
t.Fatalf("CreateRoom must derive visible_region_id from user-service: profile=%+v create=%+v", profileClient.lastGet, client.lastCreate)
|
||||
}
|
||||
if client.lastCreate.GetOwnerCountryCode() != "US" {
|
||||
t.Fatalf("CreateRoom must derive owner_country_code from user-service: %+v", client.lastCreate)
|
||||
}
|
||||
if client.lastCreate.GetRoomName() != "Lobby" || client.lastCreate.GetRoomAvatar() != "https://cdn.example.com/room.png" || client.lastCreate.GetRoomDescription() != "welcome" {
|
||||
t.Fatalf("CreateRoom should trim and forward room profile fields: %+v", client.lastCreate)
|
||||
}
|
||||
@ -2267,16 +2360,29 @@ func TestJoinRoomReturnsInitialDataWithIMGroupRTCTokenAndProfiles(t *testing.T)
|
||||
|
||||
func TestListRoomsUsesUserRegionFromUserService(t *testing.T) {
|
||||
profileClient := &fakeUserProfileClient{regionID: 1001}
|
||||
regionClient := &fakeUserRegionClient{resp: &userv1.RegionResponse{Region: &userv1.Region{
|
||||
RegionId: 1001,
|
||||
Countries: []string{"AE", "US", "TR"},
|
||||
}}}
|
||||
countryClient := &fakeUserCountryQueryClient{resp: &userv1.ListRegistrationCountriesResponse{
|
||||
Countries: []*userv1.Country{
|
||||
{CountryId: 1, CountryCode: "AE", CountryName: "United Arab Emirates", CountryDisplayName: "UAE", Flag: "🇦🇪"},
|
||||
{CountryId: 2, CountryCode: "US", CountryName: "United States", CountryDisplayName: "US", Flag: "🇺🇸"},
|
||||
{CountryId: 3, CountryCode: "TR", CountryName: "Türkiye", CountryDisplayName: "TR", Flag: "🇹🇷"},
|
||||
},
|
||||
}}
|
||||
queryClient := &fakeRoomQueryClient{resp: &roomv1.ListRoomsResponse{
|
||||
Rooms: []*roomv1.RoomListItem{
|
||||
{RoomId: "room-1", VisibleRegionId: 1001, Heat: 90, Locked: true},
|
||||
{RoomId: "room-1", VisibleRegionId: 1001, Heat: 90, Locked: true, CountryCode: "US"},
|
||||
},
|
||||
NextCursor: "cursor-2",
|
||||
}}
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, profileClient)
|
||||
handler.SetRoomQueryClient(queryClient)
|
||||
handler.SetUserRegionClient(regionClient)
|
||||
handler.SetUserCountryQueryClient(countryClient)
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/rooms?tab=hot&limit=2&cursor=cursor-1&q=room&visible_region_id=9999", nil)
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/rooms?tab=hot&limit=2&cursor=cursor-1&q=room&country=US&visible_region_id=9999", nil)
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-room-list")
|
||||
recorder := httptest.NewRecorder()
|
||||
@ -2295,21 +2401,67 @@ func TestListRoomsUsesUserRegionFromUserService(t *testing.T) {
|
||||
if queryClient.lastList.GetViewerUserId() != 42 || queryClient.lastList.GetVisibleRegionId() != 1001 {
|
||||
t.Fatalf("ListRooms must use authenticated user and server-side region: %+v", queryClient.lastList)
|
||||
}
|
||||
if queryClient.lastList.GetTab() != "hot" || queryClient.lastList.GetLimit() != 2 || queryClient.lastList.GetCursor() != "cursor-1" || queryClient.lastList.GetQuery() != "room" {
|
||||
if queryClient.lastList.GetTab() != "hot" || queryClient.lastList.GetLimit() != 2 || queryClient.lastList.GetCursor() != "cursor-1" || queryClient.lastList.GetQuery() != "room" || queryClient.lastList.GetCountryCode() != "US" {
|
||||
t.Fatalf("ListRooms query params were not propagated: %+v", queryClient.lastList)
|
||||
}
|
||||
if regionClient.last == nil || regionClient.last.GetRegionId() != 1001 || countryClient.last == nil {
|
||||
t.Fatalf("ListRooms must fetch region countries and country metadata: region=%+v countries=%+v", regionClient.last, countryClient.last)
|
||||
}
|
||||
var response httpkit.ResponseEnvelope
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("decode room list response failed: %v", err)
|
||||
}
|
||||
data := response.Data.(map[string]any)
|
||||
countries := data["countries"].([]any)
|
||||
if len(countries) != 3 {
|
||||
t.Fatalf("room list must expose current region countries: %+v", countries)
|
||||
}
|
||||
for index, want := range []string{"US", "AE", "TR"} {
|
||||
country := countries[index].(map[string]any)
|
||||
if country["country_code"] != want {
|
||||
t.Fatalf("country order mismatch at %d: want %s got %+v", index, want, countries)
|
||||
}
|
||||
}
|
||||
rooms := data["rooms"].([]any)
|
||||
first := rooms[0].(map[string]any)
|
||||
if first["im_group_id"] != "room-1" || first["locked"] != true {
|
||||
if first["im_group_id"] != "room-1" || first["locked"] != true || first["country_code"] != "US" {
|
||||
t.Fatalf("room list must expose room IM group id: %+v", first)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRoomsRejectsCountryOutsideUserRegion(t *testing.T) {
|
||||
profileClient := &fakeUserProfileClient{regionID: 1001}
|
||||
regionClient := &fakeUserRegionClient{resp: &userv1.RegionResponse{Region: &userv1.Region{
|
||||
RegionId: 1001,
|
||||
Countries: []string{"US", "AE"},
|
||||
}}}
|
||||
countryClient := &fakeUserCountryQueryClient{resp: &userv1.ListRegistrationCountriesResponse{
|
||||
Countries: []*userv1.Country{
|
||||
{CountryId: 1, CountryCode: "US", Flag: "🇺🇸"},
|
||||
{CountryId: 2, CountryCode: "AE", Flag: "🇦🇪"},
|
||||
{CountryId: 3, CountryCode: "CN", Flag: "🇨🇳"},
|
||||
},
|
||||
}}
|
||||
queryClient := &fakeRoomQueryClient{}
|
||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, profileClient)
|
||||
handler.SetRoomQueryClient(queryClient)
|
||||
handler.SetUserRegionClient(regionClient)
|
||||
handler.SetUserCountryQueryClient(countryClient)
|
||||
router := handler.Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/rooms?tab=hot&limit=2&country=CN", nil)
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if queryClient.lastList != nil {
|
||||
t.Fatalf("invalid country must not reach room-service: %+v", queryClient.lastList)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetRoomPasswordForwardsPasswordAndReturnsLockedState(t *testing.T) {
|
||||
client := &fakeRoomClient{}
|
||||
router := NewHandlerWithClients(client, nil, nil, &fakeUserProfileClient{}).Routes(auth.NewVerifier("secret"))
|
||||
|
||||
@ -15,6 +15,8 @@ type Handler struct {
|
||||
roomGuardClient client.RoomGuardClient
|
||||
roomQueryClient client.RoomQueryClient
|
||||
userProfileClient client.UserProfileClient
|
||||
userCountryClient client.UserCountryQueryClient
|
||||
userRegionClient client.UserRegionClient
|
||||
userSocialClient client.UserSocialClient
|
||||
userHostClient client.UserHostClient
|
||||
walletClient client.WalletClient
|
||||
@ -28,6 +30,8 @@ type Config struct {
|
||||
RoomGuardClient client.RoomGuardClient
|
||||
RoomQueryClient client.RoomQueryClient
|
||||
UserProfileClient client.UserProfileClient
|
||||
UserCountryClient client.UserCountryQueryClient
|
||||
UserRegionClient client.UserRegionClient
|
||||
UserSocialClient client.UserSocialClient
|
||||
UserHostClient client.UserHostClient
|
||||
WalletClient client.WalletClient
|
||||
@ -42,6 +46,8 @@ func New(config Config) *Handler {
|
||||
roomGuardClient: config.RoomGuardClient,
|
||||
roomQueryClient: config.RoomQueryClient,
|
||||
userProfileClient: config.UserProfileClient,
|
||||
userCountryClient: config.UserCountryClient,
|
||||
userRegionClient: config.UserRegionClient,
|
||||
userSocialClient: config.UserSocialClient,
|
||||
userHostClient: config.UserHostClient,
|
||||
walletClient: config.WalletClient,
|
||||
|
||||
@ -63,12 +63,6 @@ type roomFeedRelationCursor struct {
|
||||
|
||||
// listRooms 按当前登录用户的服务端 region_id 查询房间发现列表。
|
||||
func (h *Handler) listRooms(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.userProfileClient == nil || h.roomQueryClient == nil {
|
||||
// 列表入口必须同时依赖 user-service 区域归属和 room-service 读模型。
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
|
||||
limit, ok := parseRoomListLimit(request.URL.Query().Get("limit"))
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
@ -79,6 +73,11 @@ func (h *Handler) listRooms(writer http.ResponseWriter, request *http.Request) {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
if h.userProfileClient == nil || h.roomQueryClient == nil || h.userRegionClient == nil || h.userCountryClient == nil {
|
||||
// 列表入口必须同时依赖 user-service 用户区域、区域国家、国家主数据和 room-service 读模型。
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
|
||||
viewerUserID := auth.UserIDFromContext(request.Context())
|
||||
userResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
|
||||
@ -90,6 +89,16 @@ func (h *Handler) listRooms(writer http.ResponseWriter, request *http.Request) {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
countries, err := h.roomListCountriesForUser(request, userResp.GetUser())
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
countryCode, ok := roomListCountryQuery(request, countries)
|
||||
if !ok {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.roomQueryClient.ListRooms(request.Context(), &roomv1.ListRoomsRequest{
|
||||
Meta: httpkit.RoomMeta(request, "", ""),
|
||||
@ -99,12 +108,15 @@ func (h *Handler) listRooms(writer http.ResponseWriter, request *http.Request) {
|
||||
Cursor: request.URL.Query().Get("cursor"),
|
||||
Limit: limit,
|
||||
Query: roomListQuery(request),
|
||||
CountryCode: countryCode,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, roomListDataFromProto(resp))
|
||||
data := roomListDataFromProto(resp)
|
||||
data.Countries = countries
|
||||
httpkit.WriteOK(writer, request, data)
|
||||
}
|
||||
|
||||
// listRoomFeeds 查询 Mine 页 visited/friend/following/followed 房间流。
|
||||
@ -296,6 +308,123 @@ func roomListQuery(request *http.Request) string {
|
||||
return strings.TrimSpace(request.URL.Query().Get("query"))
|
||||
}
|
||||
|
||||
func (h *Handler) roomListCountriesForUser(request *http.Request, user *userv1.User) ([]roomListCountryData, error) {
|
||||
if user == nil || user.GetRegionId() <= 0 {
|
||||
// 当前用户区域来自 user-service 主数据;缺失时不能猜测区域国家列表。
|
||||
return nil, xerr.New(xerr.InvalidArgument, "user region is required")
|
||||
}
|
||||
regionResp, err := h.userRegionClient.GetRegion(request.Context(), &userv1.GetRegionRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
RegionId: user.GetRegionId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
countryResp, err := h.userCountryClient.ListRegistrationCountries(request.Context(), &userv1.ListRegistrationCountriesRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roomListCountriesFromProto(user, regionResp.GetRegion(), countryResp.GetCountries()), nil
|
||||
}
|
||||
|
||||
func roomListCountriesFromProto(user *userv1.User, region *userv1.Region, countries []*userv1.Country) []roomListCountryData {
|
||||
countriesByCode := make(map[string]*userv1.Country, len(countries))
|
||||
for _, country := range countries {
|
||||
code := normalizeRoomListCountryCode(country.GetCountryCode())
|
||||
if code == "" {
|
||||
continue
|
||||
}
|
||||
countriesByCode[code] = country
|
||||
}
|
||||
|
||||
seen := make(map[string]struct{})
|
||||
regionCodes := make([]string, 0, len(region.GetCountries()))
|
||||
regionCodeSet := make(map[string]struct{}, len(region.GetCountries()))
|
||||
if region != nil {
|
||||
for _, rawCode := range region.GetCountries() {
|
||||
code := normalizeRoomListCountryCode(rawCode)
|
||||
if code == "" {
|
||||
continue
|
||||
}
|
||||
regionCodes = append(regionCodes, code)
|
||||
regionCodeSet[code] = struct{}{}
|
||||
}
|
||||
}
|
||||
result := make([]roomListCountryData, 0, len(countriesByCode))
|
||||
add := func(code string) {
|
||||
code = normalizeRoomListCountryCode(code)
|
||||
if code == "" {
|
||||
return
|
||||
}
|
||||
if _, exists := seen[code]; exists {
|
||||
return
|
||||
}
|
||||
seen[code] = struct{}{}
|
||||
result = append(result, roomListCountryDataFromProto(code, countriesByCode[code]))
|
||||
}
|
||||
|
||||
// 国家列表严格来自当前区域;用户国家命中区域配置时提前到首位,其余国家保持 user-service 区域顺序。
|
||||
if user != nil {
|
||||
if _, exists := regionCodeSet[normalizeRoomListCountryCode(user.GetCountry())]; exists {
|
||||
add(user.GetCountry())
|
||||
}
|
||||
}
|
||||
for _, code := range regionCodes {
|
||||
add(code)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func roomListCountryDataFromProto(code string, country *userv1.Country) roomListCountryData {
|
||||
item := roomListCountryData{
|
||||
CountryCode: code,
|
||||
CountryFlag: roomProfileCountryFlag(code),
|
||||
}
|
||||
if country == nil {
|
||||
return item
|
||||
}
|
||||
item.CountryID = country.GetCountryId()
|
||||
item.CountryName = strings.TrimSpace(country.GetCountryName())
|
||||
item.CountryDisplayName = strings.TrimSpace(country.GetCountryDisplayName())
|
||||
if flag := strings.TrimSpace(country.GetFlag()); flag != "" {
|
||||
item.CountryFlag = flag
|
||||
}
|
||||
item.SortOrder = country.GetSortOrder()
|
||||
return item
|
||||
}
|
||||
|
||||
func roomListCountryQuery(request *http.Request, countries []roomListCountryData) (string, bool) {
|
||||
raw := strings.TrimSpace(request.URL.Query().Get("country"))
|
||||
if raw == "" {
|
||||
raw = strings.TrimSpace(request.URL.Query().Get("country_code"))
|
||||
}
|
||||
code := normalizeRoomListCountryCode(raw)
|
||||
if code == "" {
|
||||
return "", raw == ""
|
||||
}
|
||||
for _, country := range countries {
|
||||
if normalizeRoomListCountryCode(country.CountryCode) == code {
|
||||
return code, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func normalizeRoomListCountryCode(countryCode string) string {
|
||||
countryCode = strings.ToUpper(strings.TrimSpace(countryCode))
|
||||
if len(countryCode) < 2 || len(countryCode) > 3 {
|
||||
return ""
|
||||
}
|
||||
for _, ch := range countryCode {
|
||||
if ch < 'A' || ch > 'Z' {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return countryCode
|
||||
}
|
||||
|
||||
// parseRoomListLimit 只做 HTTP 字符串到数字的传输层解析。
|
||||
// 默认值和最大值仍由 room-service 统一裁剪,避免 gateway 和查询服务出现双份策略。
|
||||
func parseRoomListLimit(raw string) (int32, bool) {
|
||||
@ -697,14 +826,15 @@ func (h *Handler) createRoom(writer http.ResponseWriter, request *http.Request)
|
||||
roomID := appcode.NewScopedID(appcode.FromContext(request.Context()))
|
||||
roomShortID := userResp.GetUser().GetDisplayUserId()
|
||||
resp, err := h.roomClient.CreateRoom(request.Context(), &roomv1.CreateRoomRequest{
|
||||
Meta: httpkit.RoomMeta(request, roomID, body.CommandID),
|
||||
SeatCount: body.SeatCount,
|
||||
Mode: body.Mode,
|
||||
VisibleRegionId: userResp.GetUser().GetRegionId(),
|
||||
RoomName: body.RoomName,
|
||||
RoomAvatar: body.RoomAvatar,
|
||||
RoomDescription: body.RoomDescription,
|
||||
RoomShortId: roomShortID,
|
||||
Meta: httpkit.RoomMeta(request, roomID, body.CommandID),
|
||||
SeatCount: body.SeatCount,
|
||||
Mode: body.Mode,
|
||||
VisibleRegionId: userResp.GetUser().GetRegionId(),
|
||||
OwnerCountryCode: userResp.GetUser().GetCountry(),
|
||||
RoomName: body.RoomName,
|
||||
RoomAvatar: body.RoomAvatar,
|
||||
RoomDescription: body.RoomDescription,
|
||||
RoomShortId: roomShortID,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
|
||||
@ -11,8 +11,18 @@ import (
|
||||
const joinRoomContributionRankLimit = 10
|
||||
|
||||
type roomListData struct {
|
||||
Rooms []roomListItemData `json:"rooms"`
|
||||
NextCursor string `json:"next_cursor,omitempty"`
|
||||
Rooms []roomListItemData `json:"rooms"`
|
||||
NextCursor string `json:"next_cursor,omitempty"`
|
||||
Countries []roomListCountryData `json:"countries,omitempty"`
|
||||
}
|
||||
|
||||
type roomListCountryData struct {
|
||||
CountryID int64 `json:"country_id,omitempty"`
|
||||
CountryCode string `json:"country_code"`
|
||||
CountryName string `json:"country_name,omitempty"`
|
||||
CountryDisplayName string `json:"country_display_name,omitempty"`
|
||||
CountryFlag string `json:"country_flag,omitempty"`
|
||||
SortOrder int32 `json:"sort_order,omitempty"`
|
||||
}
|
||||
|
||||
type myRoomData struct {
|
||||
@ -37,6 +47,8 @@ type roomListItemData struct {
|
||||
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"`
|
||||
}
|
||||
|
||||
type createRoomData struct {
|
||||
@ -534,6 +546,8 @@ func roomListItemDataFromProto(room *roomv1.RoomListItem) roomListItemData {
|
||||
VisibleRegionID: room.GetVisibleRegionId(),
|
||||
AppCode: room.GetAppCode(),
|
||||
RoomShortID: room.GetRoomShortId(),
|
||||
CountryCode: room.GetCountryCode(),
|
||||
CountryFlag: roomProfileCountryFlag(room.GetCountryCode()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,8 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler {
|
||||
RoomGuardClient: h.roomGuardClient,
|
||||
RoomQueryClient: h.roomQueryClient,
|
||||
UserProfileClient: h.userProfileClient,
|
||||
UserCountryClient: h.userCountryClient,
|
||||
UserRegionClient: h.userRegionClient,
|
||||
UserSocialClient: h.userSocialClient,
|
||||
UserHostClient: h.userHostClient,
|
||||
WalletClient: h.walletClient,
|
||||
@ -92,6 +94,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler {
|
||||
WalletClient: h.walletClient,
|
||||
UserHostClient: h.userHostClient,
|
||||
UserProfileClient: h.userProfileClient,
|
||||
GrowthLevelClient: h.growthLevelClient,
|
||||
})
|
||||
appAPI := appapi.New(appapi.Config{
|
||||
AppConfigReader: h.appConfigReader,
|
||||
|
||||
@ -42,15 +42,20 @@ type cpApplicationData struct {
|
||||
}
|
||||
|
||||
type cpRelationshipData struct {
|
||||
RelationshipID string `json:"relationship_id"`
|
||||
RelationType string `json:"relation_type"`
|
||||
Status string `json:"status"`
|
||||
Me *cpUserProfileData `json:"me,omitempty"`
|
||||
Partner *cpUserProfileData `json:"partner,omitempty"`
|
||||
IntimacyValue int64 `json:"intimacy_value"`
|
||||
Level int32 `json:"level"`
|
||||
FormedAtMS int64 `json:"formed_at_ms"`
|
||||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||||
RelationshipID string `json:"relationship_id"`
|
||||
RelationType string `json:"relation_type"`
|
||||
Status string `json:"status"`
|
||||
Me *cpUserProfileData `json:"me,omitempty"`
|
||||
Partner *cpUserProfileData `json:"partner,omitempty"`
|
||||
IntimacyValue int64 `json:"intimacy_value"`
|
||||
Level int32 `json:"level"`
|
||||
CurrentLevelThreshold int64 `json:"current_level_threshold"`
|
||||
NextLevelThreshold int64 `json:"next_level_threshold"`
|
||||
NeededForNextLevel int64 `json:"needed_for_next_level"`
|
||||
LevelProgressPercent int32 `json:"level_progress_percent"`
|
||||
MaxLevel bool `json:"max_level"`
|
||||
FormedAtMS int64 `json:"formed_at_ms"`
|
||||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||||
}
|
||||
|
||||
type cpRejectRequest struct {
|
||||
@ -202,15 +207,20 @@ func cpRelationshipFromProto(item *userv1.CPRelationship) cpRelationshipData {
|
||||
return cpRelationshipData{}
|
||||
}
|
||||
return cpRelationshipData{
|
||||
RelationshipID: item.GetRelationshipId(),
|
||||
RelationType: item.GetRelationType(),
|
||||
Status: item.GetStatus(),
|
||||
Me: cpUserProfileFromProto(item.GetMe()),
|
||||
Partner: cpUserProfileFromProto(item.GetPartner()),
|
||||
IntimacyValue: item.GetIntimacyValue(),
|
||||
Level: item.GetLevel(),
|
||||
FormedAtMS: item.GetFormedAtMs(),
|
||||
UpdatedAtMS: item.GetUpdatedAtMs(),
|
||||
RelationshipID: item.GetRelationshipId(),
|
||||
RelationType: item.GetRelationType(),
|
||||
Status: item.GetStatus(),
|
||||
Me: cpUserProfileFromProto(item.GetMe()),
|
||||
Partner: cpUserProfileFromProto(item.GetPartner()),
|
||||
IntimacyValue: item.GetIntimacyValue(),
|
||||
Level: item.GetLevel(),
|
||||
CurrentLevelThreshold: item.GetCurrentLevelThreshold(),
|
||||
NextLevelThreshold: item.GetNextLevelThreshold(),
|
||||
NeededForNextLevel: item.GetNeededForNextLevel(),
|
||||
LevelProgressPercent: item.GetLevelProgressPercent(),
|
||||
MaxLevel: item.GetMaxLevel(),
|
||||
FormedAtMS: item.GetFormedAtMs(),
|
||||
UpdatedAtMS: item.GetUpdatedAtMs(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package userapi
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
userv1 "hyapp.local/api/proto/user/v1"
|
||||
)
|
||||
|
||||
func TestCPRelationshipFromProtoIncludesLevelProgress(t *testing.T) {
|
||||
item := &userv1.CPRelationship{
|
||||
RelationshipId: "cp_rel:1:2",
|
||||
RelationType: "brother",
|
||||
Status: "active",
|
||||
IntimacyValue: 180,
|
||||
Level: 2,
|
||||
CurrentLevelThreshold: 100,
|
||||
NextLevelThreshold: 300,
|
||||
NeededForNextLevel: 120,
|
||||
LevelProgressPercent: 40,
|
||||
MaxLevel: false,
|
||||
FormedAtMs: 1700000000000,
|
||||
UpdatedAtMs: 1700000001000,
|
||||
}
|
||||
|
||||
got := cpRelationshipFromProto(item)
|
||||
if got.CurrentLevelThreshold != 100 ||
|
||||
got.NextLevelThreshold != 300 ||
|
||||
got.NeededForNextLevel != 120 ||
|
||||
got.LevelProgressPercent != 40 ||
|
||||
got.MaxLevel {
|
||||
t.Fatalf("relationship progress fields not mapped: %+v", got)
|
||||
}
|
||||
}
|
||||
@ -189,10 +189,10 @@ func validateDelivery(delivery CPDelivery) error {
|
||||
len(delivery.PayloadJSON) == 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "cp delivery is incomplete")
|
||||
}
|
||||
if delivery.Channel == channelTencentIMC2C && delivery.TargetUserID <= 0 {
|
||||
if isTencentIMC2CChannel(delivery.Channel) && delivery.TargetUserID <= 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "cp c2c delivery target_user_id is required")
|
||||
}
|
||||
if delivery.Channel == channelTencentIMC2C && delivery.SenderUserID <= 0 {
|
||||
if isTencentIMC2CChannel(delivery.Channel) && delivery.SenderUserID <= 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "cp c2c delivery sender_user_id is required")
|
||||
}
|
||||
if (delivery.Channel == channelTencentIMRoom || delivery.Channel == channelTencentIMRegion) && strings.TrimSpace(delivery.GroupID) == "" {
|
||||
@ -201,6 +201,15 @@ func validateDelivery(delivery CPDelivery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isTencentIMC2CChannel(channel string) bool {
|
||||
switch channel {
|
||||
case channelTencentIMC2C, channelTencentIMC2CAcceptor:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func truncateError(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if len(value) <= 512 {
|
||||
|
||||
@ -22,9 +22,10 @@ const (
|
||||
eventApplicationRejected = "UserCPApplicationRejected"
|
||||
eventRelationshipCreated = "UserCPRelationshipCreated"
|
||||
|
||||
channelTencentIMC2C = "tencent_im_c2c"
|
||||
channelTencentIMRoom = "tencent_im_room"
|
||||
channelTencentIMRegion = "tencent_im_region"
|
||||
channelTencentIMC2C = "tencent_im_c2c"
|
||||
channelTencentIMC2CAcceptor = "tencent_im_c2c_acceptor"
|
||||
channelTencentIMRoom = "tencent_im_room"
|
||||
channelTencentIMRegion = "tencent_im_region"
|
||||
|
||||
noticeTypeApplicationCreated = "cp_application_created"
|
||||
noticeTypeApplicationAccepted = "cp_application_accepted"
|
||||
@ -99,7 +100,7 @@ func (s *Service) publishDelivery(ctx context.Context, delivery CPDelivery, opti
|
||||
defer cancel()
|
||||
var err error
|
||||
switch delivery.Channel {
|
||||
case channelTencentIMC2C:
|
||||
case channelTencentIMC2C, channelTencentIMC2CAcceptor:
|
||||
err = s.publisher.PublishUserCustomMessage(publishCtx, tencentim.CustomUserMessage{
|
||||
ToAccount: tencentim.FormatUserID(delivery.TargetUserID),
|
||||
FromAccount: tencentim.FormatUserID(delivery.SenderUserID),
|
||||
@ -246,7 +247,7 @@ func deliveriesFromMessage(message usermq.UserOutboxMessage, groupIDPrefix strin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return applicationDecisionDeliveries(appCode, message, application, payload, noticeTypeApplicationAccepted), nil
|
||||
return applicationAcceptedDeliveries(appCode, message, application, payload), nil
|
||||
case eventApplicationRejected:
|
||||
application, err := applicationFromObject(firstObject(root, "application", "Application"))
|
||||
if err != nil {
|
||||
@ -309,6 +310,58 @@ func applicationDecisionDeliveries(appCode string, message usermq.UserOutboxMess
|
||||
return deliveries
|
||||
}
|
||||
|
||||
func applicationAcceptedDeliveries(appCode string, message usermq.UserOutboxMessage, application cpApplication, payload map[string]any) []CPDelivery {
|
||||
// 同意成功后双方都要在 C2C 会话里看到一条消息;notice_delivery_events 的幂等键只有 event_id + channel,
|
||||
// 所以第二条 C2C 使用独立内部 channel,但 publishDelivery 仍按腾讯 IM 单聊投递。
|
||||
requesterPayload := cloneJSONMap(payload)
|
||||
requesterPayload["c2c_notice_role"] = "accepted_to_requester"
|
||||
requesterPayload["message_text"] = "我同意了你"
|
||||
acceptorPayload := cloneJSONMap(payload)
|
||||
acceptorPayload["c2c_notice_role"] = "accepted_to_acceptor"
|
||||
acceptorPayload["message_text"] = "对方已同意你的申请"
|
||||
deliveries := []CPDelivery{
|
||||
{
|
||||
AppCode: appCode,
|
||||
EventID: message.EventID,
|
||||
EventType: message.EventType,
|
||||
Channel: channelTencentIMC2C,
|
||||
NoticeType: noticeTypeApplicationAccepted,
|
||||
SenderUserID: application.Target.UserID,
|
||||
TargetUserID: application.Requester.UserID,
|
||||
PayloadJSON: mustJSON(requesterPayload),
|
||||
CreatedAtMS: message.OccurredAtMS,
|
||||
},
|
||||
{
|
||||
AppCode: appCode,
|
||||
EventID: message.EventID,
|
||||
EventType: message.EventType,
|
||||
Channel: channelTencentIMC2CAcceptor,
|
||||
NoticeType: noticeTypeApplicationAccepted,
|
||||
SenderUserID: application.Requester.UserID,
|
||||
TargetUserID: application.Target.UserID,
|
||||
PayloadJSON: mustJSON(acceptorPayload),
|
||||
CreatedAtMS: message.OccurredAtMS,
|
||||
},
|
||||
}
|
||||
if application.RoomID == "" {
|
||||
return deliveries
|
||||
}
|
||||
roomPayload := cloneJSONMap(payload)
|
||||
roomPayload["recipient_user_id"] = strconv.FormatInt(application.Requester.UserID, 10)
|
||||
deliveries = append(deliveries, CPDelivery{
|
||||
AppCode: appCode,
|
||||
EventID: message.EventID,
|
||||
EventType: message.EventType,
|
||||
Channel: channelTencentIMRoom,
|
||||
NoticeType: noticeTypeApplicationAccepted,
|
||||
TargetUserID: application.Requester.UserID,
|
||||
GroupID: application.RoomID,
|
||||
PayloadJSON: mustJSON(roomPayload),
|
||||
CreatedAtMS: message.OccurredAtMS,
|
||||
})
|
||||
return deliveries
|
||||
}
|
||||
|
||||
func relationshipCreatedDelivery(appCode string, message usermq.UserOutboxMessage, application cpApplication, relationshipID string, groupID string) ([]CPDelivery, error) {
|
||||
payload, err := cpRelationshipBroadcastPayload(message, application, relationshipID, groupID)
|
||||
if err != nil {
|
||||
|
||||
@ -39,7 +39,7 @@ func TestProcessApplicationCreatedPublishesC2CAndRoomIM(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessApplicationAcceptedPublishesRequesterC2CAndRoomIM(t *testing.T) {
|
||||
func TestProcessApplicationAcceptedPublishesMutualC2CAndRoomIM(t *testing.T) {
|
||||
repo := &fakeRepository{}
|
||||
publisher := &fakePublisher{}
|
||||
service := New(Config{NodeID: "notice-test"}, repo, publisher)
|
||||
@ -56,13 +56,27 @@ func TestProcessApplicationAcceptedPublishesRequesterC2CAndRoomIM(t *testing.T)
|
||||
if err != nil || !handled {
|
||||
t.Fatalf("ProcessUserOutboxMessage failed handled=%v err=%v", handled, err)
|
||||
}
|
||||
if len(publisher.userMessages) != 1 || publisher.userMessages[0].FromAccount != "1002" || publisher.userMessages[0].ToAccount != "1001" {
|
||||
t.Fatalf("expected requester c2c message, got %+v", publisher.userMessages)
|
||||
if len(publisher.userMessages) != 2 {
|
||||
t.Fatalf("expected mutual c2c messages, got %+v", publisher.userMessages)
|
||||
}
|
||||
if publisher.userMessages[0].FromAccount != "1002" || publisher.userMessages[0].ToAccount != "1001" {
|
||||
t.Fatalf("expected acceptor -> requester c2c message, got %+v", publisher.userMessages[0])
|
||||
}
|
||||
requesterPayload := mustObject(string(publisher.userMessages[0].PayloadJSON))
|
||||
if requesterPayload["c2c_notice_role"] != "accepted_to_requester" || requesterPayload["message_text"] != "我同意了你" {
|
||||
t.Fatalf("requester c2c payload mismatch: %+v", requesterPayload)
|
||||
}
|
||||
if publisher.userMessages[1].FromAccount != "1001" || publisher.userMessages[1].ToAccount != "1002" {
|
||||
t.Fatalf("expected requester -> acceptor c2c message, got %+v", publisher.userMessages[1])
|
||||
}
|
||||
acceptorPayload := mustObject(string(publisher.userMessages[1].PayloadJSON))
|
||||
if acceptorPayload["c2c_notice_role"] != "accepted_to_acceptor" || acceptorPayload["message_text"] != "对方已同意你的申请" {
|
||||
t.Fatalf("acceptor c2c payload mismatch: %+v", acceptorPayload)
|
||||
}
|
||||
if len(publisher.groupMessages) != 1 || publisher.groupMessages[0].GroupID != "room-100" {
|
||||
t.Fatalf("expected requester room group message, got %+v", publisher.groupMessages)
|
||||
}
|
||||
if len(repo.delivered) != 2 || repo.delivered[0].Channel != channelTencentIMC2C || repo.delivered[1].Channel != channelTencentIMRoom {
|
||||
if len(repo.delivered) != 3 || repo.delivered[0].Channel != channelTencentIMC2C || repo.delivered[1].Channel != channelTencentIMC2CAcceptor || repo.delivered[2].Channel != channelTencentIMRoom {
|
||||
t.Fatalf("delivery channels mismatch: %+v", repo.delivered)
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ CREATE TABLE IF NOT EXISTS room_list_entries (
|
||||
room_id VARCHAR(64) NOT NULL COMMENT '房间 ID',
|
||||
room_short_id VARCHAR(32) NOT NULL DEFAULT '' COMMENT '房间短号 ID',
|
||||
visible_region_id BIGINT NOT NULL DEFAULT 0 COMMENT '可见区域 ID',
|
||||
owner_country_code VARCHAR(3) NOT NULL DEFAULT '' COMMENT '房主国家码',
|
||||
owner_user_id BIGINT NOT NULL COMMENT '房主用户 ID',
|
||||
title VARCHAR(128) NOT NULL DEFAULT '' COMMENT '标题',
|
||||
cover_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT '封面 URL',
|
||||
@ -56,6 +57,8 @@ CREATE TABLE IF NOT EXISTS room_list_entries (
|
||||
KEY idx_room_list_short_id (app_code, room_short_id),
|
||||
KEY idx_room_list_region_hot (app_code, visible_region_id, status, sort_score DESC, room_id),
|
||||
KEY idx_room_list_region_new (app_code, visible_region_id, status, created_at_ms DESC, room_id),
|
||||
KEY idx_room_list_region_country_hot (app_code, visible_region_id, owner_country_code, status, sort_score DESC, room_id),
|
||||
KEY idx_room_list_region_country_new (app_code, visible_region_id, owner_country_code, status, created_at_ms DESC, room_id),
|
||||
KEY idx_room_list_owner (app_code, owner_user_id, updated_at_ms)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='房间列表项表';
|
||||
|
||||
|
||||
@ -64,6 +64,8 @@ type CreateRoom struct {
|
||||
Mode string `json:"mode"`
|
||||
// VisibleRegionID 是创建时固定的房间列表区域,0 表示 GLOBAL。
|
||||
VisibleRegionID int64 `json:"visible_region_id"`
|
||||
// OwnerCountryCode 是创建瞬间房主所属国家,列表国家筛选以该投影为准。
|
||||
OwnerCountryCode string `json:"owner_country_code,omitempty"`
|
||||
// RoomName 是房间展示名称,恢复时回填 RoomExt["title"],不拆成独立状态 owner。
|
||||
RoomName string `json:"room_name"`
|
||||
// RoomAvatar 是创建时必填的房间封面,恢复时回填 RoomExt["cover_url"]。
|
||||
@ -161,15 +163,16 @@ func (CloseRoom) Type() string { return "close_room" }
|
||||
// AdminUpdateRoom 定义后台房间资料和生命周期修改请求。
|
||||
type AdminUpdateRoom struct {
|
||||
Base
|
||||
Title *string `json:"title,omitempty"`
|
||||
CoverURL *string `json:"cover_url,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Mode *string `json:"mode,omitempty"`
|
||||
Status *string `json:"status,omitempty"`
|
||||
VisibleRegionID *int64 `json:"visible_region_id,omitempty"`
|
||||
CloseReason string `json:"close_reason,omitempty"`
|
||||
AdminID uint64 `json:"admin_id,omitempty"`
|
||||
AdminName string `json:"admin_name,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
CoverURL *string `json:"cover_url,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Mode *string `json:"mode,omitempty"`
|
||||
Status *string `json:"status,omitempty"`
|
||||
VisibleRegionID *int64 `json:"visible_region_id,omitempty"`
|
||||
OwnerCountryCode *string `json:"owner_country_code,omitempty"`
|
||||
CloseReason string `json:"close_reason,omitempty"`
|
||||
AdminID uint64 `json:"admin_id,omitempty"`
|
||||
AdminName string `json:"admin_name,omitempty"`
|
||||
}
|
||||
|
||||
func (AdminUpdateRoom) Type() string { return "admin_update_room" }
|
||||
|
||||
@ -243,6 +243,14 @@ func applyAdminRoomPatch(current *state.RoomState, cmd command.AdminUpdateRoom)
|
||||
current.VisibleRegionID = *cmd.VisibleRegionID
|
||||
changed = true
|
||||
}
|
||||
if cmd.OwnerCountryCode != nil {
|
||||
// 房主国家只作为发现页分类投影字段保存在 RoomExt;后台 HTTP 不开放直改入口,只有 user-service 国家事实同步会写入。
|
||||
ownerCountryCode := normalizeRoomCountryCode(*cmd.OwnerCountryCode)
|
||||
if current.RoomExt[roomExtOwnerCountryKey] != ownerCountryCode {
|
||||
current.RoomExt[roomExtOwnerCountryKey] = ownerCountryCode
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if cmd.Status != nil && current.Status != *cmd.Status {
|
||||
current.Status = *cmd.Status
|
||||
changed = true
|
||||
|
||||
@ -21,11 +21,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
roomExtTitleKey = "title"
|
||||
roomExtCoverURLKey = "cover_url"
|
||||
roomExtDescriptionKey = "description"
|
||||
roomExtShortIDKey = "room_short_id"
|
||||
roomExtBackgroundKey = "background_url"
|
||||
roomExtTitleKey = "title"
|
||||
roomExtCoverURLKey = "cover_url"
|
||||
roomExtDescriptionKey = "description"
|
||||
roomExtShortIDKey = "room_short_id"
|
||||
roomExtOwnerCountryKey = "owner_country_code"
|
||||
roomExtBackgroundKey = "background_url"
|
||||
|
||||
// defaultRoomAvatar 只服务房间资料更新/后台清空封面后的兜底;创建房间必须显式提交封面。
|
||||
defaultRoomAvatar = "hyapp://room/default-avatar"
|
||||
@ -39,10 +40,11 @@ const (
|
||||
|
||||
// roomProfileInput 是创建房间时需要落到 RoomExt 的展示资料集合。
|
||||
type roomProfileInput struct {
|
||||
Name string
|
||||
Avatar string
|
||||
Description string
|
||||
ShortID string
|
||||
Name string
|
||||
Avatar string
|
||||
Description string
|
||||
ShortID string
|
||||
OwnerCountryCode string
|
||||
}
|
||||
|
||||
// CreateRoom 创建一个新的房间执行单元,并把首个快照和事件落盘。
|
||||
@ -92,15 +94,16 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest)
|
||||
|
||||
// protobuf 请求先收敛为 command,后续幂等、持久化和恢复都只认识 command 模型。
|
||||
cmd := command.CreateRoom{
|
||||
Base: baseFromMeta(req.GetMeta()),
|
||||
OwnerUserID: actorUserID,
|
||||
SeatCount: seatCount,
|
||||
Mode: mode,
|
||||
VisibleRegionID: normalizeVisibleRegionID(req.GetVisibleRegionId()),
|
||||
RoomName: profile.Name,
|
||||
RoomAvatar: profile.Avatar,
|
||||
RoomDescription: profile.Description,
|
||||
RoomShortID: normalizeRoomShortID(req.GetRoomShortId(), actorUserID),
|
||||
Base: baseFromMeta(req.GetMeta()),
|
||||
OwnerUserID: actorUserID,
|
||||
SeatCount: seatCount,
|
||||
Mode: mode,
|
||||
VisibleRegionID: normalizeVisibleRegionID(req.GetVisibleRegionId()),
|
||||
OwnerCountryCode: normalizeRoomCountryCode(req.GetOwnerCountryCode()),
|
||||
RoomName: profile.Name,
|
||||
RoomAvatar: profile.Avatar,
|
||||
RoomDescription: profile.Description,
|
||||
RoomShortID: normalizeRoomShortID(req.GetRoomShortId(), actorUserID),
|
||||
}
|
||||
|
||||
idempotencyStartedAt := time.Now()
|
||||
@ -174,10 +177,11 @@ func (s *Service) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest)
|
||||
roomState.Version = 1
|
||||
roomState.VisibleRegionID = cmd.VisibleRegionID
|
||||
applyRoomProfileExt(roomState, roomProfileInput{
|
||||
Name: cmd.RoomName,
|
||||
Avatar: cmd.RoomAvatar,
|
||||
Description: cmd.RoomDescription,
|
||||
ShortID: cmd.RoomShortID,
|
||||
Name: cmd.RoomName,
|
||||
Avatar: cmd.RoomAvatar,
|
||||
Description: cmd.RoomDescription,
|
||||
ShortID: cmd.RoomShortID,
|
||||
OwnerCountryCode: cmd.OwnerCountryCode,
|
||||
})
|
||||
roomState.OnlineUsers[cmd.ActorUserID()] = &state.RoomUserState{
|
||||
UserID: cmd.ActorUserID(),
|
||||
@ -332,4 +336,5 @@ func applyRoomProfileExt(roomState *state.RoomState, profile roomProfileInput) {
|
||||
roomState.RoomExt[roomExtCoverURLKey] = profile.Avatar
|
||||
roomState.RoomExt[roomExtDescriptionKey] = profile.Description
|
||||
roomState.RoomExt[roomExtShortIDKey] = profile.ShortID
|
||||
roomState.RoomExt[roomExtOwnerCountryKey] = normalizeRoomCountryCode(profile.OwnerCountryCode)
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ const (
|
||||
type roomListCursor struct {
|
||||
Tab string `json:"tab"`
|
||||
Query string `json:"query,omitempty"`
|
||||
CountryCode string `json:"country_code,omitempty"`
|
||||
SortScore int64 `json:"sort_score,omitempty"`
|
||||
CreatedAtMS int64 `json:"created_at_ms,omitempty"`
|
||||
UpdatedAtMS int64 `json:"updated_at_ms,omitempty"`
|
||||
@ -66,7 +67,8 @@ func (s *Service) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cursor, err := decodeRoomListCursor(tab, query, req.GetCursor())
|
||||
countryCode := normalizeRoomCountryCode(req.GetCountryCode())
|
||||
cursor, err := decodeRoomListCursor(tab, query, countryCode, req.GetCursor())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -76,6 +78,7 @@ func (s *Service) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (
|
||||
VisibleRegionID: normalizeVisibleRegionID(req.GetVisibleRegionId()),
|
||||
Tab: tab,
|
||||
Query: query,
|
||||
CountryCode: countryCode,
|
||||
Limit: limit + 1,
|
||||
CursorSortScore: cursor.SortScore,
|
||||
CursorCreatedAtMS: cursor.CreatedAtMS,
|
||||
@ -90,7 +93,7 @@ func (s *Service) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return roomListResponseFromEntries(tab, query, entries, limit), nil
|
||||
return roomListResponseFromEntries(tab, query, countryCode, entries, limit), nil
|
||||
}
|
||||
|
||||
// ListRoomFeeds 查询 Mine 页 visited/friend/following/followed 房间流。
|
||||
@ -112,7 +115,7 @@ func (s *Service) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRe
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cursor, err := decodeRoomListCursor(tab, query, req.GetCursor())
|
||||
cursor, err := decodeRoomListCursor(tab, query, "", req.GetCursor())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -160,7 +163,7 @@ func (s *Service) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return roomListResponseFromEntries(tab, query, entries, limit), nil
|
||||
return roomListResponseFromEntries(tab, query, "", entries, limit), nil
|
||||
}
|
||||
|
||||
// GetMyRoom 查询当前用户自己创建的房间,不依赖 room_list_entries 投影命中。
|
||||
@ -193,12 +196,12 @@ func (s *Service) GetMyRoom(ctx context.Context, req *roomv1.GetMyRoomRequest) (
|
||||
}, nil
|
||||
}
|
||||
|
||||
func roomListResponseFromEntries(tab string, query string, entries []RoomListEntry, limit int) *roomv1.ListRoomsResponse {
|
||||
func roomListResponseFromEntries(tab string, query string, countryCode string, entries []RoomListEntry, limit int) *roomv1.ListRoomsResponse {
|
||||
nextCursor := ""
|
||||
if len(entries) > limit {
|
||||
// 多查一条用于判断是否存在下一页;返回数据只包含请求的 limit 条。
|
||||
last := entries[limit-1]
|
||||
nextCursor = encodeRoomListCursor(tab, query, last)
|
||||
nextCursor = encodeRoomListCursor(tab, query, countryCode, last)
|
||||
entries = entries[:limit]
|
||||
}
|
||||
|
||||
@ -280,6 +283,7 @@ func roomListEntryFromSnapshot(snapshot *roomv1.RoomSnapshot, visibleRegionID in
|
||||
RoomID: snapshot.GetRoomId(),
|
||||
RoomShortID: roomShortID,
|
||||
VisibleRegionID: normalizeVisibleRegionID(visibleRegionID),
|
||||
OwnerCountryCode: normalizeRoomCountryCode(snapshot.GetRoomExt()[roomExtOwnerCountryKey]),
|
||||
OwnerUserID: snapshot.GetOwnerUserId(),
|
||||
Title: title,
|
||||
CoverURL: coverURL,
|
||||
@ -387,11 +391,25 @@ func normalizeVisibleRegionID(regionID int64) int64 {
|
||||
return regionID
|
||||
}
|
||||
|
||||
// normalizeRoomCountryCode 把国家码收敛为大写字母;非法值按空值处理,避免污染 SQL 精确筛选。
|
||||
func normalizeRoomCountryCode(countryCode string) string {
|
||||
countryCode = strings.ToUpper(strings.TrimSpace(countryCode))
|
||||
if len(countryCode) < 2 || len(countryCode) > 3 {
|
||||
return ""
|
||||
}
|
||||
for _, ch := range countryCode {
|
||||
if ch < 'A' || ch > 'Z' {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return countryCode
|
||||
}
|
||||
|
||||
// decodeRoomListCursor 校验不透明 cursor 和当前 tab 一致,禁止客户端跨排序维度复用游标。
|
||||
func decodeRoomListCursor(tab string, query string, encoded string) (roomListCursor, error) {
|
||||
func decodeRoomListCursor(tab string, query string, countryCode string, encoded string) (roomListCursor, error) {
|
||||
encoded = strings.TrimSpace(encoded)
|
||||
if encoded == "" {
|
||||
return roomListCursor{Tab: tab, Query: query}, nil
|
||||
return roomListCursor{Tab: tab, Query: query, CountryCode: countryCode}, nil
|
||||
}
|
||||
|
||||
payload, err := base64.RawURLEncoding.DecodeString(encoded)
|
||||
@ -403,7 +421,7 @@ func decodeRoomListCursor(tab string, query string, encoded string) (roomListCur
|
||||
if err := json.Unmarshal(payload, &cursor); err != nil {
|
||||
return roomListCursor{}, xerr.New(xerr.InvalidArgument, "cursor is invalid")
|
||||
}
|
||||
if cursor.Tab != tab || cursor.Query != query || cursor.RoomID == "" {
|
||||
if cursor.Tab != tab || cursor.Query != query || cursor.CountryCode != countryCode || cursor.RoomID == "" {
|
||||
return roomListCursor{}, xerr.New(xerr.InvalidArgument, "cursor is invalid")
|
||||
}
|
||||
|
||||
@ -412,10 +430,11 @@ func decodeRoomListCursor(tab string, query string, encoded string) (roomListCur
|
||||
|
||||
// encodeRoomListCursor 把最后一条列表记录编码成下一页边界。
|
||||
// cursor 不暴露契约语义,后续调整排序字段时可以只兼容服务端解析逻辑。
|
||||
func encodeRoomListCursor(tab string, query string, entry RoomListEntry) string {
|
||||
func encodeRoomListCursor(tab string, query string, countryCode string, entry RoomListEntry) string {
|
||||
cursor := roomListCursor{
|
||||
Tab: tab,
|
||||
Query: query,
|
||||
CountryCode: countryCode,
|
||||
SortScore: entry.SortScore,
|
||||
CreatedAtMS: entry.CreatedAtMS,
|
||||
UpdatedAtMS: entry.UpdatedAtMS,
|
||||
@ -453,6 +472,7 @@ func roomListItemToProto(entry RoomListEntry) *roomv1.RoomListItem {
|
||||
SeatCount: entry.SeatCount,
|
||||
OccupiedSeatCount: entry.OccupiedSeatCount,
|
||||
VisibleRegionId: entry.VisibleRegionID,
|
||||
CountryCode: normalizeRoomCountryCode(entry.OwnerCountryCode),
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,17 +480,18 @@ func roomListEntryFromMetaAndSnapshot(meta RoomMeta, snapshot *roomv1.RoomSnapsh
|
||||
if snapshot == nil || snapshot.GetRoomId() == "" {
|
||||
// GetMyRoom 兜底路径:即使快照暂时不可用,也能用 rooms 元数据返回“有房间”的最小卡片。
|
||||
return RoomListEntry{
|
||||
AppCode: meta.AppCode,
|
||||
RoomID: meta.RoomID,
|
||||
RoomShortID: meta.RoomShortID,
|
||||
VisibleRegionID: normalizeVisibleRegionID(meta.VisibleRegionID),
|
||||
OwnerUserID: meta.OwnerUserID,
|
||||
Mode: meta.Mode,
|
||||
Status: meta.Status,
|
||||
Locked: meta.RoomPasswordHash != "",
|
||||
SeatCount: meta.SeatCount,
|
||||
CreatedAtMS: nowMS,
|
||||
UpdatedAtMS: nowMS,
|
||||
AppCode: meta.AppCode,
|
||||
RoomID: meta.RoomID,
|
||||
RoomShortID: meta.RoomShortID,
|
||||
VisibleRegionID: normalizeVisibleRegionID(meta.VisibleRegionID),
|
||||
OwnerCountryCode: "",
|
||||
OwnerUserID: meta.OwnerUserID,
|
||||
Mode: meta.Mode,
|
||||
Status: meta.Status,
|
||||
Locked: meta.RoomPasswordHash != "",
|
||||
SeatCount: meta.SeatCount,
|
||||
CreatedAtMS: nowMS,
|
||||
UpdatedAtMS: nowMS,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -148,17 +148,86 @@ func TestPinnedRoomListOrdersGlobalRegionLocalThenOtherForNew(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func createPinnedListRoom(t *testing.T, ctx context.Context, svc *roomservice.Service, roomID string, shortID string, ownerID int64, regionID int64) {
|
||||
func TestRoomListFiltersByOwnerCountry(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repository := mysqltest.NewRepository(t)
|
||||
svc := roomservice.New(roomservice.Config{
|
||||
NodeID: "node-country-filter-test",
|
||||
LeaseTTL: 10 * time.Second,
|
||||
RankLimit: 20,
|
||||
SnapshotEveryN: 1,
|
||||
}, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher())
|
||||
|
||||
createPinnedListRoom(t, ctx, svc, "room-us-low", "us-low", 3301, 9001, "US")
|
||||
createPinnedListRoom(t, ctx, svc, "room-ae", "ae", 3302, 9001, "AE")
|
||||
createPinnedListRoom(t, ctx, svc, "room-us-high", "us-high", 3303, 9001, "US")
|
||||
repository.SetRoomSortScore("room-us-low", 100)
|
||||
repository.SetRoomSortScore("room-ae", 200)
|
||||
repository.SetRoomSortScore("room-us-high", 300)
|
||||
|
||||
firstPage, err := svc.ListRooms(ctx, &roomv1.ListRoomsRequest{
|
||||
Meta: &roomv1.RequestMeta{AppCode: appcode.Default},
|
||||
ViewerUserId: 4001,
|
||||
VisibleRegionId: 9001,
|
||||
Tab: "hot",
|
||||
Limit: 1,
|
||||
CountryCode: "us",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("list country filtered first page failed: %v", err)
|
||||
}
|
||||
if len(firstPage.GetRooms()) != 1 || firstPage.GetRooms()[0].GetRoomId() != "room-us-high" || firstPage.GetRooms()[0].GetCountryCode() != "US" {
|
||||
t.Fatalf("country filter must return only matching owner country in hot order: %+v", firstPage.GetRooms())
|
||||
}
|
||||
if firstPage.GetNextCursor() == "" {
|
||||
t.Fatalf("first country page should return cursor")
|
||||
}
|
||||
|
||||
if _, err := svc.ListRooms(ctx, &roomv1.ListRoomsRequest{
|
||||
Meta: &roomv1.RequestMeta{AppCode: appcode.Default},
|
||||
ViewerUserId: 4001,
|
||||
VisibleRegionId: 9001,
|
||||
Tab: "hot",
|
||||
Limit: 1,
|
||||
CountryCode: "AE",
|
||||
Cursor: firstPage.GetNextCursor(),
|
||||
}); err == nil {
|
||||
t.Fatalf("country cursor must not be reusable across country tabs")
|
||||
}
|
||||
|
||||
secondPage, err := svc.ListRooms(ctx, &roomv1.ListRoomsRequest{
|
||||
Meta: &roomv1.RequestMeta{AppCode: appcode.Default},
|
||||
ViewerUserId: 4001,
|
||||
VisibleRegionId: 9001,
|
||||
Tab: "hot",
|
||||
Limit: 1,
|
||||
CountryCode: "US",
|
||||
Cursor: firstPage.GetNextCursor(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("list country filtered second page failed: %v", err)
|
||||
}
|
||||
if len(secondPage.GetRooms()) != 1 || secondPage.GetRooms()[0].GetRoomId() != "room-us-low" || secondPage.GetRooms()[0].GetCountryCode() != "US" {
|
||||
t.Fatalf("second country page mismatch: %+v", secondPage.GetRooms())
|
||||
}
|
||||
}
|
||||
|
||||
func createPinnedListRoom(t *testing.T, ctx context.Context, svc *roomservice.Service, roomID string, shortID string, ownerID int64, regionID int64, countryCodes ...string) {
|
||||
t.Helper()
|
||||
|
||||
ownerCountryCode := ""
|
||||
if len(countryCodes) > 0 {
|
||||
ownerCountryCode = countryCodes[0]
|
||||
}
|
||||
if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{
|
||||
Meta: roomservice.NewRequestMeta(roomID, ownerID),
|
||||
SeatCount: 10,
|
||||
Mode: "voice",
|
||||
VisibleRegionId: regionID,
|
||||
RoomName: roomID,
|
||||
RoomAvatar: testRoomCoverURL,
|
||||
RoomShortId: shortID,
|
||||
Meta: roomservice.NewRequestMeta(roomID, ownerID),
|
||||
SeatCount: 10,
|
||||
Mode: "voice",
|
||||
VisibleRegionId: regionID,
|
||||
OwnerCountryCode: ownerCountryCode,
|
||||
RoomName: roomID,
|
||||
RoomAvatar: testRoomCoverURL,
|
||||
RoomShortId: shortID,
|
||||
}); err != nil {
|
||||
t.Fatalf("create room %s failed: %v", roomID, err)
|
||||
}
|
||||
|
||||
@ -128,6 +128,8 @@ type RoomListEntry struct {
|
||||
RoomShortID string
|
||||
// VisibleRegionID 是房间自身的列表区域;公共发现列表会用它把当前区域房间排在其他区域之前。
|
||||
VisibleRegionID int64
|
||||
// OwnerCountryCode 是房主国家码;公共发现列表国家 tab 使用它做服务端筛选。
|
||||
OwnerCountryCode string
|
||||
// OwnerUserID 是房间所有者,用于卡片展示和运营排查。
|
||||
OwnerUserID int64
|
||||
// Title 是卡片标题;空值由客户端或后续资料聚合兜底。
|
||||
@ -364,6 +366,8 @@ type RoomListQuery struct {
|
||||
OwnerUserID int64
|
||||
// Query 非空时按 room_id 或 title 做包含匹配。
|
||||
Query string
|
||||
// CountryCode 非空时只返回房主国家命中的房间;gateway 必须先校验它属于当前用户区域。
|
||||
CountryCode string
|
||||
// Limit 是实际查询数量,service 层会限制最大值。
|
||||
Limit int
|
||||
// CursorSortScore 是 hot tab 的游标 score。
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
roomv1 "hyapp.local/api/proto/room/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/usermq"
|
||||
"hyapp/services/room-service/internal/room/command"
|
||||
"hyapp/services/room-service/internal/room/state"
|
||||
)
|
||||
|
||||
@ -46,10 +47,14 @@ func (s *Service) HandleUserOutboxMessage(ctx context.Context, message usermq.Us
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists || meta.Status == state.RoomStatusDeleted || meta.VisibleRegionID == payload.NewRegionID {
|
||||
if !exists || meta.Status == state.RoomStatusDeleted {
|
||||
return nil
|
||||
}
|
||||
|
||||
newCountry := normalizeRoomCountryCode(payload.NewCountry)
|
||||
if meta.VisibleRegionID == payload.NewRegionID && newCountry == "" {
|
||||
return nil
|
||||
}
|
||||
requestID := strings.TrimSpace(payload.RequestID)
|
||||
if requestID == "" {
|
||||
requestID = message.EventID
|
||||
@ -58,17 +63,25 @@ func (s *Service) HandleUserOutboxMessage(ctx context.Context, message usermq.Us
|
||||
if sentAtMS <= 0 {
|
||||
sentAtMS = message.OccurredAtMS
|
||||
}
|
||||
_, err = s.AdminUpdateRoom(ctx, &roomv1.AdminUpdateRoomRequest{
|
||||
Meta: &roomv1.RequestMeta{
|
||||
AppCode: message.AppCode,
|
||||
RequestId: requestID,
|
||||
CommandId: message.EventID,
|
||||
ActorUserId: payload.UserID,
|
||||
RoomId: meta.RoomID,
|
||||
SentAtMs: sentAtMS,
|
||||
},
|
||||
VisibleRegionId: &payload.NewRegionID,
|
||||
AdminName: "user-region-sync",
|
||||
})
|
||||
updateMeta := &roomv1.RequestMeta{
|
||||
AppCode: message.AppCode,
|
||||
RequestId: requestID,
|
||||
CommandId: message.EventID,
|
||||
ActorUserId: payload.UserID,
|
||||
RoomId: meta.RoomID,
|
||||
SentAtMs: sentAtMS,
|
||||
}
|
||||
cmd := command.AdminUpdateRoom{
|
||||
Base: baseFromMeta(updateMeta),
|
||||
AdminName: "user-region-sync",
|
||||
}
|
||||
if meta.VisibleRegionID != payload.NewRegionID {
|
||||
cmd.VisibleRegionID = &payload.NewRegionID
|
||||
}
|
||||
if newCountry != "" {
|
||||
// UserRegionChanged 同时承载国家事实;即使区域未变,也要把房主国家投影写回房间列表。
|
||||
cmd.OwnerCountryCode = &newCountry
|
||||
}
|
||||
_, err = s.applyAdminRoomMutation(ctx, cmd, cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -28,13 +28,14 @@ func TestHandleUserRegionChangedUpdatesOwnerRoomRegionIdempotently(t *testing.T)
|
||||
roomID := "room-user-region-sync"
|
||||
ownerID := int64(163212)
|
||||
if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{
|
||||
Meta: roomservice.NewRequestMeta(roomID, ownerID),
|
||||
SeatCount: 10,
|
||||
Mode: "voice",
|
||||
VisibleRegionId: 3,
|
||||
RoomName: "Region Sync Room",
|
||||
RoomAvatar: testRoomCoverURL,
|
||||
RoomShortId: "163212",
|
||||
Meta: roomservice.NewRequestMeta(roomID, ownerID),
|
||||
SeatCount: 10,
|
||||
Mode: "voice",
|
||||
VisibleRegionId: 3,
|
||||
OwnerCountryCode: "AE",
|
||||
RoomName: "Region Sync Room",
|
||||
RoomAvatar: testRoomCoverURL,
|
||||
RoomShortId: "163212",
|
||||
}); err != nil {
|
||||
t.Fatalf("create room failed: %v", err)
|
||||
}
|
||||
@ -79,9 +80,16 @@ func TestHandleUserRegionChangedUpdatesOwnerRoomRegionIdempotently(t *testing.T)
|
||||
if err != nil {
|
||||
t.Fatalf("list new region entries failed: %v", err)
|
||||
}
|
||||
if len(newRegionEntries) != 1 || newRegionEntries[0].RoomID != roomID || newRegionEntries[0].VisibleRegionID != 2 {
|
||||
if len(newRegionEntries) != 1 || newRegionEntries[0].RoomID != roomID || newRegionEntries[0].VisibleRegionID != 2 || newRegionEntries[0].OwnerCountryCode != "BD" {
|
||||
t.Fatalf("new region list projection mismatch: %+v", newRegionEntries)
|
||||
}
|
||||
countryEntries, err := repository.ListRoomListEntries(ctx, roomservice.RoomListQuery{VisibleRegionID: 2, CountryCode: "BD", Tab: "new", Limit: 10})
|
||||
if err != nil {
|
||||
t.Fatalf("list new country entries failed: %v", err)
|
||||
}
|
||||
if len(countryEntries) != 1 || countryEntries[0].RoomID != roomID || countryEntries[0].OwnerCountryCode != "BD" {
|
||||
t.Fatalf("new country list projection mismatch: %+v", countryEntries)
|
||||
}
|
||||
oldRegionEntries, err := repository.ListRoomListEntries(ctx, roomservice.RoomListQuery{VisibleRegionID: 3, Tab: "new", Limit: 10})
|
||||
if err != nil {
|
||||
t.Fatalf("list old region entries failed: %v", err)
|
||||
|
||||
@ -98,6 +98,7 @@ func (r *Repository) Migrate(ctx context.Context) error {
|
||||
room_id VARCHAR(64) NOT NULL,
|
||||
room_short_id VARCHAR(32) NOT NULL DEFAULT '',
|
||||
visible_region_id BIGINT NOT NULL DEFAULT 0,
|
||||
owner_country_code VARCHAR(3) NOT NULL DEFAULT '',
|
||||
owner_user_id BIGINT NOT NULL,
|
||||
title VARCHAR(128) NOT NULL DEFAULT '',
|
||||
cover_url VARCHAR(512) NOT NULL DEFAULT '',
|
||||
@ -119,6 +120,8 @@ func (r *Repository) Migrate(ctx context.Context) error {
|
||||
KEY idx_room_list_short_id (app_code, room_short_id),
|
||||
KEY idx_room_list_region_hot (app_code, visible_region_id, status, sort_score DESC, room_id),
|
||||
KEY idx_room_list_region_new (app_code, visible_region_id, status, created_at_ms DESC, room_id),
|
||||
KEY idx_room_list_region_country_hot (app_code, visible_region_id, owner_country_code, status, sort_score DESC, room_id),
|
||||
KEY idx_room_list_region_country_new (app_code, visible_region_id, owner_country_code, status, created_at_ms DESC, room_id),
|
||||
KEY idx_room_list_owner (app_code, owner_user_id, updated_at_ms)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
||||
`CREATE TABLE IF NOT EXISTS room_user_presence (
|
||||
@ -334,6 +337,9 @@ func (r *Repository) Migrate(ctx context.Context) error {
|
||||
if err := r.ensureRoomListLockSchema(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureRoomListCountrySchema(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureRoomPasswordSchema(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -433,6 +439,44 @@ func (r *Repository) ensureRoomListLockSchema(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) ensureRoomListCountrySchema(ctx context.Context) error {
|
||||
hasColumn, err := r.columnExists(ctx, "room_list_entries", "owner_country_code")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !hasColumn {
|
||||
// owner_country_code 是房主国家快照,只服务发现页国家筛选;历史行先为空,后续房间投影刷新会补真实值。
|
||||
if _, err := r.db.ExecContext(ctx, `ALTER TABLE room_list_entries ADD COLUMN owner_country_code VARCHAR(3) NOT NULL DEFAULT '' AFTER visible_region_id`); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
indexes := []struct {
|
||||
name string
|
||||
statement string
|
||||
}{
|
||||
{
|
||||
name: "idx_room_list_region_country_hot",
|
||||
statement: `ALTER TABLE room_list_entries ADD INDEX idx_room_list_region_country_hot (app_code, visible_region_id, owner_country_code, status, sort_score DESC, room_id)`,
|
||||
},
|
||||
{
|
||||
name: "idx_room_list_region_country_new",
|
||||
statement: `ALTER TABLE room_list_entries ADD INDEX idx_room_list_region_country_new (app_code, visible_region_id, owner_country_code, status, created_at_ms DESC, room_id)`,
|
||||
},
|
||||
}
|
||||
for _, item := range indexes {
|
||||
hasIndex, err := r.indexExists(ctx, "room_list_entries", item.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !hasIndex {
|
||||
if _, err := r.db.ExecContext(ctx, item.statement); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) ensureRoomAdminCloseSchema(ctx context.Context) error {
|
||||
columns := []struct {
|
||||
table string
|
||||
@ -1458,12 +1502,13 @@ func (r *Repository) UpsertRoomListEntry(ctx context.Context, entry roomservice.
|
||||
appCode := normalizedRecordAppCode(ctx, entry.AppCode)
|
||||
_, err := r.db.ExecContext(ctx,
|
||||
`INSERT INTO room_list_entries (
|
||||
app_code, room_id, room_short_id, visible_region_id, owner_user_id, title, cover_url, mode, status, locked,
|
||||
app_code, room_id, room_short_id, visible_region_id, owner_country_code, owner_user_id, title, cover_url, mode, status, locked,
|
||||
heat, online_count, seat_count, occupied_seat_count, sort_score, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
room_short_id = VALUES(room_short_id),
|
||||
visible_region_id = VALUES(visible_region_id),
|
||||
owner_country_code = VALUES(owner_country_code),
|
||||
owner_user_id = VALUES(owner_user_id),
|
||||
title = VALUES(title),
|
||||
cover_url = VALUES(cover_url),
|
||||
@ -1480,6 +1525,7 @@ func (r *Repository) UpsertRoomListEntry(ctx context.Context, entry roomservice.
|
||||
entry.RoomID,
|
||||
entry.RoomShortID,
|
||||
entry.VisibleRegionID,
|
||||
entry.OwnerCountryCode,
|
||||
entry.OwnerUserID,
|
||||
entry.Title,
|
||||
entry.CoverURL,
|
||||
@ -1524,6 +1570,7 @@ func (r *Repository) ListRoomListEntries(ctx context.Context, query roomservice.
|
||||
&entry.RoomID,
|
||||
&entry.RoomShortID,
|
||||
&entry.VisibleRegionID,
|
||||
&entry.OwnerCountryCode,
|
||||
&entry.OwnerUserID,
|
||||
&entry.Title,
|
||||
&entry.CoverURL,
|
||||
@ -1571,7 +1618,7 @@ func (r *Repository) ListRoomListEntriesByIDs(ctx context.Context, query roomser
|
||||
args = append(args, roomID)
|
||||
}
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT app_code, room_id, room_short_id, visible_region_id, owner_user_id, title, cover_url, mode, status, locked,
|
||||
SELECT app_code, room_id, room_short_id, visible_region_id, owner_country_code, owner_user_id, title, cover_url, mode, status, locked,
|
||||
heat, online_count, seat_count, occupied_seat_count, sort_score, created_at_ms, updated_at_ms
|
||||
FROM room_list_entries
|
||||
WHERE app_code = ? AND room_id IN (`+placeholders+`)`, args...)
|
||||
@ -1587,6 +1634,7 @@ func (r *Repository) ListRoomListEntriesByIDs(ctx context.Context, query roomser
|
||||
&entry.RoomID,
|
||||
&entry.RoomShortID,
|
||||
&entry.VisibleRegionID,
|
||||
&entry.OwnerCountryCode,
|
||||
&entry.OwnerUserID,
|
||||
&entry.Title,
|
||||
&entry.CoverURL,
|
||||
@ -1669,6 +1717,7 @@ func (r *Repository) ListRoomUserFeedEntries(ctx context.Context, query roomserv
|
||||
&entry.RoomID,
|
||||
&entry.RoomShortID,
|
||||
&entry.VisibleRegionID,
|
||||
&entry.OwnerCountryCode,
|
||||
&entry.OwnerUserID,
|
||||
&entry.Title,
|
||||
&entry.CoverURL,
|
||||
@ -1794,6 +1843,7 @@ func (r *Repository) ListRoomFollowEntries(ctx context.Context, query roomservic
|
||||
&entry.RoomID,
|
||||
&entry.RoomShortID,
|
||||
&entry.VisibleRegionID,
|
||||
&entry.OwnerCountryCode,
|
||||
&entry.OwnerUserID,
|
||||
&entry.Title,
|
||||
&entry.CoverURL,
|
||||
@ -1846,6 +1896,7 @@ func (r *Repository) ListRoomRelatedFeedEntries(ctx context.Context, query rooms
|
||||
&entry.RoomID,
|
||||
&entry.RoomShortID,
|
||||
&entry.VisibleRegionID,
|
||||
&entry.OwnerCountryCode,
|
||||
&entry.OwnerUserID,
|
||||
&entry.Title,
|
||||
&entry.CoverURL,
|
||||
@ -1889,18 +1940,18 @@ func (r *Repository) ListRoomRelatedFeedEntries(ctx context.Context, query rooms
|
||||
}
|
||||
|
||||
const roomListSelectColumns = `
|
||||
SELECT app_code, room_id, room_short_id, visible_region_id, owner_user_id, title, cover_url, mode, status, locked,
|
||||
SELECT app_code, room_id, room_short_id, visible_region_id, owner_country_code, owner_user_id, title, cover_url, mode, status, locked,
|
||||
heat, online_count, seat_count, occupied_seat_count, sort_score, created_at_ms, updated_at_ms
|
||||
FROM room_list_entries`
|
||||
|
||||
const roomUserFeedSelectColumns = `
|
||||
SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.locked,
|
||||
SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_country_code, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.locked,
|
||||
r.heat, r.online_count, r.seat_count, r.occupied_seat_count, r.sort_score, r.created_at_ms, f.updated_at_ms
|
||||
FROM room_user_feed_entries f
|
||||
JOIN room_list_entries r ON r.app_code = f.app_code AND r.room_id = f.room_id`
|
||||
|
||||
const roomFollowSelectColumns = `
|
||||
SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.locked,
|
||||
SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_country_code, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.locked,
|
||||
r.heat, r.online_count, r.seat_count, r.occupied_seat_count, r.sort_score, r.created_at_ms, f.followed_at_ms
|
||||
FROM room_follows f
|
||||
JOIN room_list_entries r ON r.app_code = f.app_code AND r.room_id = f.room_id`
|
||||
@ -1921,7 +1972,7 @@ func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
|
||||
pinWeightExpr := "CASE WHEN gp.room_id IS NOT NULL THEN gp.weight WHEN rp.room_id IS NOT NULL THEN rp.weight ELSE 0 END"
|
||||
pinExpiresExpr := "CASE WHEN gp.room_id IS NOT NULL THEN gp.expires_at_ms WHEN rp.room_id IS NOT NULL THEN rp.expires_at_ms ELSE 0 END"
|
||||
selectSQL := `
|
||||
SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.locked,
|
||||
SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_country_code, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.locked,
|
||||
r.heat, r.online_count, r.seat_count, r.occupied_seat_count, r.sort_score, r.created_at_ms, r.updated_at_ms,
|
||||
` + pinnedExpr + ` AS is_pinned, ` + pinRankExpr + ` AS pin_list_rank, ` + pinWeightExpr + ` AS pin_weight, ` + pinExpiresExpr + ` AS pinned_until_ms
|
||||
FROM room_list_entries r
|
||||
@ -1947,6 +1998,10 @@ func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
|
||||
where = append(where, "r.owner_user_id = ?")
|
||||
args = append(args, query.OwnerUserID)
|
||||
}
|
||||
if strings.TrimSpace(query.CountryCode) != "" {
|
||||
where = append(where, "r.owner_country_code = ?")
|
||||
args = append(args, strings.ToUpper(strings.TrimSpace(query.CountryCode)))
|
||||
}
|
||||
if strings.TrimSpace(query.Query) != "" {
|
||||
where = append(where, "(r.room_id LIKE ? ESCAPE '\\\\' OR r.room_short_id LIKE ? ESCAPE '\\\\' OR r.title LIKE ? ESCAPE '\\\\')")
|
||||
like := "%" + escapeRoomListLike(query.Query) + "%"
|
||||
|
||||
@ -147,6 +147,31 @@ CREATE TABLE IF NOT EXISTS user_status_change_logs (
|
||||
KEY idx_user_status_logs_request (app_code, request_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户状态变更日志表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS manager_user_blocks (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码,用于多租户隔离',
|
||||
block_id VARCHAR(96) NOT NULL COMMENT '经理封禁记录 ID',
|
||||
command_id VARCHAR(128) NOT NULL COMMENT '幂等命令 ID',
|
||||
manager_user_id BIGINT NOT NULL COMMENT '经理用户 ID',
|
||||
target_user_id BIGINT NOT NULL COMMENT '被封禁用户 ID',
|
||||
target_display_user_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '被封禁用户短 ID 快照',
|
||||
target_username VARCHAR(128) NOT NULL DEFAULT '' COMMENT '被封禁用户昵称快照',
|
||||
target_avatar VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '被封禁用户头像快照',
|
||||
country VARCHAR(16) NOT NULL DEFAULT '' COMMENT '封禁时双方国家码',
|
||||
target_old_status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '封禁前用户状态',
|
||||
blocked_until_ms BIGINT NOT NULL COMMENT '计划解封时间,UTC epoch ms',
|
||||
status VARCHAR(32) NOT NULL COMMENT 'active/released/expired',
|
||||
reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '封禁原因',
|
||||
released_reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '释放原因',
|
||||
released_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '释放时间,UTC epoch ms',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, block_id),
|
||||
UNIQUE KEY uk_manager_user_blocks_command (app_code, command_id),
|
||||
KEY idx_manager_user_blocks_manager (app_code, manager_user_id, status, created_at_ms),
|
||||
KEY idx_manager_user_blocks_target (app_code, target_user_id, status),
|
||||
KEY idx_manager_user_blocks_expire (app_code, status, blocked_until_ms)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='经理中心用户封禁记录表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_reports (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码,用于多租户隔离',
|
||||
report_id VARCHAR(96) NOT NULL COMMENT '举报单业务 ID',
|
||||
@ -506,6 +531,98 @@ CREATE TABLE IF NOT EXISTS user_outbox (
|
||||
KEY idx_user_outbox_aggregate (app_code, aggregate_type, aggregate_id, created_at_ms)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户发件箱表';
|
||||
|
||||
-- 老测试库可能已经存在 user_outbox,CREATE TABLE IF NOT EXISTS 不会补齐后续新增的 MQ 投递字段。
|
||||
-- 这里用 information_schema 生成幂等 ALTER,保证重复执行 initdb 时不会因重复列名失败。
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND COLUMN_NAME = 'worker_id') = 0,
|
||||
'ALTER TABLE user_outbox ADD COLUMN worker_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''MQ 投递 worker ID'' AFTER status',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 投递锁过期时间用于多实例 claim user_outbox,老库缺这个列时 CP 通知 worker 会直接 SQL 1054。
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND COLUMN_NAME = 'lock_until_ms') = 0,
|
||||
'ALTER TABLE user_outbox ADD COLUMN lock_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''MQ 投递锁过期时间,UTC epoch ms'' AFTER worker_id',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 重试次数和下一次重试时间跟 outbox 补偿投递扫描绑定,缺列会导致 pending 查询或失败回写不可用。
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND COLUMN_NAME = 'retry_count') = 0,
|
||||
'ALTER TABLE user_outbox ADD COLUMN retry_count INT NOT NULL DEFAULT 0 COMMENT ''重试次数'' AFTER lock_until_ms',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND COLUMN_NAME = 'next_retry_at_ms') = 0,
|
||||
'ALTER TABLE user_outbox ADD COLUMN next_retry_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''下一次 MQ 投递重试时间,UTC epoch ms'' AFTER retry_count',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 失败原因用于排查投递链路,缺列时 MarkFailed 会再次失败并掩盖真实业务错误。
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND COLUMN_NAME = 'last_error') = 0,
|
||||
'ALTER TABLE user_outbox ADD COLUMN last_error VARCHAR(512) NOT NULL DEFAULT '''' COMMENT ''最后一次失败原因'' AFTER next_retry_at_ms',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- pending 索引列顺序跟 user_outbox 扫描条件绑定;历史索引存在时先删除再按当前结构重建。
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND INDEX_NAME = 'idx_user_outbox_status_created') > 0,
|
||||
'ALTER TABLE user_outbox DROP INDEX idx_user_outbox_status_created',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @ddl := 'ALTER TABLE user_outbox ADD INDEX idx_user_outbox_status_created (app_code, status, next_retry_at_ms, created_at_ms, event_id)';
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND INDEX_NAME = 'idx_user_outbox_lock') = 0,
|
||||
'ALTER TABLE user_outbox ADD INDEX idx_user_outbox_lock (app_code, status, lock_until_ms, created_at_ms, event_id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND INDEX_NAME = 'idx_user_outbox_retention') = 0,
|
||||
'ALTER TABLE user_outbox ADD INDEX idx_user_outbox_retention (app_code, status, updated_at_ms, event_id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @ddl := IF(
|
||||
(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_outbox' AND INDEX_NAME = 'idx_user_outbox_aggregate') = 0,
|
||||
'ALTER TABLE user_outbox ADD INDEX idx_user_outbox_aggregate (app_code, aggregate_type, aggregate_id, created_at_ms)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_mic_sessions (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码,用于多租户隔离',
|
||||
mic_session_id VARCHAR(128) NOT NULL COMMENT '麦位会话 ID',
|
||||
|
||||
@ -64,18 +64,23 @@ type Application struct {
|
||||
|
||||
// Relationship 表达 A/B 已建立的一种 active 关系;展示时由 service 填充 me/partner。
|
||||
type Relationship struct {
|
||||
RelationshipID string
|
||||
RelationType string
|
||||
Status string
|
||||
UserAID int64
|
||||
UserBID int64
|
||||
Me UserProfile
|
||||
Partner UserProfile
|
||||
IntimacyValue int64
|
||||
Level int32
|
||||
SourceApplicationID string
|
||||
FormedAtMS int64
|
||||
UpdatedAtMS int64
|
||||
RelationshipID string
|
||||
RelationType string
|
||||
Status string
|
||||
UserAID int64
|
||||
UserBID int64
|
||||
Me UserProfile
|
||||
Partner UserProfile
|
||||
IntimacyValue int64
|
||||
Level int32
|
||||
CurrentLevelThreshold int64
|
||||
NextLevelThreshold int64
|
||||
NeededForNextLevel int64
|
||||
LevelProgressPercent int32
|
||||
MaxLevel bool
|
||||
SourceApplicationID string
|
||||
FormedAtMS int64
|
||||
UpdatedAtMS int64
|
||||
}
|
||||
|
||||
// GiftEvent 是 room outbox 中 RoomGiftSent 转换后的 CP 关系消费输入。
|
||||
|
||||
@ -23,6 +23,14 @@ const (
|
||||
OperatorTypeSystem = "system"
|
||||
)
|
||||
|
||||
const (
|
||||
ManagerUserBlockStatusActive = "active"
|
||||
ManagerUserBlockStatusReleased = "released"
|
||||
ManagerUserBlockStatusExpired = "expired"
|
||||
|
||||
managerUserBlockReasonPrefix = "manager_center_block:"
|
||||
)
|
||||
|
||||
// UserStatusCommand 是用户治理入口的服务层命令。
|
||||
type UserStatusCommand struct {
|
||||
AppCode string
|
||||
@ -56,6 +64,51 @@ type UserStatusResult struct {
|
||||
RoomEvictError string
|
||||
}
|
||||
|
||||
// ManagerUserBlockCommand 是经理中心封禁用户的服务层命令。
|
||||
// command_id 是 H5 写操作幂等边界,blocked_until_ms 决定 cron 何时自动解封。
|
||||
type ManagerUserBlockCommand struct {
|
||||
CommandID string
|
||||
ManagerUserID int64
|
||||
TargetUserID int64
|
||||
BlockedUntilMS int64
|
||||
Reason string
|
||||
RequestID string
|
||||
NowMS int64
|
||||
}
|
||||
|
||||
// ReleaseManagerUserBlockCommand 是手动或系统到期释放经理封禁的命令。
|
||||
type ReleaseManagerUserBlockCommand struct {
|
||||
ManagerUserID int64
|
||||
BlockID string
|
||||
Status string
|
||||
Reason string
|
||||
RequestID string
|
||||
NowMS int64
|
||||
}
|
||||
|
||||
// ManagerUserBlock 是经理封禁列表的稳定读模型。
|
||||
type ManagerUserBlock struct {
|
||||
BlockID string
|
||||
ManagerUserID int64
|
||||
TargetUserID int64
|
||||
TargetDisplayUserID string
|
||||
TargetUsername string
|
||||
TargetAvatar string
|
||||
Country string
|
||||
TargetOldStatus userdomain.Status
|
||||
BlockedUntilMS int64
|
||||
Status string
|
||||
Reason string
|
||||
CreatedAtMS int64
|
||||
UpdatedAtMS int64
|
||||
}
|
||||
|
||||
// ManagerUserBlockRelease 带上是否需要恢复 users.status,避免释放记录时误放仍被其他经理封禁的用户。
|
||||
type ManagerUserBlockRelease struct {
|
||||
Block ManagerUserBlock
|
||||
ShouldRestore bool
|
||||
}
|
||||
|
||||
// SetUserStatus 是封禁、停用和恢复用户的通用用例入口。
|
||||
// 非 active 状态会先提交用户状态和 session 吊销事实,再执行 Redis/IM/Room 的可重试副作用。
|
||||
func (s *Service) SetUserStatus(ctx context.Context, command UserStatusCommand) (UserStatusResult, error) {
|
||||
@ -99,6 +152,154 @@ func (s *Service) SetUserStatus(ctx context.Context, command UserStatusCommand)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CreateManagerUserBlock 创建经理封禁记录并把目标用户状态置为 banned。
|
||||
// 国家和 active 状态在 service 层校验,保证任何 gateway/H5 入口都不能跨国家或重复封禁非 active 用户。
|
||||
func (s *Service) CreateManagerUserBlock(ctx context.Context, command ManagerUserBlockCommand) (ManagerUserBlock, UserStatusResult, error) {
|
||||
if s.userRepository == nil || s.moderationRepository == nil {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, xerr.New(xerr.Unavailable, "user repository is not configured")
|
||||
}
|
||||
command.CommandID = strings.TrimSpace(command.CommandID)
|
||||
command.Reason = strings.TrimSpace(command.Reason)
|
||||
if command.CommandID == "" || command.ManagerUserID <= 0 || command.TargetUserID <= 0 || command.BlockedUntilMS <= 0 {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, xerr.New(xerr.InvalidArgument, "manager block command is incomplete")
|
||||
}
|
||||
if command.NowMS <= 0 {
|
||||
command.NowMS = s.now().UTC().UnixMilli()
|
||||
}
|
||||
if command.BlockedUntilMS <= command.NowMS {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, xerr.New(xerr.InvalidArgument, "blocked_until_ms must be in the future")
|
||||
}
|
||||
if command.Reason == "" {
|
||||
command.Reason = "manager_center"
|
||||
}
|
||||
manager, err := s.userRepository.GetUser(ctx, command.ManagerUserID)
|
||||
if err != nil {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, err
|
||||
}
|
||||
target, err := s.userRepository.GetUser(ctx, command.TargetUserID)
|
||||
if err != nil {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, err
|
||||
}
|
||||
if manager.Country == "" || target.Country == "" || !strings.EqualFold(manager.Country, target.Country) {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, xerr.New(xerr.PermissionDenied, "target user is outside manager country")
|
||||
}
|
||||
if target.Status != userdomain.StatusActive {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, xerr.New(xerr.InvalidArgument, "target user is not active")
|
||||
}
|
||||
block, err := s.moderationRepository.CreateManagerUserBlock(ctx, command, target)
|
||||
if err != nil {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, err
|
||||
}
|
||||
status, err := s.SetUserStatus(ctx, UserStatusCommand{
|
||||
AppCode: appcode.FromContext(ctx),
|
||||
TargetUserID: command.TargetUserID,
|
||||
Status: userdomain.StatusBanned,
|
||||
OperatorType: OperatorTypeAppUser,
|
||||
OperatorUserID: command.ManagerUserID,
|
||||
Reason: managerUserBlockReasonPrefix + block.BlockID,
|
||||
RequestID: command.RequestID,
|
||||
NowMs: command.NowMS,
|
||||
})
|
||||
if err != nil {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, err
|
||||
}
|
||||
return block, status, nil
|
||||
}
|
||||
|
||||
func (s *Service) ListManagerUserBlocks(ctx context.Context, managerUserID int64, status string, pageSize int32) ([]ManagerUserBlock, error) {
|
||||
if s.moderationRepository == nil {
|
||||
return nil, xerr.New(xerr.Unavailable, "moderation repository is not configured")
|
||||
}
|
||||
if managerUserID <= 0 {
|
||||
return nil, xerr.New(xerr.InvalidArgument, "manager_user_id is required")
|
||||
}
|
||||
status = normalizeManagerBlockStatus(status)
|
||||
if status == "" {
|
||||
status = ManagerUserBlockStatusActive
|
||||
}
|
||||
if pageSize <= 0 || pageSize > 100 {
|
||||
pageSize = 50
|
||||
}
|
||||
return s.moderationRepository.ListManagerUserBlocks(ctx, managerUserID, status, pageSize)
|
||||
}
|
||||
|
||||
func (s *Service) UnblockManagerUser(ctx context.Context, command ReleaseManagerUserBlockCommand) (ManagerUserBlock, UserStatusResult, error) {
|
||||
command.Status = ManagerUserBlockStatusReleased
|
||||
return s.releaseManagerUserBlock(ctx, command, OperatorTypeAppUser)
|
||||
}
|
||||
|
||||
func (s *Service) ExpireManagerUserBlocks(ctx context.Context, limit int32) (int, error) {
|
||||
if s.moderationRepository == nil {
|
||||
return 0, xerr.New(xerr.Unavailable, "moderation repository is not configured")
|
||||
}
|
||||
if limit <= 0 || limit > 500 {
|
||||
limit = 100
|
||||
}
|
||||
nowMS := s.now().UTC().UnixMilli()
|
||||
releases, err := s.moderationRepository.ExpireManagerUserBlocks(ctx, nowMS, limit)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, release := range releases {
|
||||
if !release.ShouldRestore {
|
||||
// 释放封禁记录不等于一定恢复用户;仍有其他经理封禁或最后一次 ban 不是经理封禁时必须保持 banned。
|
||||
continue
|
||||
}
|
||||
if _, err := s.SetUserStatus(ctx, UserStatusCommand{
|
||||
AppCode: appcode.FromContext(ctx),
|
||||
TargetUserID: release.Block.TargetUserID,
|
||||
Status: userdomain.StatusActive,
|
||||
OperatorType: OperatorTypeSystem,
|
||||
OperatorUserID: 0,
|
||||
Reason: "manager_center_block_expired:" + release.Block.BlockID,
|
||||
RequestID: "manager_block_expire:" + release.Block.BlockID,
|
||||
NowMs: nowMS,
|
||||
}); err != nil {
|
||||
return len(releases), err
|
||||
}
|
||||
}
|
||||
return len(releases), nil
|
||||
}
|
||||
|
||||
func (s *Service) releaseManagerUserBlock(ctx context.Context, command ReleaseManagerUserBlockCommand, operatorType string) (ManagerUserBlock, UserStatusResult, error) {
|
||||
if s.moderationRepository == nil {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, xerr.New(xerr.Unavailable, "moderation repository is not configured")
|
||||
}
|
||||
command.BlockID = strings.TrimSpace(command.BlockID)
|
||||
command.Reason = strings.TrimSpace(command.Reason)
|
||||
if command.ManagerUserID <= 0 || command.BlockID == "" {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, xerr.New(xerr.InvalidArgument, "manager unblock command is incomplete")
|
||||
}
|
||||
if command.NowMS <= 0 {
|
||||
command.NowMS = s.now().UTC().UnixMilli()
|
||||
}
|
||||
if command.Reason == "" {
|
||||
command.Reason = "manager_center_unblock"
|
||||
}
|
||||
release, err := s.moderationRepository.ReleaseManagerUserBlock(ctx, command)
|
||||
if err != nil {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, err
|
||||
}
|
||||
if !release.ShouldRestore {
|
||||
// repository 已判断能否安全恢复;这里不能盲目 SetUserStatus(active),否则会覆盖后台封禁或并发经理封禁。
|
||||
return release.Block, UserStatusResult{}, nil
|
||||
}
|
||||
status, err := s.SetUserStatus(ctx, UserStatusCommand{
|
||||
AppCode: appcode.FromContext(ctx),
|
||||
TargetUserID: release.Block.TargetUserID,
|
||||
Status: userdomain.StatusActive,
|
||||
OperatorType: operatorType,
|
||||
OperatorUserID: command.ManagerUserID,
|
||||
Reason: "manager_center_unblock:" + release.Block.BlockID,
|
||||
RequestID: command.RequestID,
|
||||
NowMs: command.NowMS,
|
||||
})
|
||||
if err != nil {
|
||||
return ManagerUserBlock{}, UserStatusResult{}, err
|
||||
}
|
||||
return release.Block, status, nil
|
||||
}
|
||||
|
||||
func (s *Service) writeSessionDenylist(ctx context.Context, command UserStatusCommand, sessionIDs []string, reason string) (bool, string) {
|
||||
if len(sessionIDs) == 0 {
|
||||
return true, ""
|
||||
@ -187,6 +388,16 @@ func normalizeOperatorType(operatorType string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeManagerBlockStatus(status string) string {
|
||||
status = strings.ToLower(strings.TrimSpace(status))
|
||||
switch status {
|
||||
case ManagerUserBlockStatusActive, ManagerUserBlockStatusReleased, ManagerUserBlockStatusExpired:
|
||||
return status
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeModerationReason(reason string, status userdomain.Status) string {
|
||||
reason = strings.TrimSpace(reason)
|
||||
if reason != "" {
|
||||
|
||||
@ -117,6 +117,33 @@ func (r *fakeModerationRepository) SetUserStatus(_ context.Context, command User
|
||||
return UserStatusPersistenceResult{User: r.user, RevokedSessionIDs: append([]string{}, r.sessionIDs...)}, nil
|
||||
}
|
||||
|
||||
func (r *fakeModerationRepository) CreateManagerUserBlock(_ context.Context, command ManagerUserBlockCommand, target userdomain.User) (ManagerUserBlock, error) {
|
||||
return ManagerUserBlock{
|
||||
BlockID: "block-1",
|
||||
ManagerUserID: command.ManagerUserID,
|
||||
TargetUserID: command.TargetUserID,
|
||||
TargetDisplayUserID: target.CurrentDisplayUserID,
|
||||
TargetUsername: target.Username,
|
||||
TargetAvatar: target.Avatar,
|
||||
Country: target.Country,
|
||||
BlockedUntilMS: command.BlockedUntilMS,
|
||||
Status: ManagerUserBlockStatusActive,
|
||||
Reason: command.Reason,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *fakeModerationRepository) ListManagerUserBlocks(context.Context, int64, string, int32) ([]ManagerUserBlock, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *fakeModerationRepository) ReleaseManagerUserBlock(context.Context, ReleaseManagerUserBlockCommand) (ManagerUserBlockRelease, error) {
|
||||
return ManagerUserBlockRelease{}, nil
|
||||
}
|
||||
|
||||
func (r *fakeModerationRepository) ExpireManagerUserBlocks(context.Context, int64, int32) ([]ManagerUserBlockRelease, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *fakeModerationRepository) GetUser(context.Context, int64) (userdomain.User, error) {
|
||||
return r.user, nil
|
||||
}
|
||||
|
||||
@ -126,6 +126,10 @@ type DeviceRepository interface {
|
||||
// ModerationRepository 持有用户状态和认证 session 的同库事务。
|
||||
type ModerationRepository interface {
|
||||
SetUserStatus(ctx context.Context, command UserStatusCommand) (UserStatusPersistenceResult, error)
|
||||
CreateManagerUserBlock(ctx context.Context, command ManagerUserBlockCommand, target userdomain.User) (ManagerUserBlock, error)
|
||||
ListManagerUserBlocks(ctx context.Context, managerUserID int64, status string, pageSize int32) ([]ManagerUserBlock, error)
|
||||
ReleaseManagerUserBlock(ctx context.Context, command ReleaseManagerUserBlockCommand) (ManagerUserBlockRelease, error)
|
||||
ExpireManagerUserBlocks(ctx context.Context, nowMS int64, limit int32) ([]ManagerUserBlockRelease, error)
|
||||
}
|
||||
|
||||
// SessionDenylist 写入 gateway access token 快速拒绝缓存。
|
||||
|
||||
@ -445,10 +445,30 @@ func assertPendingApplication(application cpdomain.Application, nowMs int64) err
|
||||
|
||||
func relationshipSelectSQL(suffix string) string {
|
||||
// viewerUserID 连续出现两次:me 投影和 partner 选择都必须以当前查看用户为准。
|
||||
// 等级阈值也在查询时投影出来,客户端资料卡只能使用服务端计算后的进度,不能读取后台配置或硬编码等级表。
|
||||
return `
|
||||
SELECT
|
||||
r.relationship_id, r.relation_type, r.status, r.user_a_id, r.user_b_id,
|
||||
r.intimacy_value, r.level_no, r.source_application_id, r.formed_at_ms, r.updated_at_ms,
|
||||
COALESCE((
|
||||
SELECT current_rule.intimacy_threshold
|
||||
FROM user_cp_level_rules current_rule
|
||||
WHERE current_rule.app_code = r.app_code
|
||||
AND current_rule.relation_type = r.relation_type
|
||||
AND current_rule.level_no = r.level_no
|
||||
AND current_rule.status = 'active'
|
||||
LIMIT 1
|
||||
), 0) AS current_level_threshold,
|
||||
COALESCE((
|
||||
SELECT next_rule.intimacy_threshold
|
||||
FROM user_cp_level_rules next_rule
|
||||
WHERE next_rule.app_code = r.app_code
|
||||
AND next_rule.relation_type = r.relation_type
|
||||
AND next_rule.level_no > r.level_no
|
||||
AND next_rule.status = 'active'
|
||||
ORDER BY next_rule.level_no ASC
|
||||
LIMIT 1
|
||||
), 0) AS next_level_threshold,
|
||||
me.user_id, COALESCE(me.current_display_user_id, ''), COALESCE(me.username, ''), COALESCE(me.avatar, ''),
|
||||
partner.user_id, COALESCE(partner.current_display_user_id, ''), COALESCE(partner.username, ''), COALESCE(partner.avatar, '')
|
||||
FROM user_cp_relationships r
|
||||
@ -475,12 +495,52 @@ func scanRelationship(scanner interface{ Scan(dest ...any) error }) (cpdomain.Re
|
||||
err := scanner.Scan(
|
||||
&relationship.RelationshipID, &relationship.RelationType, &relationship.Status, &relationship.UserAID, &relationship.UserBID,
|
||||
&relationship.IntimacyValue, &relationship.Level, &relationship.SourceApplicationID, &relationship.FormedAtMS, &relationship.UpdatedAtMS,
|
||||
&relationship.CurrentLevelThreshold, &relationship.NextLevelThreshold,
|
||||
&relationship.Me.UserID, &relationship.Me.DisplayUserID, &relationship.Me.Username, &relationship.Me.Avatar,
|
||||
&relationship.Partner.UserID, &relationship.Partner.DisplayUserID, &relationship.Partner.Username, &relationship.Partner.Avatar,
|
||||
)
|
||||
if err == nil {
|
||||
applyRelationshipLevelProgress(&relationship)
|
||||
}
|
||||
return relationship, err
|
||||
}
|
||||
|
||||
func applyRelationshipLevelProgress(relationship *cpdomain.Relationship) {
|
||||
if relationship == nil {
|
||||
return
|
||||
}
|
||||
if relationship.CurrentLevelThreshold < 0 {
|
||||
relationship.CurrentLevelThreshold = 0
|
||||
}
|
||||
if relationship.NextLevelThreshold <= relationship.CurrentLevelThreshold {
|
||||
// 没有下一等级规则时按满级处理;客户端可以直接隐藏“距离下一级”和进度条。
|
||||
relationship.NextLevelThreshold = 0
|
||||
relationship.NeededForNextLevel = 0
|
||||
relationship.LevelProgressPercent = 100
|
||||
relationship.MaxLevel = true
|
||||
return
|
||||
}
|
||||
remaining := relationship.NextLevelThreshold - relationship.IntimacyValue
|
||||
if remaining < 0 {
|
||||
remaining = 0
|
||||
}
|
||||
relationship.NeededForNextLevel = remaining
|
||||
span := relationship.NextLevelThreshold - relationship.CurrentLevelThreshold
|
||||
filled := relationship.IntimacyValue - relationship.CurrentLevelThreshold
|
||||
if filled < 0 {
|
||||
filled = 0
|
||||
}
|
||||
progress := int32((filled * 100) / span)
|
||||
if progress < 0 {
|
||||
progress = 0
|
||||
}
|
||||
if progress > 100 {
|
||||
progress = 100
|
||||
}
|
||||
relationship.LevelProgressPercent = progress
|
||||
relationship.MaxLevel = false
|
||||
}
|
||||
|
||||
func queryRelationshipByIDTx(ctx context.Context, tx *sql.Tx, appCode string, viewerUserID int64, relationshipID string) (cpdomain.Relationship, error) {
|
||||
row := tx.QueryRowContext(ctx, relationshipSelectSQL(`
|
||||
WHERE r.app_code = ? AND r.relationship_id = ?`),
|
||||
|
||||
@ -114,6 +114,41 @@ func TestAcceptApplicationKeepsCPHardLimit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRelationshipsIncludesServerLevelProgress(t *testing.T) {
|
||||
schema := mysqlschema.New(t)
|
||||
repo := New(schema.DB)
|
||||
ctx := appcode.WithContext(context.Background(), appcode.Default)
|
||||
nowMS := int64(1700000000000)
|
||||
|
||||
for _, userID := range []int64{4001, 4002, 4003} {
|
||||
seedCPTestUser(t, schema.DB, userID, fmt.Sprintf("Progress %d", userID), nowMS)
|
||||
}
|
||||
seedCPLevelRules(t, schema.DB, cpdomain.RelationTypeBrother, []int64{0, 100, 300, 600, 1000}, nowMS)
|
||||
seedActiveCPRelationship(t, schema.DB, "progress_mid", cpdomain.RelationTypeBrother, 4001, 4002, 180, 2, nowMS)
|
||||
seedActiveCPRelationship(t, schema.DB, "progress_max", cpdomain.RelationTypeBrother, 4001, 4003, 1200, 5, nowMS+1)
|
||||
|
||||
relationships, total, err := repo.ListRelationships(ctx, 4001, cpdomain.RelationTypeBrother, 1, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("list relationships failed: %v", err)
|
||||
}
|
||||
if total != 2 || len(relationships) != 2 {
|
||||
t.Fatalf("expected two relationships, total=%d len=%d", total, len(relationships))
|
||||
}
|
||||
|
||||
byID := map[string]cpdomain.Relationship{}
|
||||
for _, relationship := range relationships {
|
||||
byID[relationship.RelationshipID] = relationship
|
||||
}
|
||||
mid := byID["progress_mid"]
|
||||
if mid.CurrentLevelThreshold != 100 || mid.NextLevelThreshold != 300 || mid.NeededForNextLevel != 120 || mid.LevelProgressPercent != 40 || mid.MaxLevel {
|
||||
t.Fatalf("mid-level progress mismatch: %+v", mid)
|
||||
}
|
||||
max := byID["progress_max"]
|
||||
if max.CurrentLevelThreshold != 1000 || max.NextLevelThreshold != 0 || max.NeededForNextLevel != 0 || max.LevelProgressPercent != 100 || !max.MaxLevel {
|
||||
t.Fatalf("max-level progress mismatch: %+v", max)
|
||||
}
|
||||
}
|
||||
|
||||
func seedCPTestUser(t testing.TB, db *sql.DB, userID int64, username string, nowMS int64) {
|
||||
t.Helper()
|
||||
|
||||
@ -149,6 +184,46 @@ func seedRelationConfig(t testing.TB, db *sql.DB, relationType string, maxCount
|
||||
}
|
||||
}
|
||||
|
||||
func seedCPLevelRules(t testing.TB, db *sql.DB, relationType string, thresholds []int64, nowMS int64) {
|
||||
t.Helper()
|
||||
|
||||
for index, threshold := range thresholds {
|
||||
level := int32(index + 1)
|
||||
// 测试直接写等级阈值表,验证关系查询返回的是服务端配置结果,而不是客户端或测试本地推导结果。
|
||||
if _, err := db.ExecContext(context.Background(), `
|
||||
INSERT INTO user_cp_level_rules (
|
||||
app_code, relation_type, level_no, intimacy_threshold,
|
||||
reward_resource_group_id, level_icon_url, status, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, 0, '', 'active', ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
intimacy_threshold = VALUES(intimacy_threshold),
|
||||
status = VALUES(status),
|
||||
updated_at_ms = VALUES(updated_at_ms)`,
|
||||
appcode.Default, relationType, level, threshold, nowMS, nowMS,
|
||||
); err != nil {
|
||||
t.Fatalf("seed cp level rule %s/%d failed: %v", relationType, level, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func seedActiveCPRelationship(t testing.TB, db *sql.DB, relationshipID string, relationType string, userAID int64, userBID int64, intimacy int64, level int32, nowMS int64) {
|
||||
t.Helper()
|
||||
|
||||
firstUserID, secondUserID := orderedPair(userAID, userBID)
|
||||
// active 关系事实只保存当前等级和亲密值;当前/下一阈值必须由查询时读取等级规则计算。
|
||||
if _, err := db.ExecContext(context.Background(), `
|
||||
INSERT INTO user_cp_relationships (
|
||||
app_code, relationship_id, user_a_id, user_b_id, relation_type, status,
|
||||
intimacy_value, level_no, source_application_id,
|
||||
formed_at_ms, ended_at_ms, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, '', ?, 0, ?, ?)`,
|
||||
appcode.Default, relationshipID, firstUserID, secondUserID, relationType, cpdomain.RelationshipStatusActive,
|
||||
intimacy, level, nowMS, nowMS, nowMS,
|
||||
); err != nil {
|
||||
t.Fatalf("seed active cp relationship %s failed: %v", relationshipID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func seedPendingCPApplication(t testing.TB, db *sql.DB, applicationID string, relationType string, requesterUserID int64, targetUserID int64, nowMS int64) {
|
||||
t.Helper()
|
||||
|
||||
|
||||
@ -3,8 +3,11 @@ package user
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/idgen"
|
||||
"hyapp/pkg/xerr"
|
||||
userdomain "hyapp/services/user-service/internal/domain/user"
|
||||
userservice "hyapp/services/user-service/internal/service/user"
|
||||
@ -115,3 +118,253 @@ func revokedBy(operatorUserID int64) string {
|
||||
}
|
||||
return "user_status"
|
||||
}
|
||||
|
||||
// CreateManagerUserBlock 写入经理封禁记录;用户主状态修改由 service 层随后调用 SetUserStatus 完成。
|
||||
func (r *Repository) CreateManagerUserBlock(ctx context.Context, command userservice.ManagerUserBlockCommand, target userdomain.User) (userservice.ManagerUserBlock, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return userservice.ManagerUserBlock{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
appCode := appcode.FromContext(ctx)
|
||||
blockID := idgen.New("mblock")
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
INSERT INTO manager_user_blocks (
|
||||
app_code, block_id, command_id, manager_user_id, target_user_id,
|
||||
target_display_user_id, target_username, target_avatar, country, target_old_status,
|
||||
blocked_until_ms, status, reason, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', ?, ?, ?)`,
|
||||
appCode, blockID, command.CommandID, command.ManagerUserID, command.TargetUserID,
|
||||
target.CurrentDisplayUserID, target.Username, target.Avatar, target.Country, string(target.Status),
|
||||
command.BlockedUntilMS, command.Reason, command.NowMS, command.NowMS,
|
||||
)
|
||||
if err != nil {
|
||||
if managerBlockDuplicate(err) {
|
||||
return r.getManagerUserBlockByCommand(ctx, command.CommandID)
|
||||
}
|
||||
return userservice.ManagerUserBlock{}, err
|
||||
}
|
||||
return r.getManagerUserBlock(ctx, blockID)
|
||||
}
|
||||
|
||||
func (r *Repository) ListManagerUserBlocks(ctx context.Context, managerUserID int64, status string, pageSize int32) ([]userservice.ManagerUserBlock, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
rows, err := r.db.QueryContext(ctx, managerBlockSelectSQL()+`
|
||||
WHERE app_code = ? AND manager_user_id = ? AND status = ?
|
||||
ORDER BY created_at_ms DESC, block_id DESC
|
||||
LIMIT ?`,
|
||||
appcode.FromContext(ctx), managerUserID, status, pageSize,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
return scanManagerUserBlocks(rows)
|
||||
}
|
||||
|
||||
func (r *Repository) ReleaseManagerUserBlock(ctx context.Context, command userservice.ReleaseManagerUserBlockCommand) (userservice.ManagerUserBlockRelease, error) {
|
||||
return r.releaseManagerUserBlock(ctx, command.BlockID, command.ManagerUserID, command.Status, command.Reason, command.NowMS)
|
||||
}
|
||||
|
||||
func (r *Repository) ExpireManagerUserBlocks(ctx context.Context, nowMS int64, limit int32) ([]userservice.ManagerUserBlockRelease, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT block_id, manager_user_id
|
||||
FROM manager_user_blocks
|
||||
WHERE app_code = ? AND status = 'active' AND blocked_until_ms <= ?
|
||||
ORDER BY blocked_until_ms ASC, block_id ASC
|
||||
LIMIT ?`,
|
||||
appcode.FromContext(ctx), nowMS, limit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pending := make([]struct {
|
||||
blockID string
|
||||
managerUserID int64
|
||||
}, 0)
|
||||
for rows.Next() {
|
||||
var item struct {
|
||||
blockID string
|
||||
managerUserID int64
|
||||
}
|
||||
if err := rows.Scan(&item.blockID, &item.managerUserID); err != nil {
|
||||
_ = rows.Close()
|
||||
return nil, err
|
||||
}
|
||||
pending = append(pending, item)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
releases := make([]userservice.ManagerUserBlockRelease, 0, len(pending))
|
||||
for _, item := range pending {
|
||||
// 逐条释放而不是批量 UPDATE,是为了给每个目标用户单独计算是否还存在其他 active 经理封禁。
|
||||
release, err := r.releaseManagerUserBlock(ctx, item.blockID, item.managerUserID, userservice.ManagerUserBlockStatusExpired, "manager_center_block_expired", nowMS)
|
||||
if err != nil {
|
||||
return releases, err
|
||||
}
|
||||
releases = append(releases, release)
|
||||
}
|
||||
return releases, nil
|
||||
}
|
||||
|
||||
func (r *Repository) releaseManagerUserBlock(ctx context.Context, blockID string, managerUserID int64, status string, reason string, nowMS int64) (userservice.ManagerUserBlockRelease, error) {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return userservice.ManagerUserBlockRelease{}, err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
block, err := r.getManagerUserBlockForUpdate(ctx, tx, blockID, managerUserID)
|
||||
if err != nil {
|
||||
return userservice.ManagerUserBlockRelease{}, err
|
||||
}
|
||||
if block.Status != userservice.ManagerUserBlockStatusActive {
|
||||
if err := tx.Commit(); err != nil {
|
||||
return userservice.ManagerUserBlockRelease{}, err
|
||||
}
|
||||
return userservice.ManagerUserBlockRelease{Block: block}, nil
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
UPDATE manager_user_blocks
|
||||
SET status = ?, released_reason = ?, released_at_ms = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND block_id = ?`,
|
||||
status, reason, nowMS, nowMS, appcode.FromContext(ctx), blockID,
|
||||
)
|
||||
if err != nil {
|
||||
return userservice.ManagerUserBlockRelease{}, err
|
||||
}
|
||||
block.Status = status
|
||||
block.UpdatedAtMS = nowMS
|
||||
activeCount, err := r.countActiveManagerBlocks(ctx, tx, block.TargetUserID)
|
||||
if err != nil {
|
||||
return userservice.ManagerUserBlockRelease{}, err
|
||||
}
|
||||
// 只在“没有其他经理封禁 + 原状态是 active + 最近一次 ban 由经理封禁写入”时恢复,避免误解后台封禁。
|
||||
latestManagerBan, err := r.latestBanBelongsToManagerBlock(ctx, tx, block.TargetUserID)
|
||||
if err != nil {
|
||||
return userservice.ManagerUserBlockRelease{}, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return userservice.ManagerUserBlockRelease{}, err
|
||||
}
|
||||
return userservice.ManagerUserBlockRelease{
|
||||
Block: block,
|
||||
ShouldRestore: activeCount == 0 && block.TargetOldStatus == userdomain.StatusActive && latestManagerBan,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) getManagerUserBlock(ctx context.Context, blockID string) (userservice.ManagerUserBlock, error) {
|
||||
row := r.db.QueryRowContext(ctx, managerBlockSelectSQL()+`WHERE app_code = ? AND block_id = ?`, appcode.FromContext(ctx), blockID)
|
||||
return scanManagerUserBlock(row)
|
||||
}
|
||||
|
||||
func (r *Repository) getManagerUserBlockByCommand(ctx context.Context, commandID string) (userservice.ManagerUserBlock, error) {
|
||||
row := r.db.QueryRowContext(ctx, managerBlockSelectSQL()+`WHERE app_code = ? AND command_id = ?`, appcode.FromContext(ctx), commandID)
|
||||
return scanManagerUserBlock(row)
|
||||
}
|
||||
|
||||
func (r *Repository) getManagerUserBlockForUpdate(ctx context.Context, tx *sql.Tx, blockID string, managerUserID int64) (userservice.ManagerUserBlock, error) {
|
||||
row := tx.QueryRowContext(ctx, managerBlockSelectSQL()+`
|
||||
WHERE app_code = ? AND block_id = ? AND manager_user_id = ?
|
||||
FOR UPDATE`,
|
||||
appcode.FromContext(ctx), blockID, managerUserID,
|
||||
)
|
||||
return scanManagerUserBlock(row)
|
||||
}
|
||||
|
||||
func (r *Repository) countActiveManagerBlocks(ctx context.Context, tx *sql.Tx, targetUserID int64) (int64, error) {
|
||||
var count int64
|
||||
err := tx.QueryRowContext(ctx, `
|
||||
SELECT COUNT(*)
|
||||
FROM manager_user_blocks
|
||||
WHERE app_code = ? AND target_user_id = ? AND status = 'active'`,
|
||||
appcode.FromContext(ctx), targetUserID,
|
||||
).Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
func (r *Repository) latestBanBelongsToManagerBlock(ctx context.Context, tx *sql.Tx, targetUserID int64) (bool, error) {
|
||||
var reason string
|
||||
err := tx.QueryRowContext(ctx, `
|
||||
SELECT reason
|
||||
FROM user_status_change_logs
|
||||
WHERE app_code = ? AND target_user_id = ? AND new_status = 'banned'
|
||||
ORDER BY created_at_ms DESC, id DESC
|
||||
LIMIT 1`,
|
||||
appcode.FromContext(ctx), targetUserID,
|
||||
).Scan(&reason)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return strings.HasPrefix(reason, "manager_center_block:"), nil
|
||||
}
|
||||
|
||||
func managerBlockSelectSQL() string {
|
||||
return `
|
||||
SELECT block_id, manager_user_id, target_user_id, target_display_user_id,
|
||||
target_username, target_avatar, country, target_old_status, blocked_until_ms,
|
||||
status, reason, created_at_ms, updated_at_ms
|
||||
FROM manager_user_blocks
|
||||
`
|
||||
}
|
||||
|
||||
func scanManagerUserBlocks(rows *sql.Rows) ([]userservice.ManagerUserBlock, error) {
|
||||
items := make([]userservice.ManagerUserBlock, 0)
|
||||
for rows.Next() {
|
||||
item, err := scanManagerUserBlockRows(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
return items, rows.Err()
|
||||
}
|
||||
|
||||
type managerBlockScanner interface {
|
||||
Scan(dest ...any) error
|
||||
}
|
||||
|
||||
func scanManagerUserBlock(row managerBlockScanner) (userservice.ManagerUserBlock, error) {
|
||||
item, err := scanManagerUserBlockRows(row)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return userservice.ManagerUserBlock{}, xerr.New(xerr.NotFound, "manager block not found")
|
||||
}
|
||||
return item, err
|
||||
}
|
||||
|
||||
func scanManagerUserBlockRows(row managerBlockScanner) (userservice.ManagerUserBlock, error) {
|
||||
var item userservice.ManagerUserBlock
|
||||
var oldStatus string
|
||||
if err := row.Scan(
|
||||
&item.BlockID,
|
||||
&item.ManagerUserID,
|
||||
&item.TargetUserID,
|
||||
&item.TargetDisplayUserID,
|
||||
&item.TargetUsername,
|
||||
&item.TargetAvatar,
|
||||
&item.Country,
|
||||
&oldStatus,
|
||||
&item.BlockedUntilMS,
|
||||
&item.Status,
|
||||
&item.Reason,
|
||||
&item.CreatedAtMS,
|
||||
&item.UpdatedAtMS,
|
||||
); err != nil {
|
||||
return userservice.ManagerUserBlock{}, err
|
||||
}
|
||||
item.TargetOldStatus = userdomain.Status(oldStatus)
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func managerBlockDuplicate(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(err.Error(), "Duplicate entry") || strings.Contains(err.Error(), "Error 1062")
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
mictimedomain "hyapp/services/user-service/internal/domain/mictime"
|
||||
userdomain "hyapp/services/user-service/internal/domain/user"
|
||||
authservice "hyapp/services/user-service/internal/service/auth"
|
||||
userservice "hyapp/services/user-service/internal/service/user"
|
||||
)
|
||||
|
||||
// toProtoApp 把 App 注册表事实转换为 protobuf 投影。
|
||||
@ -93,6 +94,24 @@ func toProtoBusinessUserLookupItem(item userdomain.BusinessUserLookupItem) *user
|
||||
}
|
||||
}
|
||||
|
||||
func toProtoManagerUserBlock(block userservice.ManagerUserBlock) *userv1.ManagerUserBlock {
|
||||
// 经理封禁记录是 H5 弹窗的列表数据;这里仅暴露可展示和可操作的稳定字段。
|
||||
return &userv1.ManagerUserBlock{
|
||||
BlockId: block.BlockID,
|
||||
ManagerUserId: block.ManagerUserID,
|
||||
TargetUserId: block.TargetUserID,
|
||||
TargetDisplayUserId: block.TargetDisplayUserID,
|
||||
TargetUsername: block.TargetUsername,
|
||||
TargetAvatar: block.TargetAvatar,
|
||||
Country: block.Country,
|
||||
BlockedUntilMs: block.BlockedUntilMS,
|
||||
Status: block.Status,
|
||||
Reason: block.Reason,
|
||||
CreatedAtMs: block.CreatedAtMS,
|
||||
UpdatedAtMs: block.UpdatedAtMS,
|
||||
}
|
||||
}
|
||||
|
||||
func toProtoInviteOverview(overview invitedomain.Overview) *userv1.InviteOverview {
|
||||
if overview.MyInviteCode == "" && !overview.InviteEnabled && overview.InviteCount == 0 && overview.ValidInviteCount == 0 && overview.ValidInviteThresholdCoin == 0 {
|
||||
return nil
|
||||
|
||||
@ -140,15 +140,20 @@ func toProtoCPRelationship(relationship cpdomain.Relationship) *userv1.CPRelatio
|
||||
return nil
|
||||
}
|
||||
return &userv1.CPRelationship{
|
||||
RelationshipId: relationship.RelationshipID,
|
||||
RelationType: relationship.RelationType,
|
||||
Status: relationship.Status,
|
||||
Me: toProtoCPUserProfile(relationship.Me),
|
||||
Partner: toProtoCPUserProfile(relationship.Partner),
|
||||
IntimacyValue: relationship.IntimacyValue,
|
||||
Level: relationship.Level,
|
||||
FormedAtMs: relationship.FormedAtMS,
|
||||
UpdatedAtMs: relationship.UpdatedAtMS,
|
||||
RelationshipId: relationship.RelationshipID,
|
||||
RelationType: relationship.RelationType,
|
||||
Status: relationship.Status,
|
||||
Me: toProtoCPUserProfile(relationship.Me),
|
||||
Partner: toProtoCPUserProfile(relationship.Partner),
|
||||
IntimacyValue: relationship.IntimacyValue,
|
||||
Level: relationship.Level,
|
||||
FormedAtMs: relationship.FormedAtMS,
|
||||
UpdatedAtMs: relationship.UpdatedAtMS,
|
||||
CurrentLevelThreshold: relationship.CurrentLevelThreshold,
|
||||
NextLevelThreshold: relationship.NextLevelThreshold,
|
||||
NeededForNextLevel: relationship.NeededForNextLevel,
|
||||
LevelProgressPercent: relationship.LevelProgressPercent,
|
||||
MaxLevel: relationship.MaxLevel,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -82,6 +82,24 @@ func (s *Server) CompensateMicOpenSessions(ctx context.Context, req *userv1.Cron
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExpireManagerUserBlocks 释放到期的经理封禁记录;真正是否恢复 users.status 由 user-service 内部封禁来源判断。
|
||||
func (s *Server) ExpireManagerUserBlocks(ctx context.Context, req *userv1.CronBatchRequest) (*userv1.CronBatchResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
if s.userSvc == nil {
|
||||
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "user service is not configured"))
|
||||
}
|
||||
processed, err := s.userSvc.ExpireManagerUserBlocks(ctx, req.GetBatchSize())
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &userv1.CronBatchResponse{
|
||||
ClaimedCount: int32(processed),
|
||||
ProcessedCount: int32(processed),
|
||||
SuccessCount: int32(processed),
|
||||
HasMore: processed >= normalizedBatchSize(req.GetBatchSize(), 100),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func durationFromMillis(value int64) time.Duration {
|
||||
if value <= 0 {
|
||||
return 0
|
||||
|
||||
@ -304,6 +304,67 @@ func (s *Server) SetUserStatus(ctx context.Context, req *userv1.SetUserStatusReq
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
|
||||
return toProtoSetUserStatusResponse(result), nil
|
||||
}
|
||||
|
||||
// CreateManagerUserBlock 创建经理中心封禁记录,并同步把目标账号置为 banned。
|
||||
func (s *Server) CreateManagerUserBlock(ctx context.Context, req *userv1.CreateManagerUserBlockRequest) (*userv1.CreateManagerUserBlockResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
block, status, err := s.userSvc.CreateManagerUserBlock(ctx, userservice.ManagerUserBlockCommand{
|
||||
CommandID: req.GetCommandId(),
|
||||
ManagerUserID: req.GetManagerUserId(),
|
||||
TargetUserID: req.GetTargetUserId(),
|
||||
BlockedUntilMS: req.GetBlockedUntilMs(),
|
||||
Reason: req.GetReason(),
|
||||
RequestID: req.GetMeta().GetRequestId(),
|
||||
NowMS: req.GetMeta().GetSentAtMs(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &userv1.CreateManagerUserBlockResponse{
|
||||
Block: toProtoManagerUserBlock(block),
|
||||
Status: toProtoSetUserStatusResponse(status),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListManagerUserBlocks 返回当前经理名下的封禁记录,默认只列 active 记录。
|
||||
func (s *Server) ListManagerUserBlocks(ctx context.Context, req *userv1.ListManagerUserBlocksRequest) (*userv1.ListManagerUserBlocksResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
blocks, err := s.userSvc.ListManagerUserBlocks(ctx, req.GetManagerUserId(), req.GetStatus(), req.GetPageSize())
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
resp := &userv1.ListManagerUserBlocksResponse{Blocks: make([]*userv1.ManagerUserBlock, 0, len(blocks))}
|
||||
for _, block := range blocks {
|
||||
resp.Blocks = append(resp.Blocks, toProtoManagerUserBlock(block))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// UnblockManagerUser 手动释放经理封禁;service 层会判断是否可以恢复用户主状态。
|
||||
func (s *Server) UnblockManagerUser(ctx context.Context, req *userv1.UnblockManagerUserRequest) (*userv1.UnblockManagerUserResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
block, status, err := s.userSvc.UnblockManagerUser(ctx, userservice.ReleaseManagerUserBlockCommand{
|
||||
BlockID: req.GetBlockId(),
|
||||
ManagerUserID: req.GetManagerUserId(),
|
||||
Reason: req.GetReason(),
|
||||
NowMS: req.GetMeta().GetSentAtMs(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &userv1.UnblockManagerUserResponse{
|
||||
Block: toProtoManagerUserBlock(block),
|
||||
Status: toProtoSetUserStatusResponse(status),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toProtoSetUserStatusResponse(result userservice.UserStatusResult) *userv1.SetUserStatusResponse {
|
||||
// 解封时如果还有其他封禁记录或后台封禁链路,service 会返回空状态结果;空响应表示记录已释放但用户主状态不应被恢复。
|
||||
if result.User.UserID == 0 {
|
||||
return nil
|
||||
}
|
||||
return &userv1.SetUserStatusResponse{
|
||||
User: toProtoUser(result.User),
|
||||
RevokedSessionCount: result.RevokedSessionCount,
|
||||
@ -316,7 +377,7 @@ func (s *Server) SetUserStatus(ctx context.Context, req *userv1.SetUserStatusReq
|
||||
RtcKicked: result.RTCKicked,
|
||||
RtcKickError: result.RTCKickError,
|
||||
RoomEvictError: result.RoomEvictError,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// RecordProfileVisit 记录访问足迹;重复访问只刷新访问次数和最后访问时间。
|
||||
|
||||
@ -72,6 +72,8 @@ const (
|
||||
VipGrantSourceActivity = "activity_grant"
|
||||
// VipGrantSourceAdmin 表示后台人工赠送 VIP。
|
||||
VipGrantSourceAdmin = "admin_grant"
|
||||
// VipGrantSourceManagerCenter 表示经理中心按权限赠送 VIP,账务仍复用后台赠送激活链路。
|
||||
VipGrantSourceManagerCenter = "manager_center"
|
||||
|
||||
// GameOpDebit 表示游戏平台下注、局内道具等扣金币行为。
|
||||
GameOpDebit = "debit"
|
||||
@ -948,6 +950,8 @@ func NormalizeVipGrantSource(source string) string {
|
||||
return VipGrantSourceActivity
|
||||
case VipGrantSourceAdmin:
|
||||
return VipGrantSourceAdmin
|
||||
case VipGrantSourceManagerCenter:
|
||||
return VipGrantSourceManagerCenter
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -971,7 +971,7 @@ func (s *Service) GrantVip(ctx context.Context, command ledger.GrantVipCommand)
|
||||
}
|
||||
command.GrantSource = ledger.NormalizeVipGrantSource(command.GrantSource)
|
||||
switch command.GrantSource {
|
||||
case ledger.VipGrantSourceAdmin:
|
||||
case ledger.VipGrantSourceAdmin, ledger.VipGrantSourceManagerCenter:
|
||||
if command.OperatorUserID <= 0 {
|
||||
return ledger.GrantVipReceipt{}, xerr.New(xerr.InvalidArgument, "operator_user_id is required")
|
||||
}
|
||||
|
||||
@ -3511,6 +3511,21 @@ func TestGrantVipUsesUnifiedActivationAndNoticeOutbox(t *testing.T) {
|
||||
if got := repository.CountRows("wallet_outbox", "user_id = ? AND event_type = ?", int64(51003), "VipActivated"); got != 2 {
|
||||
t.Fatalf("both vip grants should enqueue activation IM events, got %d", got)
|
||||
}
|
||||
|
||||
managerGrant, err := svc.GrantVip(context.Background(), ledger.GrantVipCommand{
|
||||
CommandID: "cmd-manager-vip2",
|
||||
TargetUserID: 51004,
|
||||
Level: 2,
|
||||
GrantSource: ledger.VipGrantSourceManagerCenter,
|
||||
OperatorUserID: 9002,
|
||||
Reason: "manager center vip grant",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("GrantVip manager center failed: %v", err)
|
||||
}
|
||||
if gotDuration := managerGrant.Vip.ExpiresAtMS - managerGrant.Vip.StartedAtMS; gotDuration != int64(30*24*time.Hour/time.Millisecond) {
|
||||
t.Fatalf("manager center VIP grant duration mismatch: got %d receipt=%+v", gotDuration, managerGrant)
|
||||
}
|
||||
}
|
||||
|
||||
// TestVipLevelSixRequiresRechargeThreshold 验证 6-10 级 VIP 必须先达到累计充值门槛。
|
||||
|
||||
@ -16,9 +16,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
bizTypeVIPPurchase = "vip_purchase"
|
||||
bizTypeVIPGrant = "vip_grant"
|
||||
vipOutboxAsset = "VIP"
|
||||
bizTypeVIPPurchase = "vip_purchase"
|
||||
bizTypeVIPGrant = "vip_grant"
|
||||
vipOutboxAsset = "VIP"
|
||||
managerCenterVIPGrantDurationMS = 30 * 24 * 60 * 60 * 1000
|
||||
)
|
||||
|
||||
// GetWalletOverview 返回钱包首页摘要;开关放在 wallet-service 内,避免 gateway 硬编码账务能力。
|
||||
@ -524,6 +525,10 @@ func (r *Repository) GrantVip(ctx context.Context, command ledger.GrantVipComman
|
||||
if level.Status != ledger.VipStatusActive {
|
||||
return ledger.GrantVipReceipt{}, xerr.New(xerr.VIPLevelDisabled, "vip level is disabled")
|
||||
}
|
||||
if command.GrantSource == ledger.VipGrantSourceManagerCenter {
|
||||
// 经理中心只能赠送 30 天 VIP;这里覆盖配置里的购买周期,保证 H5 即使不能传 duration,也不会受后台 VIP 套餐周期影响。
|
||||
level.DurationMS = managerCenterVIPGrantDurationMS
|
||||
}
|
||||
current, err := r.ensureUserVipForUpdate(ctx, tx, command.TargetUserID, nowMs)
|
||||
if err != nil {
|
||||
return ledger.GrantVipReceipt{}, err
|
||||
|
||||
@ -57,11 +57,31 @@ type cpApplication struct {
|
||||
}
|
||||
|
||||
type cpRelationship struct {
|
||||
RelationshipID string `json:"relationship_id"`
|
||||
RelationType string `json:"relation_type"`
|
||||
Status string `json:"status"`
|
||||
IntimacyValue int64 `json:"intimacy_value"`
|
||||
Level int32 `json:"level"`
|
||||
RelationshipID string `json:"relationship_id"`
|
||||
RelationType string `json:"relation_type"`
|
||||
Status string `json:"status"`
|
||||
IntimacyValue int64 `json:"intimacy_value"`
|
||||
Level int32 `json:"level"`
|
||||
CurrentLevelThreshold int64 `json:"current_level_threshold"`
|
||||
NextLevelThreshold int64 `json:"next_level_threshold"`
|
||||
NeededForNextLevel int64 `json:"needed_for_next_level"`
|
||||
LevelProgressPercent int32 `json:"level_progress_percent"`
|
||||
MaxLevel bool `json:"max_level"`
|
||||
}
|
||||
|
||||
type cpRelationshipListData struct {
|
||||
Relationships []cpRelationship `json:"relationships"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
|
||||
type cpLevelRuleSnapshot struct {
|
||||
LevelNo int32
|
||||
IntimacyThreshold int64
|
||||
RewardResourceGroupID int64
|
||||
LevelIconURL string
|
||||
Status string
|
||||
CreatedAtMS int64
|
||||
UpdatedAtMS int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
@ -84,6 +104,16 @@ func main() {
|
||||
startMS: time.Now().UTC().UnixMilli(),
|
||||
}
|
||||
|
||||
if env("CP_SMOKE_FOCUS", "") == "relationships_progress" {
|
||||
fmt.Println("==> focused relationship progress HTTP chain")
|
||||
if err := s.runRelationshipProgressFocus(ctx); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
fmt.Println("ok focused relationship progress HTTP chain")
|
||||
fmt.Println("CP relationship progress smoke passed")
|
||||
return
|
||||
}
|
||||
|
||||
steps := []struct {
|
||||
name string
|
||||
fn func(context.Context) error
|
||||
@ -130,6 +160,208 @@ func (s *smoke) seed(ctx context.Context) error {
|
||||
return s.seedGifts(ctx)
|
||||
}
|
||||
|
||||
func (s *smoke) runRelationshipProgressFocus(ctx context.Context) (err error) {
|
||||
originalRules, err := s.snapshotCPLevelRules(ctx, "cp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 聚焦烟测会临时写入确定性的等级规则;退出前恢复原规则,避免影响本地后台正在调的 CP 配置。
|
||||
defer func() {
|
||||
if restoreErr := s.restoreCPLevelRules(ctx, "cp", originalRules); err == nil && restoreErr != nil {
|
||||
err = restoreErr
|
||||
}
|
||||
}()
|
||||
// 关系和申请只使用固定 smoke 用户,退出时清掉这些事实,避免下一次烟测被旧 active 关系挡住。
|
||||
defer func() {
|
||||
if cleanupErr := s.cleanupCPFacts(ctx); err == nil && cleanupErr != nil {
|
||||
err = cleanupErr
|
||||
}
|
||||
}()
|
||||
if err := s.seed(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.seedProgressLevelRules(ctx, "cp"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.seedProgressRelationship(ctx, 180, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.assertRelationshipProgressHTTP(ctx, cpRelationship{
|
||||
RelationshipID: relationshipID(userA, userB),
|
||||
RelationType: "cp",
|
||||
Status: "active",
|
||||
IntimacyValue: 180,
|
||||
Level: 2,
|
||||
CurrentLevelThreshold: 100,
|
||||
NextLevelThreshold: 300,
|
||||
NeededForNextLevel: 120,
|
||||
LevelProgressPercent: 40,
|
||||
MaxLevel: false,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.seedProgressRelationship(ctx, 1200, 5); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.assertRelationshipProgressHTTP(ctx, cpRelationship{
|
||||
RelationshipID: relationshipID(userA, userB),
|
||||
RelationType: "cp",
|
||||
Status: "active",
|
||||
IntimacyValue: 1200,
|
||||
Level: 5,
|
||||
CurrentLevelThreshold: 1000,
|
||||
NextLevelThreshold: 0,
|
||||
NeededForNextLevel: 0,
|
||||
LevelProgressPercent: 100,
|
||||
MaxLevel: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *smoke) snapshotCPLevelRules(ctx context.Context, relationType string) ([]cpLevelRuleSnapshot, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT level_no, intimacy_threshold, reward_resource_group_id, level_icon_url, status, created_at_ms, updated_at_ms
|
||||
FROM hyapp_user.user_cp_level_rules
|
||||
WHERE app_code = ? AND relation_type = ?
|
||||
ORDER BY level_no ASC`, appCode, relationType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
rules := make([]cpLevelRuleSnapshot, 0)
|
||||
for rows.Next() {
|
||||
var rule cpLevelRuleSnapshot
|
||||
if err := rows.Scan(&rule.LevelNo, &rule.IntimacyThreshold, &rule.RewardResourceGroupID, &rule.LevelIconURL, &rule.Status, &rule.CreatedAtMS, &rule.UpdatedAtMS); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
return rules, rows.Err()
|
||||
}
|
||||
|
||||
func (s *smoke) restoreCPLevelRules(ctx context.Context, relationType string, rules []cpLevelRuleSnapshot) error {
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
// 先删除当前 relation_type 的临时规则,再按快照恢复;这样新增、删除和禁用状态都能回到烟测前。
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
DELETE FROM hyapp_user.user_cp_level_rules
|
||||
WHERE app_code = ? AND relation_type = ?`, appCode, relationType); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, rule := range rules {
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO hyapp_user.user_cp_level_rules (
|
||||
app_code, relation_type, level_no, intimacy_threshold, reward_resource_group_id,
|
||||
level_icon_url, status, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
appCode, relationType, rule.LevelNo, rule.IntimacyThreshold, rule.RewardResourceGroupID,
|
||||
rule.LevelIconURL, rule.Status, rule.CreatedAtMS, rule.UpdatedAtMS,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *smoke) seedProgressLevelRules(ctx context.Context, relationType string) error {
|
||||
nowMS := time.Now().UTC().UnixMilli()
|
||||
rules := []struct {
|
||||
level int32
|
||||
threshold int64
|
||||
}{
|
||||
{1, 0},
|
||||
{2, 100},
|
||||
{3, 300},
|
||||
{4, 600},
|
||||
{5, 1000},
|
||||
}
|
||||
for _, rule := range rules {
|
||||
if _, err := s.db.ExecContext(ctx, `
|
||||
INSERT INTO hyapp_user.user_cp_level_rules (
|
||||
app_code, relation_type, level_no, intimacy_threshold, reward_resource_group_id,
|
||||
level_icon_url, status, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, 0, '', 'active', ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
intimacy_threshold = VALUES(intimacy_threshold),
|
||||
reward_resource_group_id = 0,
|
||||
level_icon_url = '',
|
||||
status = 'active',
|
||||
updated_at_ms = VALUES(updated_at_ms)`,
|
||||
appCode, relationType, rule.level, rule.threshold, nowMS, nowMS,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *smoke) seedProgressRelationship(ctx context.Context, intimacyValue int64, level int32) error {
|
||||
nowMS := time.Now().UTC().UnixMilli()
|
||||
a, b := orderedPair(userA, userB)
|
||||
// 直接写真实关系表,只绕过“送礼/申请/同意”前置链路;本用例验证的是已形成关系的服务端读模型和 gateway 输出。
|
||||
_, err := s.db.ExecContext(ctx, `
|
||||
INSERT INTO hyapp_user.user_cp_relationships (
|
||||
app_code, relationship_id, user_a_id, user_b_id, relation_type, status,
|
||||
intimacy_value, level_no, source_application_id, formed_at_ms, ended_at_ms, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, 'cp', 'active', ?, ?, 'cp-smoke-progress', ?, 0, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
relation_type = 'cp',
|
||||
status = 'active',
|
||||
intimacy_value = VALUES(intimacy_value),
|
||||
level_no = VALUES(level_no),
|
||||
updated_at_ms = VALUES(updated_at_ms)`,
|
||||
appCode, relationshipID(userA, userB), a, b, intimacyValue, level, nowMS, nowMS, nowMS,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *smoke) assertRelationshipProgressHTTP(ctx context.Context, want cpRelationship) error {
|
||||
got, err := s.getHTTPRelationship(ctx, userA, want.RelationType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 新增字段必须由 HTTP 响应直接给出;这里逐项比对,防止客户端继续用等级和亲密值自行推算进度。
|
||||
checks := []struct {
|
||||
name string
|
||||
got any
|
||||
want any
|
||||
}{
|
||||
{"relationship_id", got.RelationshipID, want.RelationshipID},
|
||||
{"relation_type", got.RelationType, want.RelationType},
|
||||
{"status", got.Status, want.Status},
|
||||
{"intimacy_value", got.IntimacyValue, want.IntimacyValue},
|
||||
{"level", got.Level, want.Level},
|
||||
{"current_level_threshold", got.CurrentLevelThreshold, want.CurrentLevelThreshold},
|
||||
{"next_level_threshold", got.NextLevelThreshold, want.NextLevelThreshold},
|
||||
{"needed_for_next_level", got.NeededForNextLevel, want.NeededForNextLevel},
|
||||
{"level_progress_percent", got.LevelProgressPercent, want.LevelProgressPercent},
|
||||
{"max_level", got.MaxLevel, want.MaxLevel},
|
||||
}
|
||||
for _, check := range checks {
|
||||
if check.got != check.want {
|
||||
return fmt.Errorf("relationship %s mismatch: got=%v want=%v full=%+v", check.name, check.got, check.want, got)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *smoke) getHTTPRelationship(ctx context.Context, userID int64, relationType string) (cpRelationship, error) {
|
||||
resp, err := s.request(ctx, http.MethodGet, "/api/v1/cp/relationships?relation_type="+relationType+"&page=1&page_size=20", userID, nil)
|
||||
if err != nil {
|
||||
return cpRelationship{}, err
|
||||
}
|
||||
var data cpRelationshipListData
|
||||
if err := json.Unmarshal(resp.Data, &data); err != nil {
|
||||
return cpRelationship{}, err
|
||||
}
|
||||
if data.Total != 1 || len(data.Relationships) != 1 {
|
||||
return cpRelationship{}, fmt.Errorf("relationship list size mismatch total=%d len=%d data=%s", data.Total, len(data.Relationships), string(resp.Data))
|
||||
}
|
||||
return data.Relationships[0], nil
|
||||
}
|
||||
|
||||
func (s *smoke) lookupUSRegion(ctx context.Context) (int64, error) {
|
||||
var regionID int64
|
||||
err := s.db.QueryRowContext(ctx, `
|
||||
@ -474,6 +706,9 @@ func (s *smoke) testAcceptApplication(ctx context.Context) error {
|
||||
if err := s.waitNotice(ctx, "UserCPApplicationAccepted", "tencent_im_c2c", "cp_application_accepted", userA, "delivered"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.waitNotice(ctx, "UserCPApplicationAccepted", "tencent_im_c2c_acceptor", "cp_application_accepted", userB, "delivered"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.waitNotice(ctx, "UserCPApplicationAccepted", "tencent_im_room", "cp_application_accepted", userA, "delivered"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user