机器人

This commit is contained in:
zhx 2026-06-17 23:13:08 +08:00
parent da64d5f189
commit 0d111d9a88
108 changed files with 31153 additions and 15564 deletions

View File

@ -193,6 +193,7 @@ docs/flutter对接/Flutter App 通知与钱包余额对接.md
| `hyapp_room_outbox` | `hyapp-room-outbox-producer` | `hyapp-activity-room-outbox` | activity-service 消费 `RoomGiftSent``RoomRocketIgnited` 等房间事实 |
| `hyapp_room_outbox` | `hyapp-room-outbox-producer` | `hyapp-notice-room-outbox` | notice-service 消费 `RoomUserKicked` 等私有通知事实 |
| `hyapp_room_outbox` | `hyapp-room-outbox-producer` | `hyapp-room-im-bridge` | room-service IM bridge 消费房间群系统消息和群成员控制事实 |
| `hyapp_robot_room_outbox` | `hyapp-room-robot-outbox-producer` | `hyapp-test-room-robot-im-bridge` / `hyapp-room-robot-im-bridge` | room-service IM bridge 只消费机器人房间礼物、热度和麦位热度展示事实;本地/testbox 用 test group线上用正式 group |
| `hyapp_room_outbox` | `hyapp-room-outbox-producer` | `hyapp-user-mictime-room-outbox` | user-service 消费 `RoomMicChanged` 并更新用户麦时读模型 |
| `hyapp_room_outbox` | `hyapp-room-outbox-producer` | `hyapp-statistics-room-outbox` | statistics-service 消费 `RoomGiftSent``RoomUserJoined` 并更新聚合表 |
| `hyapp_user_outbox` | `hyapp-user-outbox-producer` | `hyapp-statistics-user-outbox` | statistics-service 消费 `UserRegistered` 并更新注册 cohort |

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc-gen-go-grpc v1.5.1
// - 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.Error(codes.Unimplemented, "method PingActivity not implemented")
return nil, status.Errorf(codes.Unimplemented, "method PingActivity not implemented")
}
func (UnimplementedActivityServiceServer) GetActivityStatus(context.Context, *GetActivityStatusRequest) (*GetActivityStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetActivityStatus not implemented")
return nil, status.Errorf(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 panics, it indicates UnimplementedActivityServiceServer was
// If the following call pancis, 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.Error(codes.Unimplemented, "method ListMessageTabs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListMessageTabs not implemented")
}
func (UnimplementedMessageInboxServiceServer) ListInboxMessages(context.Context, *ListInboxMessagesRequest) (*ListInboxMessagesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListInboxMessages not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListInboxMessages not implemented")
}
func (UnimplementedMessageInboxServiceServer) MarkInboxMessageRead(context.Context, *MarkInboxMessageReadRequest) (*MarkInboxMessageReadResponse, error) {
return nil, status.Error(codes.Unimplemented, "method MarkInboxMessageRead not implemented")
return nil, status.Errorf(codes.Unimplemented, "method MarkInboxMessageRead not implemented")
}
func (UnimplementedMessageInboxServiceServer) MarkInboxSectionRead(context.Context, *MarkInboxSectionReadRequest) (*MarkInboxSectionReadResponse, error) {
return nil, status.Error(codes.Unimplemented, "method MarkInboxSectionRead not implemented")
return nil, status.Errorf(codes.Unimplemented, "method MarkInboxSectionRead not implemented")
}
func (UnimplementedMessageInboxServiceServer) DeleteInboxMessage(context.Context, *DeleteInboxMessageRequest) (*DeleteInboxMessageResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteInboxMessage not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteInboxMessage not implemented")
}
func (UnimplementedMessageInboxServiceServer) CreateInboxMessage(context.Context, *CreateInboxMessageRequest) (*CreateInboxMessageResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateInboxMessage not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateInboxMessage not implemented")
}
func (UnimplementedMessageInboxServiceServer) CreateFanoutJob(context.Context, *CreateFanoutJobRequest) (*CreateFanoutJobResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateFanoutJob not implemented")
return nil, status.Errorf(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 panics, it indicates UnimplementedMessageInboxServiceServer was
// If the following call pancis, it indicates UnimplementedMessageInboxServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
@ -623,25 +623,25 @@ type ActivityCronServiceServer interface {
type UnimplementedActivityCronServiceServer struct{}
func (UnimplementedActivityCronServiceServer) ProcessMessageFanoutBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessMessageFanoutBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessMessageFanoutBatch not implemented")
}
func (UnimplementedActivityCronServiceServer) ProcessLevelRewardBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessLevelRewardBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessLevelRewardBatch not implemented")
}
func (UnimplementedActivityCronServiceServer) ProcessAchievementRewardBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessAchievementRewardBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessAchievementRewardBatch not implemented")
}
func (UnimplementedActivityCronServiceServer) ProcessRoomTurnoverRewardSettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessRoomTurnoverRewardSettlementBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessRoomTurnoverRewardSettlementBatch not implemented")
}
func (UnimplementedActivityCronServiceServer) ProcessWeeklyStarSettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessWeeklyStarSettlementBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessWeeklyStarSettlementBatch not implemented")
}
func (UnimplementedActivityCronServiceServer) ProcessCPWeeklyRankSettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessCPWeeklyRankSettlementBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessCPWeeklyRankSettlementBatch not implemented")
}
func (UnimplementedActivityCronServiceServer) ProcessAgencyOpeningSettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessAgencyOpeningSettlementBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessAgencyOpeningSettlementBatch not implemented")
}
func (UnimplementedActivityCronServiceServer) mustEmbedUnimplementedActivityCronServiceServer() {}
func (UnimplementedActivityCronServiceServer) testEmbeddedByValue() {}
@ -654,7 +654,7 @@ type UnsafeActivityCronServiceServer interface {
}
func RegisterActivityCronServiceServer(s grpc.ServiceRegistrar, srv ActivityCronServiceServer) {
// If the following call panics, it indicates UnimplementedActivityCronServiceServer was
// If the following call pancis, 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.
@ -905,13 +905,13 @@ type TaskServiceServer interface {
type UnimplementedTaskServiceServer struct{}
func (UnimplementedTaskServiceServer) ListUserTasks(context.Context, *ListUserTasksRequest) (*ListUserTasksResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListUserTasks not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListUserTasks not implemented")
}
func (UnimplementedTaskServiceServer) ClaimTaskReward(context.Context, *ClaimTaskRewardRequest) (*ClaimTaskRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ClaimTaskReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ClaimTaskReward not implemented")
}
func (UnimplementedTaskServiceServer) ConsumeTaskEvent(context.Context, *ConsumeTaskEventRequest) (*ConsumeTaskEventResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConsumeTaskEvent not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConsumeTaskEvent not implemented")
}
func (UnimplementedTaskServiceServer) mustEmbedUnimplementedTaskServiceServer() {}
func (UnimplementedTaskServiceServer) testEmbeddedByValue() {}
@ -924,7 +924,7 @@ type UnsafeTaskServiceServer interface {
}
func RegisterTaskServiceServer(s grpc.ServiceRegistrar, srv TaskServiceServer) {
// If the following call panics, it indicates UnimplementedTaskServiceServer was
// If the following call pancis, 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.
@ -1139,25 +1139,25 @@ type GrowthLevelServiceServer interface {
type UnimplementedGrowthLevelServiceServer struct{}
func (UnimplementedGrowthLevelServiceServer) GetMyLevelOverview(context.Context, *GetMyLevelOverviewRequest) (*GetMyLevelOverviewResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetMyLevelOverview not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetMyLevelOverview not implemented")
}
func (UnimplementedGrowthLevelServiceServer) GetLevelTrack(context.Context, *GetLevelTrackRequest) (*GetLevelTrackResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetLevelTrack not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetLevelTrack not implemented")
}
func (UnimplementedGrowthLevelServiceServer) BatchGetUserLevelDisplayProfiles(context.Context, *BatchGetUserLevelDisplayProfilesRequest) (*BatchGetUserLevelDisplayProfilesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method BatchGetUserLevelDisplayProfiles not implemented")
return nil, status.Errorf(codes.Unimplemented, "method BatchGetUserLevelDisplayProfiles not implemented")
}
func (UnimplementedGrowthLevelServiceServer) ListLevelRewards(context.Context, *ListLevelRewardsRequest) (*ListLevelRewardsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListLevelRewards not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListLevelRewards not implemented")
}
func (UnimplementedGrowthLevelServiceServer) ConsumeLevelEvent(context.Context, *ConsumeLevelEventRequest) (*ConsumeLevelEventResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConsumeLevelEvent not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConsumeLevelEvent not implemented")
}
func (UnimplementedGrowthLevelServiceServer) SetUserLevel(context.Context, *SetUserLevelRequest) (*SetUserLevelResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetUserLevel not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetUserLevel not implemented")
}
func (UnimplementedGrowthLevelServiceServer) IssueRegistrationLevelBadges(context.Context, *IssueRegistrationLevelBadgesRequest) (*IssueRegistrationLevelBadgesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method IssueRegistrationLevelBadges not implemented")
return nil, status.Errorf(codes.Unimplemented, "method IssueRegistrationLevelBadges not implemented")
}
func (UnimplementedGrowthLevelServiceServer) mustEmbedUnimplementedGrowthLevelServiceServer() {}
func (UnimplementedGrowthLevelServiceServer) testEmbeddedByValue() {}
@ -1170,7 +1170,7 @@ type UnsafeGrowthLevelServiceServer interface {
}
func RegisterGrowthLevelServiceServer(s grpc.ServiceRegistrar, srv GrowthLevelServiceServer) {
// If the following call panics, it indicates UnimplementedGrowthLevelServiceServer was
// If the following call pancis, 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.
@ -1434,16 +1434,16 @@ type AchievementServiceServer interface {
type UnimplementedAchievementServiceServer struct{}
func (UnimplementedAchievementServiceServer) ListAchievements(context.Context, *ListAchievementsRequest) (*ListAchievementsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListAchievements not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListAchievements not implemented")
}
func (UnimplementedAchievementServiceServer) ConsumeAchievementEvent(context.Context, *ConsumeAchievementEventRequest) (*ConsumeAchievementEventResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConsumeAchievementEvent not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConsumeAchievementEvent not implemented")
}
func (UnimplementedAchievementServiceServer) ListMyBadges(context.Context, *ListMyBadgesRequest) (*ListMyBadgesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListMyBadges not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListMyBadges not implemented")
}
func (UnimplementedAchievementServiceServer) SetBadgeDisplay(context.Context, *SetBadgeDisplayRequest) (*SetBadgeDisplayResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetBadgeDisplay not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetBadgeDisplay not implemented")
}
func (UnimplementedAchievementServiceServer) mustEmbedUnimplementedAchievementServiceServer() {}
func (UnimplementedAchievementServiceServer) testEmbeddedByValue() {}
@ -1456,7 +1456,7 @@ type UnsafeAchievementServiceServer interface {
}
func RegisterAchievementServiceServer(s grpc.ServiceRegistrar, srv AchievementServiceServer) {
// If the following call panics, it indicates UnimplementedAchievementServiceServer was
// If the following call pancis, 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.
@ -1628,10 +1628,10 @@ type LuckyGiftServiceServer interface {
type UnimplementedLuckyGiftServiceServer struct{}
func (UnimplementedLuckyGiftServiceServer) CheckLuckyGift(context.Context, *CheckLuckyGiftRequest) (*CheckLuckyGiftResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CheckLuckyGift not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CheckLuckyGift not implemented")
}
func (UnimplementedLuckyGiftServiceServer) ExecuteLuckyGiftDraw(context.Context, *ExecuteLuckyGiftDrawRequest) (*ExecuteLuckyGiftDrawResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ExecuteLuckyGiftDraw not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ExecuteLuckyGiftDraw not implemented")
}
func (UnimplementedLuckyGiftServiceServer) mustEmbedUnimplementedLuckyGiftServiceServer() {}
func (UnimplementedLuckyGiftServiceServer) testEmbeddedByValue() {}
@ -1644,7 +1644,7 @@ type UnsafeLuckyGiftServiceServer interface {
}
func RegisterLuckyGiftServiceServer(s grpc.ServiceRegistrar, srv LuckyGiftServiceServer) {
// If the following call panics, it indicates UnimplementedLuckyGiftServiceServer was
// If the following call pancis, 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.
@ -1759,7 +1759,7 @@ type RoomTurnoverRewardServiceServer interface {
type UnimplementedRoomTurnoverRewardServiceServer struct{}
func (UnimplementedRoomTurnoverRewardServiceServer) GetRoomTurnoverRewardStatus(context.Context, *GetRoomTurnoverRewardStatusRequest) (*GetRoomTurnoverRewardStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoomTurnoverRewardStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRoomTurnoverRewardStatus not implemented")
}
func (UnimplementedRoomTurnoverRewardServiceServer) mustEmbedUnimplementedRoomTurnoverRewardServiceServer() {
}
@ -1773,7 +1773,7 @@ type UnsafeRoomTurnoverRewardServiceServer interface {
}
func RegisterRoomTurnoverRewardServiceServer(s grpc.ServiceRegistrar, srv RoomTurnoverRewardServiceServer) {
// If the following call panics, it indicates UnimplementedRoomTurnoverRewardServiceServer was
// If the following call pancis, 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.
@ -1892,13 +1892,13 @@ type WeeklyStarServiceServer interface {
type UnimplementedWeeklyStarServiceServer struct{}
func (UnimplementedWeeklyStarServiceServer) GetWeeklyStarCurrent(context.Context, *GetWeeklyStarCurrentRequest) (*GetWeeklyStarCurrentResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetWeeklyStarCurrent not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetWeeklyStarCurrent not implemented")
}
func (UnimplementedWeeklyStarServiceServer) ListWeeklyStarLeaderboard(context.Context, *ListWeeklyStarLeaderboardRequest) (*ListWeeklyStarLeaderboardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarLeaderboard not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarLeaderboard not implemented")
}
func (UnimplementedWeeklyStarServiceServer) ListWeeklyStarHistory(context.Context, *ListWeeklyStarHistoryRequest) (*ListWeeklyStarHistoryResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarHistory not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarHistory not implemented")
}
func (UnimplementedWeeklyStarServiceServer) mustEmbedUnimplementedWeeklyStarServiceServer() {}
func (UnimplementedWeeklyStarServiceServer) testEmbeddedByValue() {}
@ -1911,7 +1911,7 @@ type UnsafeWeeklyStarServiceServer interface {
}
func RegisterWeeklyStarServiceServer(s grpc.ServiceRegistrar, srv WeeklyStarServiceServer) {
// If the following call panics, it indicates UnimplementedWeeklyStarServiceServer was
// If the following call pancis, 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.
@ -2048,7 +2048,7 @@ type CPWeeklyRankServiceServer interface {
type UnimplementedCPWeeklyRankServiceServer struct{}
func (UnimplementedCPWeeklyRankServiceServer) GetCPWeeklyRankStatus(context.Context, *GetCPWeeklyRankStatusRequest) (*GetCPWeeklyRankStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetCPWeeklyRankStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetCPWeeklyRankStatus not implemented")
}
func (UnimplementedCPWeeklyRankServiceServer) mustEmbedUnimplementedCPWeeklyRankServiceServer() {}
func (UnimplementedCPWeeklyRankServiceServer) testEmbeddedByValue() {}
@ -2061,7 +2061,7 @@ type UnsafeCPWeeklyRankServiceServer interface {
}
func RegisterCPWeeklyRankServiceServer(s grpc.ServiceRegistrar, srv CPWeeklyRankServiceServer) {
// If the following call panics, it indicates UnimplementedCPWeeklyRankServiceServer was
// If the following call pancis, it indicates UnimplementedCPWeeklyRankServiceServer 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.
@ -2180,13 +2180,13 @@ type AgencyOpeningServiceServer interface {
type UnimplementedAgencyOpeningServiceServer struct{}
func (UnimplementedAgencyOpeningServiceServer) GetAgencyOpeningStatus(context.Context, *GetAgencyOpeningStatusRequest) (*GetAgencyOpeningStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetAgencyOpeningStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetAgencyOpeningStatus not implemented")
}
func (UnimplementedAgencyOpeningServiceServer) ApplyAgencyOpening(context.Context, *ApplyAgencyOpeningRequest) (*ApplyAgencyOpeningResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ApplyAgencyOpening not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ApplyAgencyOpening not implemented")
}
func (UnimplementedAgencyOpeningServiceServer) ListAgencyOpeningLeaderboard(context.Context, *ListAgencyOpeningApplicationsRequest) (*ListAgencyOpeningApplicationsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListAgencyOpeningLeaderboard not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListAgencyOpeningLeaderboard not implemented")
}
func (UnimplementedAgencyOpeningServiceServer) mustEmbedUnimplementedAgencyOpeningServiceServer() {}
func (UnimplementedAgencyOpeningServiceServer) testEmbeddedByValue() {}
@ -2199,7 +2199,7 @@ type UnsafeAgencyOpeningServiceServer interface {
}
func RegisterAgencyOpeningServiceServer(s grpc.ServiceRegistrar, srv AgencyOpeningServiceServer) {
// If the following call panics, it indicates UnimplementedAgencyOpeningServiceServer was
// If the following call pancis, it indicates UnimplementedAgencyOpeningServiceServer 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.
@ -2388,19 +2388,19 @@ type BroadcastServiceServer interface {
type UnimplementedBroadcastServiceServer struct{}
func (UnimplementedBroadcastServiceServer) EnsureBroadcastGroups(context.Context, *EnsureBroadcastGroupsRequest) (*EnsureBroadcastGroupsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method EnsureBroadcastGroups not implemented")
return nil, status.Errorf(codes.Unimplemented, "method EnsureBroadcastGroups not implemented")
}
func (UnimplementedBroadcastServiceServer) PublishRegionBroadcast(context.Context, *PublishRegionBroadcastRequest) (*PublishBroadcastResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PublishRegionBroadcast not implemented")
return nil, status.Errorf(codes.Unimplemented, "method PublishRegionBroadcast not implemented")
}
func (UnimplementedBroadcastServiceServer) PublishGlobalBroadcast(context.Context, *PublishGlobalBroadcastRequest) (*PublishBroadcastResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PublishGlobalBroadcast not implemented")
return nil, status.Errorf(codes.Unimplemented, "method PublishGlobalBroadcast not implemented")
}
func (UnimplementedBroadcastServiceServer) RemoveRegionBroadcastMember(context.Context, *RemoveRegionBroadcastMemberRequest) (*RemoveRegionBroadcastMemberResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RemoveRegionBroadcastMember not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RemoveRegionBroadcastMember not implemented")
}
func (UnimplementedBroadcastServiceServer) ProcessBroadcastOutboxBatch(context.Context, *CronBatchRequest) (*ProcessBroadcastOutboxBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessBroadcastOutboxBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessBroadcastOutboxBatch not implemented")
}
func (UnimplementedBroadcastServiceServer) mustEmbedUnimplementedBroadcastServiceServer() {}
func (UnimplementedBroadcastServiceServer) testEmbeddedByValue() {}
@ -2413,7 +2413,7 @@ type UnsafeBroadcastServiceServer interface {
}
func RegisterBroadcastServiceServer(s grpc.ServiceRegistrar, srv BroadcastServiceServer) {
// If the following call panics, it indicates UnimplementedBroadcastServiceServer was
// If the following call pancis, 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.
@ -2594,7 +2594,7 @@ type RoomEventConsumerServiceServer interface {
type UnimplementedRoomEventConsumerServiceServer struct{}
func (UnimplementedRoomEventConsumerServiceServer) ConsumeRoomEvent(context.Context, *ConsumeRoomEventRequest) (*ConsumeRoomEventResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConsumeRoomEvent not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConsumeRoomEvent not implemented")
}
func (UnimplementedRoomEventConsumerServiceServer) mustEmbedUnimplementedRoomEventConsumerServiceServer() {
}
@ -2608,7 +2608,7 @@ type UnsafeRoomEventConsumerServiceServer interface {
}
func RegisterRoomEventConsumerServiceServer(s grpc.ServiceRegistrar, srv RoomEventConsumerServiceServer) {
// If the following call panics, it indicates UnimplementedRoomEventConsumerServiceServer was
// If the following call pancis, 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.
@ -2727,13 +2727,13 @@ type AdminTaskServiceServer interface {
type UnimplementedAdminTaskServiceServer struct{}
func (UnimplementedAdminTaskServiceServer) ListTaskDefinitions(context.Context, *ListTaskDefinitionsRequest) (*ListTaskDefinitionsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListTaskDefinitions not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListTaskDefinitions not implemented")
}
func (UnimplementedAdminTaskServiceServer) UpsertTaskDefinition(context.Context, *UpsertTaskDefinitionRequest) (*UpsertTaskDefinitionResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertTaskDefinition not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertTaskDefinition not implemented")
}
func (UnimplementedAdminTaskServiceServer) SetTaskDefinitionStatus(context.Context, *SetTaskDefinitionStatusRequest) (*SetTaskDefinitionStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetTaskDefinitionStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetTaskDefinitionStatus not implemented")
}
func (UnimplementedAdminTaskServiceServer) mustEmbedUnimplementedAdminTaskServiceServer() {}
func (UnimplementedAdminTaskServiceServer) testEmbeddedByValue() {}
@ -2746,7 +2746,7 @@ type UnsafeAdminTaskServiceServer interface {
}
func RegisterAdminTaskServiceServer(s grpc.ServiceRegistrar, srv AdminTaskServiceServer) {
// If the following call panics, it indicates UnimplementedAdminTaskServiceServer was
// If the following call pancis, 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.
@ -2896,10 +2896,10 @@ type RegistrationRewardServiceServer interface {
type UnimplementedRegistrationRewardServiceServer struct{}
func (UnimplementedRegistrationRewardServiceServer) GetRegistrationRewardEligibility(context.Context, *GetRegistrationRewardEligibilityRequest) (*GetRegistrationRewardEligibilityResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRegistrationRewardEligibility not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRegistrationRewardEligibility not implemented")
}
func (UnimplementedRegistrationRewardServiceServer) IssueRegistrationReward(context.Context, *IssueRegistrationRewardRequest) (*IssueRegistrationRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method IssueRegistrationReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method IssueRegistrationReward not implemented")
}
func (UnimplementedRegistrationRewardServiceServer) mustEmbedUnimplementedRegistrationRewardServiceServer() {
}
@ -2913,7 +2913,7 @@ type UnsafeRegistrationRewardServiceServer interface {
}
func RegisterRegistrationRewardServiceServer(s grpc.ServiceRegistrar, srv RegistrationRewardServiceServer) {
// If the following call panics, it indicates UnimplementedRegistrationRewardServiceServer was
// If the following call pancis, 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.
@ -3054,13 +3054,13 @@ type AdminRegistrationRewardServiceServer interface {
type UnimplementedAdminRegistrationRewardServiceServer struct{}
func (UnimplementedAdminRegistrationRewardServiceServer) GetRegistrationRewardConfig(context.Context, *GetRegistrationRewardConfigRequest) (*GetRegistrationRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRegistrationRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRegistrationRewardConfig not implemented")
}
func (UnimplementedAdminRegistrationRewardServiceServer) UpdateRegistrationRewardConfig(context.Context, *UpdateRegistrationRewardConfigRequest) (*UpdateRegistrationRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateRegistrationRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateRegistrationRewardConfig not implemented")
}
func (UnimplementedAdminRegistrationRewardServiceServer) ListRegistrationRewardClaims(context.Context, *ListRegistrationRewardClaimsRequest) (*ListRegistrationRewardClaimsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRegistrationRewardClaims not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRegistrationRewardClaims not implemented")
}
func (UnimplementedAdminRegistrationRewardServiceServer) mustEmbedUnimplementedAdminRegistrationRewardServiceServer() {
}
@ -3074,7 +3074,7 @@ type UnsafeAdminRegistrationRewardServiceServer interface {
}
func RegisterAdminRegistrationRewardServiceServer(s grpc.ServiceRegistrar, srv AdminRegistrationRewardServiceServer) {
// If the following call panics, it indicates UnimplementedAdminRegistrationRewardServiceServer was
// If the following call pancis, 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.
@ -3224,10 +3224,10 @@ type FirstRechargeRewardServiceServer interface {
type UnimplementedFirstRechargeRewardServiceServer struct{}
func (UnimplementedFirstRechargeRewardServiceServer) GetFirstRechargeRewardStatus(context.Context, *GetFirstRechargeRewardStatusRequest) (*GetFirstRechargeRewardStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetFirstRechargeRewardStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetFirstRechargeRewardStatus not implemented")
}
func (UnimplementedFirstRechargeRewardServiceServer) ConsumeFirstRechargeReward(context.Context, *ConsumeFirstRechargeRewardRequest) (*ConsumeFirstRechargeRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConsumeFirstRechargeReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConsumeFirstRechargeReward not implemented")
}
func (UnimplementedFirstRechargeRewardServiceServer) mustEmbedUnimplementedFirstRechargeRewardServiceServer() {
}
@ -3241,7 +3241,7 @@ type UnsafeFirstRechargeRewardServiceServer interface {
}
func RegisterFirstRechargeRewardServiceServer(s grpc.ServiceRegistrar, srv FirstRechargeRewardServiceServer) {
// If the following call panics, it indicates UnimplementedFirstRechargeRewardServiceServer was
// If the following call pancis, 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.
@ -3382,13 +3382,13 @@ type AdminFirstRechargeRewardServiceServer interface {
type UnimplementedAdminFirstRechargeRewardServiceServer struct{}
func (UnimplementedAdminFirstRechargeRewardServiceServer) GetFirstRechargeRewardConfig(context.Context, *GetFirstRechargeRewardConfigRequest) (*GetFirstRechargeRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetFirstRechargeRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetFirstRechargeRewardConfig not implemented")
}
func (UnimplementedAdminFirstRechargeRewardServiceServer) UpdateFirstRechargeRewardConfig(context.Context, *UpdateFirstRechargeRewardConfigRequest) (*UpdateFirstRechargeRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateFirstRechargeRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateFirstRechargeRewardConfig not implemented")
}
func (UnimplementedAdminFirstRechargeRewardServiceServer) ListFirstRechargeRewardClaims(context.Context, *ListFirstRechargeRewardClaimsRequest) (*ListFirstRechargeRewardClaimsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListFirstRechargeRewardClaims not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListFirstRechargeRewardClaims not implemented")
}
func (UnimplementedAdminFirstRechargeRewardServiceServer) mustEmbedUnimplementedAdminFirstRechargeRewardServiceServer() {
}
@ -3402,7 +3402,7 @@ type UnsafeAdminFirstRechargeRewardServiceServer interface {
}
func RegisterAdminFirstRechargeRewardServiceServer(s grpc.ServiceRegistrar, srv AdminFirstRechargeRewardServiceServer) {
// If the following call panics, it indicates UnimplementedAdminFirstRechargeRewardServiceServer was
// If the following call pancis, 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.
@ -3552,10 +3552,10 @@ type CumulativeRechargeRewardServiceServer interface {
type UnimplementedCumulativeRechargeRewardServiceServer struct{}
func (UnimplementedCumulativeRechargeRewardServiceServer) GetCumulativeRechargeRewardStatus(context.Context, *GetCumulativeRechargeRewardStatusRequest) (*GetCumulativeRechargeRewardStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetCumulativeRechargeRewardStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetCumulativeRechargeRewardStatus not implemented")
}
func (UnimplementedCumulativeRechargeRewardServiceServer) ConsumeCumulativeRechargeReward(context.Context, *ConsumeCumulativeRechargeRewardRequest) (*ConsumeCumulativeRechargeRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConsumeCumulativeRechargeReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConsumeCumulativeRechargeReward not implemented")
}
func (UnimplementedCumulativeRechargeRewardServiceServer) mustEmbedUnimplementedCumulativeRechargeRewardServiceServer() {
}
@ -3569,7 +3569,7 @@ type UnsafeCumulativeRechargeRewardServiceServer interface {
}
func RegisterCumulativeRechargeRewardServiceServer(s grpc.ServiceRegistrar, srv CumulativeRechargeRewardServiceServer) {
// If the following call panics, it indicates UnimplementedCumulativeRechargeRewardServiceServer was
// If the following call pancis, 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.
@ -3710,13 +3710,13 @@ type InviteActivityRewardServiceServer interface {
type UnimplementedInviteActivityRewardServiceServer struct{}
func (UnimplementedInviteActivityRewardServiceServer) GetInviteActivityRewardStatus(context.Context, *GetInviteActivityRewardStatusRequest) (*GetInviteActivityRewardStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetInviteActivityRewardStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetInviteActivityRewardStatus not implemented")
}
func (UnimplementedInviteActivityRewardServiceServer) ClaimInviteActivityReward(context.Context, *ClaimInviteActivityRewardRequest) (*ClaimInviteActivityRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ClaimInviteActivityReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ClaimInviteActivityReward not implemented")
}
func (UnimplementedInviteActivityRewardServiceServer) ListInviteActivityLeaderboard(context.Context, *ListInviteActivityLeaderboardRequest) (*ListInviteActivityLeaderboardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListInviteActivityLeaderboard not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListInviteActivityLeaderboard not implemented")
}
func (UnimplementedInviteActivityRewardServiceServer) mustEmbedUnimplementedInviteActivityRewardServiceServer() {
}
@ -3730,7 +3730,7 @@ type UnsafeInviteActivityRewardServiceServer interface {
}
func RegisterInviteActivityRewardServiceServer(s grpc.ServiceRegistrar, srv InviteActivityRewardServiceServer) {
// If the following call panics, it indicates UnimplementedInviteActivityRewardServiceServer was
// If the following call pancis, it indicates UnimplementedInviteActivityRewardServiceServer 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.
@ -3893,13 +3893,13 @@ type AdminCumulativeRechargeRewardServiceServer interface {
type UnimplementedAdminCumulativeRechargeRewardServiceServer struct{}
func (UnimplementedAdminCumulativeRechargeRewardServiceServer) GetCumulativeRechargeRewardConfig(context.Context, *GetCumulativeRechargeRewardConfigRequest) (*GetCumulativeRechargeRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetCumulativeRechargeRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetCumulativeRechargeRewardConfig not implemented")
}
func (UnimplementedAdminCumulativeRechargeRewardServiceServer) UpdateCumulativeRechargeRewardConfig(context.Context, *UpdateCumulativeRechargeRewardConfigRequest) (*UpdateCumulativeRechargeRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateCumulativeRechargeRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateCumulativeRechargeRewardConfig not implemented")
}
func (UnimplementedAdminCumulativeRechargeRewardServiceServer) ListCumulativeRechargeRewardGrants(context.Context, *ListCumulativeRechargeRewardGrantsRequest) (*ListCumulativeRechargeRewardGrantsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCumulativeRechargeRewardGrants not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCumulativeRechargeRewardGrants not implemented")
}
func (UnimplementedAdminCumulativeRechargeRewardServiceServer) mustEmbedUnimplementedAdminCumulativeRechargeRewardServiceServer() {
}
@ -3913,7 +3913,7 @@ type UnsafeAdminCumulativeRechargeRewardServiceServer interface {
}
func RegisterAdminCumulativeRechargeRewardServiceServer(s grpc.ServiceRegistrar, srv AdminCumulativeRechargeRewardServiceServer) {
// If the following call panics, it indicates UnimplementedAdminCumulativeRechargeRewardServiceServer was
// If the following call pancis, 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.
@ -4089,16 +4089,16 @@ type AdminInviteActivityRewardServiceServer interface {
type UnimplementedAdminInviteActivityRewardServiceServer struct{}
func (UnimplementedAdminInviteActivityRewardServiceServer) GetInviteActivityRewardConfig(context.Context, *GetInviteActivityRewardConfigRequest) (*GetInviteActivityRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetInviteActivityRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetInviteActivityRewardConfig not implemented")
}
func (UnimplementedAdminInviteActivityRewardServiceServer) UpdateInviteActivityRewardConfig(context.Context, *UpdateInviteActivityRewardConfigRequest) (*UpdateInviteActivityRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateInviteActivityRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateInviteActivityRewardConfig not implemented")
}
func (UnimplementedAdminInviteActivityRewardServiceServer) ListInviteActivityRewardClaims(context.Context, *ListInviteActivityRewardClaimsRequest) (*ListInviteActivityRewardClaimsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListInviteActivityRewardClaims not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListInviteActivityRewardClaims not implemented")
}
func (UnimplementedAdminInviteActivityRewardServiceServer) ListInviteActivityRewardSummaries(context.Context, *ListInviteActivityRewardSummariesRequest) (*ListInviteActivityRewardSummariesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListInviteActivityRewardSummaries not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListInviteActivityRewardSummaries not implemented")
}
func (UnimplementedAdminInviteActivityRewardServiceServer) mustEmbedUnimplementedAdminInviteActivityRewardServiceServer() {
}
@ -4112,7 +4112,7 @@ type UnsafeAdminInviteActivityRewardServiceServer interface {
}
func RegisterAdminInviteActivityRewardServiceServer(s grpc.ServiceRegistrar, srv AdminInviteActivityRewardServiceServer) {
// If the following call panics, it indicates UnimplementedAdminInviteActivityRewardServiceServer was
// If the following call pancis, it indicates UnimplementedAdminInviteActivityRewardServiceServer 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.
@ -4310,16 +4310,16 @@ type AdminRoomTurnoverRewardServiceServer interface {
type UnimplementedAdminRoomTurnoverRewardServiceServer struct{}
func (UnimplementedAdminRoomTurnoverRewardServiceServer) GetRoomTurnoverRewardConfig(context.Context, *GetRoomTurnoverRewardConfigRequest) (*GetRoomTurnoverRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoomTurnoverRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRoomTurnoverRewardConfig not implemented")
}
func (UnimplementedAdminRoomTurnoverRewardServiceServer) UpdateRoomTurnoverRewardConfig(context.Context, *UpdateRoomTurnoverRewardConfigRequest) (*UpdateRoomTurnoverRewardConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateRoomTurnoverRewardConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateRoomTurnoverRewardConfig not implemented")
}
func (UnimplementedAdminRoomTurnoverRewardServiceServer) ListRoomTurnoverRewardSettlements(context.Context, *ListRoomTurnoverRewardSettlementsRequest) (*ListRoomTurnoverRewardSettlementsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomTurnoverRewardSettlements not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomTurnoverRewardSettlements not implemented")
}
func (UnimplementedAdminRoomTurnoverRewardServiceServer) RetryRoomTurnoverRewardSettlement(context.Context, *RetryRoomTurnoverRewardSettlementRequest) (*RetryRoomTurnoverRewardSettlementResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RetryRoomTurnoverRewardSettlement not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RetryRoomTurnoverRewardSettlement not implemented")
}
func (UnimplementedAdminRoomTurnoverRewardServiceServer) mustEmbedUnimplementedAdminRoomTurnoverRewardServiceServer() {
}
@ -4333,7 +4333,7 @@ type UnsafeAdminRoomTurnoverRewardServiceServer interface {
}
func RegisterAdminRoomTurnoverRewardServiceServer(s grpc.ServiceRegistrar, srv AdminRoomTurnoverRewardServiceServer) {
// If the following call panics, it indicates UnimplementedAdminRoomTurnoverRewardServiceServer was
// If the following call pancis, 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.
@ -4570,25 +4570,25 @@ type AdminWeeklyStarServiceServer interface {
type UnimplementedAdminWeeklyStarServiceServer struct{}
func (UnimplementedAdminWeeklyStarServiceServer) ListWeeklyStarCycles(context.Context, *ListWeeklyStarCyclesRequest) (*ListWeeklyStarCyclesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarCycles not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarCycles not implemented")
}
func (UnimplementedAdminWeeklyStarServiceServer) CreateWeeklyStarCycle(context.Context, *UpsertWeeklyStarCycleRequest) (*UpsertWeeklyStarCycleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateWeeklyStarCycle not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateWeeklyStarCycle not implemented")
}
func (UnimplementedAdminWeeklyStarServiceServer) GetWeeklyStarCycle(context.Context, *GetWeeklyStarCycleRequest) (*GetWeeklyStarCycleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetWeeklyStarCycle not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetWeeklyStarCycle not implemented")
}
func (UnimplementedAdminWeeklyStarServiceServer) UpdateWeeklyStarCycle(context.Context, *UpsertWeeklyStarCycleRequest) (*UpsertWeeklyStarCycleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateWeeklyStarCycle not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateWeeklyStarCycle not implemented")
}
func (UnimplementedAdminWeeklyStarServiceServer) SetWeeklyStarCycleStatus(context.Context, *SetWeeklyStarCycleStatusRequest) (*SetWeeklyStarCycleStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetWeeklyStarCycleStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetWeeklyStarCycleStatus not implemented")
}
func (UnimplementedAdminWeeklyStarServiceServer) ListWeeklyStarLeaderboard(context.Context, *ListWeeklyStarLeaderboardRequest) (*ListWeeklyStarLeaderboardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarLeaderboard not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarLeaderboard not implemented")
}
func (UnimplementedAdminWeeklyStarServiceServer) ListWeeklyStarSettlements(context.Context, *ListWeeklyStarSettlementsRequest) (*ListWeeklyStarSettlementsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListWeeklyStarSettlements not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListWeeklyStarSettlements not implemented")
}
func (UnimplementedAdminWeeklyStarServiceServer) mustEmbedUnimplementedAdminWeeklyStarServiceServer() {
}
@ -4602,7 +4602,7 @@ type UnsafeAdminWeeklyStarServiceServer interface {
}
func RegisterAdminWeeklyStarServiceServer(s grpc.ServiceRegistrar, srv AdminWeeklyStarServiceServer) {
// If the following call panics, it indicates UnimplementedAdminWeeklyStarServiceServer was
// If the following call pancis, 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.
@ -4853,13 +4853,13 @@ type AdminCPWeeklyRankServiceServer interface {
type UnimplementedAdminCPWeeklyRankServiceServer struct{}
func (UnimplementedAdminCPWeeklyRankServiceServer) GetCPWeeklyRankConfig(context.Context, *GetCPWeeklyRankConfigRequest) (*GetCPWeeklyRankConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetCPWeeklyRankConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetCPWeeklyRankConfig not implemented")
}
func (UnimplementedAdminCPWeeklyRankServiceServer) UpdateCPWeeklyRankConfig(context.Context, *UpdateCPWeeklyRankConfigRequest) (*UpdateCPWeeklyRankConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateCPWeeklyRankConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateCPWeeklyRankConfig not implemented")
}
func (UnimplementedAdminCPWeeklyRankServiceServer) ListCPWeeklyRankSettlements(context.Context, *ListCPWeeklyRankSettlementsRequest) (*ListCPWeeklyRankSettlementsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCPWeeklyRankSettlements not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCPWeeklyRankSettlements not implemented")
}
func (UnimplementedAdminCPWeeklyRankServiceServer) mustEmbedUnimplementedAdminCPWeeklyRankServiceServer() {
}
@ -4873,7 +4873,7 @@ type UnsafeAdminCPWeeklyRankServiceServer interface {
}
func RegisterAdminCPWeeklyRankServiceServer(s grpc.ServiceRegistrar, srv AdminCPWeeklyRankServiceServer) {
// If the following call panics, it indicates UnimplementedAdminCPWeeklyRankServiceServer was
// If the following call pancis, it indicates UnimplementedAdminCPWeeklyRankServiceServer 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.
@ -5075,22 +5075,22 @@ type AdminAgencyOpeningServiceServer interface {
type UnimplementedAdminAgencyOpeningServiceServer struct{}
func (UnimplementedAdminAgencyOpeningServiceServer) ListAgencyOpeningCycles(context.Context, *ListAgencyOpeningCyclesRequest) (*ListAgencyOpeningCyclesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListAgencyOpeningCycles not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListAgencyOpeningCycles not implemented")
}
func (UnimplementedAdminAgencyOpeningServiceServer) CreateAgencyOpeningCycle(context.Context, *UpsertAgencyOpeningCycleRequest) (*UpsertAgencyOpeningCycleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateAgencyOpeningCycle not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateAgencyOpeningCycle not implemented")
}
func (UnimplementedAdminAgencyOpeningServiceServer) GetAgencyOpeningCycle(context.Context, *GetAgencyOpeningCycleRequest) (*GetAgencyOpeningCycleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetAgencyOpeningCycle not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetAgencyOpeningCycle not implemented")
}
func (UnimplementedAdminAgencyOpeningServiceServer) UpdateAgencyOpeningCycle(context.Context, *UpsertAgencyOpeningCycleRequest) (*UpsertAgencyOpeningCycleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateAgencyOpeningCycle not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateAgencyOpeningCycle not implemented")
}
func (UnimplementedAdminAgencyOpeningServiceServer) SetAgencyOpeningCycleStatus(context.Context, *SetAgencyOpeningCycleStatusRequest) (*SetAgencyOpeningCycleStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetAgencyOpeningCycleStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetAgencyOpeningCycleStatus not implemented")
}
func (UnimplementedAdminAgencyOpeningServiceServer) ListAgencyOpeningApplications(context.Context, *ListAgencyOpeningApplicationsRequest) (*ListAgencyOpeningApplicationsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListAgencyOpeningApplications not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListAgencyOpeningApplications not implemented")
}
func (UnimplementedAdminAgencyOpeningServiceServer) mustEmbedUnimplementedAdminAgencyOpeningServiceServer() {
}
@ -5104,7 +5104,7 @@ type UnsafeAdminAgencyOpeningServiceServer interface {
}
func RegisterAdminAgencyOpeningServiceServer(s grpc.ServiceRegistrar, srv AdminAgencyOpeningServiceServer) {
// If the following call panics, it indicates UnimplementedAdminAgencyOpeningServiceServer was
// If the following call pancis, it indicates UnimplementedAdminAgencyOpeningServiceServer 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.
@ -5320,10 +5320,10 @@ type SevenDayCheckInServiceServer interface {
type UnimplementedSevenDayCheckInServiceServer struct{}
func (UnimplementedSevenDayCheckInServiceServer) GetSevenDayCheckInStatus(context.Context, *GetSevenDayCheckInStatusRequest) (*GetSevenDayCheckInStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetSevenDayCheckInStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetSevenDayCheckInStatus not implemented")
}
func (UnimplementedSevenDayCheckInServiceServer) SignSevenDayCheckIn(context.Context, *SignSevenDayCheckInRequest) (*SignSevenDayCheckInResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SignSevenDayCheckIn not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SignSevenDayCheckIn not implemented")
}
func (UnimplementedSevenDayCheckInServiceServer) mustEmbedUnimplementedSevenDayCheckInServiceServer() {
}
@ -5337,7 +5337,7 @@ type UnsafeSevenDayCheckInServiceServer interface {
}
func RegisterSevenDayCheckInServiceServer(s grpc.ServiceRegistrar, srv SevenDayCheckInServiceServer) {
// If the following call panics, it indicates UnimplementedSevenDayCheckInServiceServer was
// If the following call pancis, 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.
@ -5478,13 +5478,13 @@ type AdminSevenDayCheckInServiceServer interface {
type UnimplementedAdminSevenDayCheckInServiceServer struct{}
func (UnimplementedAdminSevenDayCheckInServiceServer) GetSevenDayCheckInConfig(context.Context, *GetSevenDayCheckInConfigRequest) (*GetSevenDayCheckInConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetSevenDayCheckInConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetSevenDayCheckInConfig not implemented")
}
func (UnimplementedAdminSevenDayCheckInServiceServer) UpdateSevenDayCheckInConfig(context.Context, *UpdateSevenDayCheckInConfigRequest) (*UpdateSevenDayCheckInConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateSevenDayCheckInConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateSevenDayCheckInConfig not implemented")
}
func (UnimplementedAdminSevenDayCheckInServiceServer) ListSevenDayCheckInClaims(context.Context, *ListSevenDayCheckInClaimsRequest) (*ListSevenDayCheckInClaimsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListSevenDayCheckInClaims not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListSevenDayCheckInClaims not implemented")
}
func (UnimplementedAdminSevenDayCheckInServiceServer) mustEmbedUnimplementedAdminSevenDayCheckInServiceServer() {
}
@ -5498,7 +5498,7 @@ type UnsafeAdminSevenDayCheckInServiceServer interface {
}
func RegisterAdminSevenDayCheckInServiceServer(s grpc.ServiceRegistrar, srv AdminSevenDayCheckInServiceServer) {
// If the following call panics, it indicates UnimplementedAdminSevenDayCheckInServiceServer was
// If the following call pancis, 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.
@ -5674,16 +5674,16 @@ type AdminGrowthLevelServiceServer interface {
type UnimplementedAdminGrowthLevelServiceServer struct{}
func (UnimplementedAdminGrowthLevelServiceServer) ListLevelConfig(context.Context, *ListLevelConfigRequest) (*ListLevelConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListLevelConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListLevelConfig not implemented")
}
func (UnimplementedAdminGrowthLevelServiceServer) UpsertLevelTrack(context.Context, *UpsertLevelTrackRequest) (*UpsertLevelTrackResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertLevelTrack not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertLevelTrack not implemented")
}
func (UnimplementedAdminGrowthLevelServiceServer) UpsertLevelRule(context.Context, *UpsertLevelRuleRequest) (*UpsertLevelRuleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertLevelRule not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertLevelRule not implemented")
}
func (UnimplementedAdminGrowthLevelServiceServer) UpsertLevelTier(context.Context, *UpsertLevelTierRequest) (*UpsertLevelTierResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertLevelTier not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertLevelTier not implemented")
}
func (UnimplementedAdminGrowthLevelServiceServer) mustEmbedUnimplementedAdminGrowthLevelServiceServer() {
}
@ -5697,7 +5697,7 @@ type UnsafeAdminGrowthLevelServiceServer interface {
}
func RegisterAdminGrowthLevelServiceServer(s grpc.ServiceRegistrar, srv AdminGrowthLevelServiceServer) {
// If the following call panics, it indicates UnimplementedAdminGrowthLevelServiceServer was
// If the following call pancis, 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.
@ -5869,10 +5869,10 @@ type AdminAchievementServiceServer interface {
type UnimplementedAdminAchievementServiceServer struct{}
func (UnimplementedAdminAchievementServiceServer) ListAchievementDefinitions(context.Context, *ListAchievementsRequest) (*ListAchievementsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListAchievementDefinitions not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListAchievementDefinitions not implemented")
}
func (UnimplementedAdminAchievementServiceServer) UpsertAchievementDefinition(context.Context, *UpsertAchievementDefinitionRequest) (*UpsertAchievementDefinitionResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertAchievementDefinition not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertAchievementDefinition not implemented")
}
func (UnimplementedAdminAchievementServiceServer) mustEmbedUnimplementedAdminAchievementServiceServer() {
}
@ -5886,7 +5886,7 @@ type UnsafeAdminAchievementServiceServer interface {
}
func RegisterAdminAchievementServiceServer(s grpc.ServiceRegistrar, srv AdminAchievementServiceServer) {
// If the following call panics, it indicates UnimplementedAdminAchievementServiceServer was
// If the following call pancis, 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.
@ -6053,19 +6053,19 @@ type AdminLuckyGiftServiceServer interface {
type UnimplementedAdminLuckyGiftServiceServer struct{}
func (UnimplementedAdminLuckyGiftServiceServer) GetLuckyGiftConfig(context.Context, *GetLuckyGiftConfigRequest) (*GetLuckyGiftConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetLuckyGiftConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetLuckyGiftConfig not implemented")
}
func (UnimplementedAdminLuckyGiftServiceServer) UpsertLuckyGiftConfig(context.Context, *UpsertLuckyGiftConfigRequest) (*UpsertLuckyGiftConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertLuckyGiftConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertLuckyGiftConfig not implemented")
}
func (UnimplementedAdminLuckyGiftServiceServer) ListLuckyGiftConfigs(context.Context, *ListLuckyGiftConfigsRequest) (*ListLuckyGiftConfigsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListLuckyGiftConfigs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListLuckyGiftConfigs not implemented")
}
func (UnimplementedAdminLuckyGiftServiceServer) ListLuckyGiftDraws(context.Context, *ListLuckyGiftDrawsRequest) (*ListLuckyGiftDrawsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListLuckyGiftDraws not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListLuckyGiftDraws not implemented")
}
func (UnimplementedAdminLuckyGiftServiceServer) GetLuckyGiftDrawSummary(context.Context, *GetLuckyGiftDrawSummaryRequest) (*GetLuckyGiftDrawSummaryResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetLuckyGiftDrawSummary not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetLuckyGiftDrawSummary not implemented")
}
func (UnimplementedAdminLuckyGiftServiceServer) mustEmbedUnimplementedAdminLuckyGiftServiceServer() {}
func (UnimplementedAdminLuckyGiftServiceServer) testEmbeddedByValue() {}
@ -6078,7 +6078,7 @@ type UnsafeAdminLuckyGiftServiceServer interface {
}
func RegisterAdminLuckyGiftServiceServer(s grpc.ServiceRegistrar, srv AdminLuckyGiftServiceServer) {
// If the following call panics, it indicates UnimplementedAdminLuckyGiftServiceServer was
// If the following call pancis, 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

View File

@ -170,6 +170,8 @@ message RoomGiftSent {
bool is_robot_gift = 20;
// synthetic_lucky_gift
bool synthetic_lucky_gift = 21;
// real_room_robot_gift Databi
bool real_room_robot_gift = 22;
}
// RoomRobotLuckyGiftDrawn

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc-gen-go-grpc v1.5.1
// - protoc v7.35.0
// source: proto/game/v1/game.proto
@ -271,55 +271,55 @@ type GameAppServiceServer interface {
type UnimplementedGameAppServiceServer struct{}
func (UnimplementedGameAppServiceServer) ListGames(context.Context, *ListGamesRequest) (*ListGamesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListGames not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListGames not implemented")
}
func (UnimplementedGameAppServiceServer) ListRecentGames(context.Context, *ListRecentGamesRequest) (*ListGamesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRecentGames not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRecentGames not implemented")
}
func (UnimplementedGameAppServiceServer) ListExploreWinners(context.Context, *ListExploreWinnersRequest) (*ListExploreWinnersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListExploreWinners not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListExploreWinners not implemented")
}
func (UnimplementedGameAppServiceServer) GetBridgeScript(context.Context, *GetBridgeScriptRequest) (*GetBridgeScriptResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetBridgeScript not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetBridgeScript not implemented")
}
func (UnimplementedGameAppServiceServer) LaunchGame(context.Context, *LaunchGameRequest) (*LaunchGameResponse, error) {
return nil, status.Error(codes.Unimplemented, "method LaunchGame not implemented")
return nil, status.Errorf(codes.Unimplemented, "method LaunchGame not implemented")
}
func (UnimplementedGameAppServiceServer) GetDiceConfig(context.Context, *GetDiceConfigRequest) (*DiceConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetDiceConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetDiceConfig not implemented")
}
func (UnimplementedGameAppServiceServer) MatchDice(context.Context, *MatchDiceRequest) (*DiceMatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method MatchDice not implemented")
return nil, status.Errorf(codes.Unimplemented, "method MatchDice not implemented")
}
func (UnimplementedGameAppServiceServer) CreateDiceMatch(context.Context, *CreateDiceMatchRequest) (*DiceMatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateDiceMatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateDiceMatch not implemented")
}
func (UnimplementedGameAppServiceServer) JoinDiceMatch(context.Context, *JoinDiceMatchRequest) (*DiceMatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method JoinDiceMatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method JoinDiceMatch not implemented")
}
func (UnimplementedGameAppServiceServer) GetDiceMatch(context.Context, *GetDiceMatchRequest) (*DiceMatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetDiceMatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetDiceMatch not implemented")
}
func (UnimplementedGameAppServiceServer) RollDiceMatch(context.Context, *RollDiceMatchRequest) (*DiceMatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RollDiceMatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RollDiceMatch not implemented")
}
func (UnimplementedGameAppServiceServer) CancelDiceMatch(context.Context, *CancelDiceMatchRequest) (*DiceMatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CancelDiceMatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CancelDiceMatch not implemented")
}
func (UnimplementedGameAppServiceServer) GetRoomRPSConfig(context.Context, *GetRoomRPSConfigRequest) (*RoomRPSConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoomRPSConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRoomRPSConfig not implemented")
}
func (UnimplementedGameAppServiceServer) ListRoomRPSChallenges(context.Context, *ListRoomRPSChallengesRequest) (*ListRoomRPSChallengesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomRPSChallenges not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomRPSChallenges not implemented")
}
func (UnimplementedGameAppServiceServer) CreateRoomRPSChallenge(context.Context, *CreateRoomRPSChallengeRequest) (*RoomRPSChallengeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateRoomRPSChallenge not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateRoomRPSChallenge not implemented")
}
func (UnimplementedGameAppServiceServer) AcceptRoomRPSChallenge(context.Context, *AcceptRoomRPSChallengeRequest) (*RoomRPSChallengeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AcceptRoomRPSChallenge not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AcceptRoomRPSChallenge not implemented")
}
func (UnimplementedGameAppServiceServer) GetRoomRPSChallenge(context.Context, *GetRoomRPSChallengeRequest) (*RoomRPSChallengeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoomRPSChallenge not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRoomRPSChallenge not implemented")
}
func (UnimplementedGameAppServiceServer) mustEmbedUnimplementedGameAppServiceServer() {}
func (UnimplementedGameAppServiceServer) testEmbeddedByValue() {}
@ -332,7 +332,7 @@ type UnsafeGameAppServiceServer interface {
}
func RegisterGameAppServiceServer(s grpc.ServiceRegistrar, srv GameAppServiceServer) {
// If the following call panics, it indicates UnimplementedGameAppServiceServer was
// If the following call pancis, 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.
@ -773,7 +773,7 @@ type GameCallbackServiceServer interface {
type UnimplementedGameCallbackServiceServer struct{}
func (UnimplementedGameCallbackServiceServer) HandleCallback(context.Context, *CallbackRequest) (*CallbackResponse, error) {
return nil, status.Error(codes.Unimplemented, "method HandleCallback not implemented")
return nil, status.Errorf(codes.Unimplemented, "method HandleCallback not implemented")
}
func (UnimplementedGameCallbackServiceServer) mustEmbedUnimplementedGameCallbackServiceServer() {}
func (UnimplementedGameCallbackServiceServer) testEmbeddedByValue() {}
@ -786,7 +786,7 @@ type UnsafeGameCallbackServiceServer interface {
}
func RegisterGameCallbackServiceServer(s grpc.ServiceRegistrar, srv GameCallbackServiceServer) {
// If the following call panics, it indicates UnimplementedGameCallbackServiceServer was
// If the following call pancis, 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.
@ -879,7 +879,7 @@ type GameCronServiceServer interface {
type UnimplementedGameCronServiceServer struct{}
func (UnimplementedGameCronServiceServer) ProcessLevelEventOutboxBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessLevelEventOutboxBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessLevelEventOutboxBatch not implemented")
}
func (UnimplementedGameCronServiceServer) mustEmbedUnimplementedGameCronServiceServer() {}
func (UnimplementedGameCronServiceServer) testEmbeddedByValue() {}
@ -892,7 +892,7 @@ type UnsafeGameCronServiceServer interface {
}
func RegisterGameCronServiceServer(s grpc.ServiceRegistrar, srv GameCronServiceServer) {
// If the following call panics, it indicates UnimplementedGameCronServiceServer was
// If the following call pancis, 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.
@ -1267,73 +1267,73 @@ type GameAdminServiceServer interface {
type UnimplementedGameAdminServiceServer struct{}
func (UnimplementedGameAdminServiceServer) ListPlatforms(context.Context, *ListPlatformsRequest) (*ListPlatformsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListPlatforms not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListPlatforms not implemented")
}
func (UnimplementedGameAdminServiceServer) UpsertPlatform(context.Context, *UpsertPlatformRequest) (*PlatformResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertPlatform not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertPlatform not implemented")
}
func (UnimplementedGameAdminServiceServer) ListCatalog(context.Context, *ListCatalogRequest) (*ListCatalogResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCatalog not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCatalog not implemented")
}
func (UnimplementedGameAdminServiceServer) UpsertCatalog(context.Context, *UpsertCatalogRequest) (*CatalogResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertCatalog not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertCatalog not implemented")
}
func (UnimplementedGameAdminServiceServer) SetGameStatus(context.Context, *SetGameStatusRequest) (*CatalogResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetGameStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetGameStatus not implemented")
}
func (UnimplementedGameAdminServiceServer) DeleteCatalog(context.Context, *DeleteCatalogRequest) (*DeleteCatalogResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteCatalog not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteCatalog not implemented")
}
func (UnimplementedGameAdminServiceServer) ListSelfGames(context.Context, *ListSelfGamesRequest) (*ListSelfGamesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListSelfGames not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListSelfGames not implemented")
}
func (UnimplementedGameAdminServiceServer) UpdateDiceConfig(context.Context, *UpdateDiceConfigRequest) (*DiceConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateDiceConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateDiceConfig not implemented")
}
func (UnimplementedGameAdminServiceServer) GetSelfGameNewUserPolicy(context.Context, *GetSelfGameNewUserPolicyRequest) (*SelfGameNewUserPolicyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetSelfGameNewUserPolicy not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetSelfGameNewUserPolicy not implemented")
}
func (UnimplementedGameAdminServiceServer) UpdateSelfGameNewUserPolicy(context.Context, *UpdateSelfGameNewUserPolicyRequest) (*SelfGameNewUserPolicyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateSelfGameNewUserPolicy not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateSelfGameNewUserPolicy not implemented")
}
func (UnimplementedGameAdminServiceServer) ListSelfGameStakePools(context.Context, *ListSelfGameStakePoolsRequest) (*ListSelfGameStakePoolsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListSelfGameStakePools not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListSelfGameStakePools not implemented")
}
func (UnimplementedGameAdminServiceServer) UpdateSelfGameStakePool(context.Context, *UpdateSelfGameStakePoolRequest) (*SelfGameStakePoolResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateSelfGameStakePool not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateSelfGameStakePool not implemented")
}
func (UnimplementedGameAdminServiceServer) AdjustSelfGameStakePool(context.Context, *AdjustSelfGameStakePoolRequest) (*AdjustSelfGameStakePoolResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdjustSelfGameStakePool not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdjustSelfGameStakePool not implemented")
}
func (UnimplementedGameAdminServiceServer) ListDiceRobots(context.Context, *ListDiceRobotsRequest) (*ListDiceRobotsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListDiceRobots not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListDiceRobots not implemented")
}
func (UnimplementedGameAdminServiceServer) RegisterDiceRobots(context.Context, *RegisterDiceRobotsRequest) (*RegisterDiceRobotsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RegisterDiceRobots not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RegisterDiceRobots not implemented")
}
func (UnimplementedGameAdminServiceServer) SetDiceRobotStatus(context.Context, *SetDiceRobotStatusRequest) (*DiceRobotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetDiceRobotStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetDiceRobotStatus not implemented")
}
func (UnimplementedGameAdminServiceServer) DeleteDiceRobot(context.Context, *DeleteDiceRobotRequest) (*DeleteDiceRobotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteDiceRobot not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteDiceRobot not implemented")
}
func (UnimplementedGameAdminServiceServer) GetRoomRPSConfig(context.Context, *GetRoomRPSConfigRequest) (*RoomRPSConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoomRPSConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRoomRPSConfig not implemented")
}
func (UnimplementedGameAdminServiceServer) UpdateRoomRPSConfig(context.Context, *UpdateRoomRPSConfigRequest) (*RoomRPSConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateRoomRPSConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateRoomRPSConfig not implemented")
}
func (UnimplementedGameAdminServiceServer) ListRoomRPSChallenges(context.Context, *ListRoomRPSChallengesRequest) (*ListRoomRPSChallengesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomRPSChallenges not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomRPSChallenges not implemented")
}
func (UnimplementedGameAdminServiceServer) GetRoomRPSChallenge(context.Context, *GetRoomRPSChallengeRequest) (*RoomRPSChallengeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoomRPSChallenge not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRoomRPSChallenge not implemented")
}
func (UnimplementedGameAdminServiceServer) RetryRoomRPSSettlement(context.Context, *RetryRoomRPSSettlementRequest) (*RoomRPSChallengeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RetryRoomRPSSettlement not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RetryRoomRPSSettlement not implemented")
}
func (UnimplementedGameAdminServiceServer) ExpireRoomRPSChallenge(context.Context, *ExpireRoomRPSChallengeRequest) (*RoomRPSChallengeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ExpireRoomRPSChallenge not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ExpireRoomRPSChallenge not implemented")
}
func (UnimplementedGameAdminServiceServer) mustEmbedUnimplementedGameAdminServiceServer() {}
func (UnimplementedGameAdminServiceServer) testEmbeddedByValue() {}
@ -1346,7 +1346,7 @@ type UnsafeGameAdminServiceServer interface {
}
func RegisterGameAdminServiceServer(s grpc.ServiceRegistrar, srv GameAdminServiceServer) {
// If the following call panics, it indicates UnimplementedGameAdminServiceServer was
// If the following call pancis, 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.

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc-gen-go v1.35.1
// protoc v7.35.0
// source: proto/robot/v1/robot.proto
@ -11,7 +11,6 @@ import (
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
@ -23,14 +22,15 @@ const (
// RequestMeta 是 robot-service 内部 RPC 的租户和追踪上下文;不要把 app_code 放到业务字段里绕过统一鉴权链路。
type RequestMeta struct {
state protoimpl.MessageState `protogen:"open.v1"`
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
Caller string `protobuf:"bytes,2,opt,name=caller,proto3" json:"caller,omitempty"`
ActorUserId int64 `protobuf:"varint,3,opt,name=actor_user_id,json=actorUserId,proto3" json:"actor_user_id,omitempty"`
SentAtMs int64 `protobuf:"varint,4,opt,name=sent_at_ms,json=sentAtMs,proto3" json:"sent_at_ms,omitempty"`
AppCode string `protobuf:"bytes,5,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
Caller string `protobuf:"bytes,2,opt,name=caller,proto3" json:"caller,omitempty"`
ActorUserId int64 `protobuf:"varint,3,opt,name=actor_user_id,json=actorUserId,proto3" json:"actor_user_id,omitempty"`
SentAtMs int64 `protobuf:"varint,4,opt,name=sent_at_ms,json=sentAtMs,proto3" json:"sent_at_ms,omitempty"`
AppCode string `protobuf:"bytes,5,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"`
}
func (x *RequestMeta) Reset() {
@ -99,20 +99,21 @@ func (x *RequestMeta) GetAppCode() string {
}
type Robot struct {
state protoimpl.MessageState `protogen:"open.v1"`
AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"`
RobotScope string `protobuf:"bytes,2,opt,name=robot_scope,json=robotScope,proto3" json:"robot_scope,omitempty"`
GameId string `protobuf:"bytes,3,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
RoomScene string `protobuf:"bytes,4,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
UserId int64 `protobuf:"varint,5,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"`
CreatedByAdminId int64 `protobuf:"varint,7,opt,name=created_by_admin_id,json=createdByAdminId,proto3" json:"created_by_admin_id,omitempty"`
CreatedAtMs int64 `protobuf:"varint,8,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"`
UpdatedAtMs int64 `protobuf:"varint,9,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"`
LastUsedAtMs int64 `protobuf:"varint,10,opt,name=last_used_at_ms,json=lastUsedAtMs,proto3" json:"last_used_at_ms,omitempty"`
UsedCount int64 `protobuf:"varint,11,opt,name=used_count,json=usedCount,proto3" json:"used_count,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"`
RobotScope string `protobuf:"bytes,2,opt,name=robot_scope,json=robotScope,proto3" json:"robot_scope,omitempty"`
GameId string `protobuf:"bytes,3,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
RoomScene string `protobuf:"bytes,4,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
UserId int64 `protobuf:"varint,5,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"`
CreatedByAdminId int64 `protobuf:"varint,7,opt,name=created_by_admin_id,json=createdByAdminId,proto3" json:"created_by_admin_id,omitempty"`
CreatedAtMs int64 `protobuf:"varint,8,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"`
UpdatedAtMs int64 `protobuf:"varint,9,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"`
LastUsedAtMs int64 `protobuf:"varint,10,opt,name=last_used_at_ms,json=lastUsedAtMs,proto3" json:"last_used_at_ms,omitempty"`
UsedCount int64 `protobuf:"varint,11,opt,name=used_count,json=usedCount,proto3" json:"used_count,omitempty"`
}
func (x *Robot) Reset() {
@ -223,14 +224,15 @@ func (x *Robot) GetUsedCount() int64 {
}
type ListGameRobotsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"`
PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
Cursor string `protobuf:"bytes,5,opt,name=cursor,proto3" json:"cursor,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"`
PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
Cursor string `protobuf:"bytes,5,opt,name=cursor,proto3" json:"cursor,omitempty"`
}
func (x *ListGameRobotsRequest) Reset() {
@ -299,12 +301,13 @@ func (x *ListGameRobotsRequest) GetCursor() string {
}
type ListGameRobotsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Robots []*Robot `protobuf:"bytes,1,rep,name=robots,proto3" json:"robots,omitempty"`
NextCursor string `protobuf:"bytes,2,opt,name=next_cursor,json=nextCursor,proto3" json:"next_cursor,omitempty"`
ServerTimeMs int64 `protobuf:"varint,3,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Robots []*Robot `protobuf:"bytes,1,rep,name=robots,proto3" json:"robots,omitempty"`
NextCursor string `protobuf:"bytes,2,opt,name=next_cursor,json=nextCursor,proto3" json:"next_cursor,omitempty"`
ServerTimeMs int64 `protobuf:"varint,3,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
}
func (x *ListGameRobotsResponse) Reset() {
@ -359,12 +362,13 @@ func (x *ListGameRobotsResponse) GetServerTimeMs() int64 {
}
type RegisterGameRobotsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
UserIds []int64 `protobuf:"varint,3,rep,packed,name=user_ids,json=userIds,proto3" json:"user_ids,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
UserIds []int64 `protobuf:"varint,3,rep,packed,name=user_ids,json=userIds,proto3" json:"user_ids,omitempty"`
}
func (x *RegisterGameRobotsRequest) Reset() {
@ -419,11 +423,12 @@ func (x *RegisterGameRobotsRequest) GetUserIds() []int64 {
}
type RegisterGameRobotsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Robots []*Robot `protobuf:"bytes,1,rep,name=robots,proto3" json:"robots,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Robots []*Robot `protobuf:"bytes,1,rep,name=robots,proto3" json:"robots,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
}
func (x *RegisterGameRobotsResponse) Reset() {
@ -471,14 +476,15 @@ func (x *RegisterGameRobotsResponse) GetServerTimeMs() int64 {
}
type PickGameRobotRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
MatchId string `protobuf:"bytes,3,opt,name=match_id,json=matchId,proto3" json:"match_id,omitempty"`
SelectedAtMs int64 `protobuf:"varint,4,opt,name=selected_at_ms,json=selectedAtMs,proto3" json:"selected_at_ms,omitempty"`
ExcludeUserIds []int64 `protobuf:"varint,5,rep,packed,name=exclude_user_ids,json=excludeUserIds,proto3" json:"exclude_user_ids,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
MatchId string `protobuf:"bytes,3,opt,name=match_id,json=matchId,proto3" json:"match_id,omitempty"`
SelectedAtMs int64 `protobuf:"varint,4,opt,name=selected_at_ms,json=selectedAtMs,proto3" json:"selected_at_ms,omitempty"`
ExcludeUserIds []int64 `protobuf:"varint,5,rep,packed,name=exclude_user_ids,json=excludeUserIds,proto3" json:"exclude_user_ids,omitempty"`
}
func (x *PickGameRobotRequest) Reset() {
@ -547,11 +553,12 @@ func (x *PickGameRobotRequest) GetExcludeUserIds() []int64 {
}
type GameRobotResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Robot *Robot `protobuf:"bytes,1,opt,name=robot,proto3" json:"robot,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Robot *Robot `protobuf:"bytes,1,opt,name=robot,proto3" json:"robot,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
}
func (x *GameRobotResponse) Reset() {
@ -599,13 +606,14 @@ func (x *GameRobotResponse) GetServerTimeMs() int64 {
}
type SetGameRobotStatusRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
}
func (x *SetGameRobotStatusRequest) Reset() {
@ -667,12 +675,13 @@ func (x *SetGameRobotStatusRequest) GetStatus() string {
}
type DeleteGameRobotRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
GameId string `protobuf:"bytes,2,opt,name=game_id,json=gameId,proto3" json:"game_id,omitempty"`
UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
}
func (x *DeleteGameRobotRequest) Reset() {
@ -727,11 +736,12 @@ func (x *DeleteGameRobotRequest) GetUserId() int64 {
}
type DeleteGameRobotResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
}
func (x *DeleteGameRobotResponse) Reset() {
@ -779,14 +789,15 @@ func (x *DeleteGameRobotResponse) GetServerTimeMs() int64 {
}
type ListRoomRobotsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"`
PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
Cursor string `protobuf:"bytes,5,opt,name=cursor,proto3" json:"cursor,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"`
PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
Cursor string `protobuf:"bytes,5,opt,name=cursor,proto3" json:"cursor,omitempty"`
}
func (x *ListRoomRobotsRequest) Reset() {
@ -855,12 +866,13 @@ func (x *ListRoomRobotsRequest) GetCursor() string {
}
type ListRoomRobotsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Robots []*Robot `protobuf:"bytes,1,rep,name=robots,proto3" json:"robots,omitempty"`
NextCursor string `protobuf:"bytes,2,opt,name=next_cursor,json=nextCursor,proto3" json:"next_cursor,omitempty"`
ServerTimeMs int64 `protobuf:"varint,3,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Robots []*Robot `protobuf:"bytes,1,rep,name=robots,proto3" json:"robots,omitempty"`
NextCursor string `protobuf:"bytes,2,opt,name=next_cursor,json=nextCursor,proto3" json:"next_cursor,omitempty"`
ServerTimeMs int64 `protobuf:"varint,3,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
}
func (x *ListRoomRobotsResponse) Reset() {
@ -915,12 +927,13 @@ func (x *ListRoomRobotsResponse) GetServerTimeMs() int64 {
}
type RegisterRoomRobotsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
UserIds []int64 `protobuf:"varint,3,rep,packed,name=user_ids,json=userIds,proto3" json:"user_ids,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
UserIds []int64 `protobuf:"varint,3,rep,packed,name=user_ids,json=userIds,proto3" json:"user_ids,omitempty"`
}
func (x *RegisterRoomRobotsRequest) Reset() {
@ -975,11 +988,12 @@ func (x *RegisterRoomRobotsRequest) GetUserIds() []int64 {
}
type RegisterRoomRobotsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Robots []*Robot `protobuf:"bytes,1,rep,name=robots,proto3" json:"robots,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Robots []*Robot `protobuf:"bytes,1,rep,name=robots,proto3" json:"robots,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
}
func (x *RegisterRoomRobotsResponse) Reset() {
@ -1027,13 +1041,14 @@ func (x *RegisterRoomRobotsResponse) GetServerTimeMs() int64 {
}
type SetRoomRobotStatusRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
}
func (x *SetRoomRobotStatusRequest) Reset() {
@ -1095,12 +1110,13 @@ func (x *SetRoomRobotStatusRequest) GetStatus() string {
}
type DeleteRoomRobotRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
UserId int64 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
}
func (x *DeleteRoomRobotRequest) Reset() {
@ -1155,11 +1171,12 @@ func (x *DeleteRoomRobotRequest) GetUserId() int64 {
}
type DeleteRoomRobotResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
}
func (x *DeleteRoomRobotResponse) Reset() {
@ -1207,13 +1224,14 @@ func (x *DeleteRoomRobotResponse) GetServerTimeMs() int64 {
}
type PickRoomRobotRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
RoomId string `protobuf:"bytes,3,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"`
SelectedAtMs int64 `protobuf:"varint,4,opt,name=selected_at_ms,json=selectedAtMs,proto3" json:"selected_at_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
RoomScene string `protobuf:"bytes,2,opt,name=room_scene,json=roomScene,proto3" json:"room_scene,omitempty"`
RoomId string `protobuf:"bytes,3,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"`
SelectedAtMs int64 `protobuf:"varint,4,opt,name=selected_at_ms,json=selectedAtMs,proto3" json:"selected_at_ms,omitempty"`
}
func (x *PickRoomRobotRequest) Reset() {
@ -1275,11 +1293,12 @@ func (x *PickRoomRobotRequest) GetSelectedAtMs() int64 {
}
type RoomRobotResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Robot *Robot `protobuf:"bytes,1,opt,name=robot,proto3" json:"robot,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Robot *Robot `protobuf:"bytes,1,opt,name=robot,proto3" json:"robot,omitempty"`
ServerTimeMs int64 `protobuf:"varint,2,opt,name=server_time_ms,json=serverTimeMs,proto3" json:"server_time_ms,omitempty"`
}
func (x *RoomRobotResponse) Reset() {
@ -1328,136 +1347,276 @@ func (x *RoomRobotResponse) GetServerTimeMs() int64 {
var File_proto_robot_v1_robot_proto protoreflect.FileDescriptor
const file_proto_robot_v1_robot_proto_rawDesc = "" +
"\n" +
"\x1aproto/robot/v1/robot.proto\x12\x0ehyapp.robot.v1\"\xa1\x01\n" +
"\vRequestMeta\x12\x1d\n" +
"\n" +
"request_id\x18\x01 \x01(\tR\trequestId\x12\x16\n" +
"\x06caller\x18\x02 \x01(\tR\x06caller\x12\"\n" +
"\ractor_user_id\x18\x03 \x01(\x03R\vactorUserId\x12\x1c\n" +
"\n" +
"sent_at_ms\x18\x04 \x01(\x03R\bsentAtMs\x12\x19\n" +
"\bapp_code\x18\x05 \x01(\tR\aappCode\"\xe9\x02\n" +
"\x05Robot\x12\x19\n" +
"\bapp_code\x18\x01 \x01(\tR\aappCode\x12\x1f\n" +
"\vrobot_scope\x18\x02 \x01(\tR\n" +
"robotScope\x12\x17\n" +
"\agame_id\x18\x03 \x01(\tR\x06gameId\x12\x1d\n" +
"\n" +
"room_scene\x18\x04 \x01(\tR\troomScene\x12\x17\n" +
"\auser_id\x18\x05 \x01(\x03R\x06userId\x12\x16\n" +
"\x06status\x18\x06 \x01(\tR\x06status\x12-\n" +
"\x13created_by_admin_id\x18\a \x01(\x03R\x10createdByAdminId\x12\"\n" +
"\rcreated_at_ms\x18\b \x01(\x03R\vcreatedAtMs\x12\"\n" +
"\rupdated_at_ms\x18\t \x01(\x03R\vupdatedAtMs\x12%\n" +
"\x0flast_used_at_ms\x18\n" +
" \x01(\x03R\flastUsedAtMs\x12\x1d\n" +
"\n" +
"used_count\x18\v \x01(\x03R\tusedCount\"\xae\x01\n" +
"\x15ListGameRobotsRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x17\n" +
"\agame_id\x18\x02 \x01(\tR\x06gameId\x12\x16\n" +
"\x06status\x18\x03 \x01(\tR\x06status\x12\x1b\n" +
"\tpage_size\x18\x04 \x01(\x05R\bpageSize\x12\x16\n" +
"\x06cursor\x18\x05 \x01(\tR\x06cursor\"\x8e\x01\n" +
"\x16ListGameRobotsResponse\x12-\n" +
"\x06robots\x18\x01 \x03(\v2\x15.hyapp.robot.v1.RobotR\x06robots\x12\x1f\n" +
"\vnext_cursor\x18\x02 \x01(\tR\n" +
"nextCursor\x12$\n" +
"\x0eserver_time_ms\x18\x03 \x01(\x03R\fserverTimeMs\"\x80\x01\n" +
"\x19RegisterGameRobotsRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x17\n" +
"\agame_id\x18\x02 \x01(\tR\x06gameId\x12\x19\n" +
"\buser_ids\x18\x03 \x03(\x03R\auserIds\"q\n" +
"\x1aRegisterGameRobotsResponse\x12-\n" +
"\x06robots\x18\x01 \x03(\v2\x15.hyapp.robot.v1.RobotR\x06robots\x12$\n" +
"\x0eserver_time_ms\x18\x02 \x01(\x03R\fserverTimeMs\"\xcb\x01\n" +
"\x14PickGameRobotRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x17\n" +
"\agame_id\x18\x02 \x01(\tR\x06gameId\x12\x19\n" +
"\bmatch_id\x18\x03 \x01(\tR\amatchId\x12$\n" +
"\x0eselected_at_ms\x18\x04 \x01(\x03R\fselectedAtMs\x12(\n" +
"\x10exclude_user_ids\x18\x05 \x03(\x03R\x0eexcludeUserIds\"f\n" +
"\x11GameRobotResponse\x12+\n" +
"\x05robot\x18\x01 \x01(\v2\x15.hyapp.robot.v1.RobotR\x05robot\x12$\n" +
"\x0eserver_time_ms\x18\x02 \x01(\x03R\fserverTimeMs\"\x96\x01\n" +
"\x19SetGameRobotStatusRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x17\n" +
"\agame_id\x18\x02 \x01(\tR\x06gameId\x12\x17\n" +
"\auser_id\x18\x03 \x01(\x03R\x06userId\x12\x16\n" +
"\x06status\x18\x04 \x01(\tR\x06status\"{\n" +
"\x16DeleteGameRobotRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x17\n" +
"\agame_id\x18\x02 \x01(\tR\x06gameId\x12\x17\n" +
"\auser_id\x18\x03 \x01(\x03R\x06userId\"Y\n" +
"\x17DeleteGameRobotResponse\x12\x18\n" +
"\adeleted\x18\x01 \x01(\bR\adeleted\x12$\n" +
"\x0eserver_time_ms\x18\x02 \x01(\x03R\fserverTimeMs\"\xb4\x01\n" +
"\x15ListRoomRobotsRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x1d\n" +
"\n" +
"room_scene\x18\x02 \x01(\tR\troomScene\x12\x16\n" +
"\x06status\x18\x03 \x01(\tR\x06status\x12\x1b\n" +
"\tpage_size\x18\x04 \x01(\x05R\bpageSize\x12\x16\n" +
"\x06cursor\x18\x05 \x01(\tR\x06cursor\"\x8e\x01\n" +
"\x16ListRoomRobotsResponse\x12-\n" +
"\x06robots\x18\x01 \x03(\v2\x15.hyapp.robot.v1.RobotR\x06robots\x12\x1f\n" +
"\vnext_cursor\x18\x02 \x01(\tR\n" +
"nextCursor\x12$\n" +
"\x0eserver_time_ms\x18\x03 \x01(\x03R\fserverTimeMs\"\x86\x01\n" +
"\x19RegisterRoomRobotsRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x1d\n" +
"\n" +
"room_scene\x18\x02 \x01(\tR\troomScene\x12\x19\n" +
"\buser_ids\x18\x03 \x03(\x03R\auserIds\"q\n" +
"\x1aRegisterRoomRobotsResponse\x12-\n" +
"\x06robots\x18\x01 \x03(\v2\x15.hyapp.robot.v1.RobotR\x06robots\x12$\n" +
"\x0eserver_time_ms\x18\x02 \x01(\x03R\fserverTimeMs\"\x9c\x01\n" +
"\x19SetRoomRobotStatusRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x1d\n" +
"\n" +
"room_scene\x18\x02 \x01(\tR\troomScene\x12\x17\n" +
"\auser_id\x18\x03 \x01(\x03R\x06userId\x12\x16\n" +
"\x06status\x18\x04 \x01(\tR\x06status\"\x81\x01\n" +
"\x16DeleteRoomRobotRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x1d\n" +
"\n" +
"room_scene\x18\x02 \x01(\tR\troomScene\x12\x17\n" +
"\auser_id\x18\x03 \x01(\x03R\x06userId\"Y\n" +
"\x17DeleteRoomRobotResponse\x12\x18\n" +
"\adeleted\x18\x01 \x01(\bR\adeleted\x12$\n" +
"\x0eserver_time_ms\x18\x02 \x01(\x03R\fserverTimeMs\"\xa5\x01\n" +
"\x14PickRoomRobotRequest\x12/\n" +
"\x04meta\x18\x01 \x01(\v2\x1b.hyapp.robot.v1.RequestMetaR\x04meta\x12\x1d\n" +
"\n" +
"room_scene\x18\x02 \x01(\tR\troomScene\x12\x17\n" +
"\aroom_id\x18\x03 \x01(\tR\x06roomId\x12$\n" +
"\x0eselected_at_ms\x18\x04 \x01(\x03R\fselectedAtMs\"f\n" +
"\x11RoomRobotResponse\x12+\n" +
"\x05robot\x18\x01 \x01(\v2\x15.hyapp.robot.v1.RobotR\x05robot\x12$\n" +
"\x0eserver_time_ms\x18\x02 \x01(\x03R\fserverTimeMs2\x82\x04\n" +
"\x10GameRobotService\x12_\n" +
"\x0eListGameRobots\x12%.hyapp.robot.v1.ListGameRobotsRequest\x1a&.hyapp.robot.v1.ListGameRobotsResponse\x12k\n" +
"\x12RegisterGameRobots\x12).hyapp.robot.v1.RegisterGameRobotsRequest\x1a*.hyapp.robot.v1.RegisterGameRobotsResponse\x12X\n" +
"\rPickGameRobot\x12$.hyapp.robot.v1.PickGameRobotRequest\x1a!.hyapp.robot.v1.GameRobotResponse\x12b\n" +
"\x12SetGameRobotStatus\x12).hyapp.robot.v1.SetGameRobotStatusRequest\x1a!.hyapp.robot.v1.GameRobotResponse\x12b\n" +
"\x0fDeleteGameRobot\x12&.hyapp.robot.v1.DeleteGameRobotRequest\x1a'.hyapp.robot.v1.DeleteGameRobotResponse2\x82\x04\n" +
"\x10RoomRobotService\x12_\n" +
"\x0eListRoomRobots\x12%.hyapp.robot.v1.ListRoomRobotsRequest\x1a&.hyapp.robot.v1.ListRoomRobotsResponse\x12k\n" +
"\x12RegisterRoomRobots\x12).hyapp.robot.v1.RegisterRoomRobotsRequest\x1a*.hyapp.robot.v1.RegisterRoomRobotsResponse\x12X\n" +
"\rPickRoomRobot\x12$.hyapp.robot.v1.PickRoomRobotRequest\x1a!.hyapp.robot.v1.RoomRobotResponse\x12b\n" +
"\x12SetRoomRobotStatus\x12).hyapp.robot.v1.SetRoomRobotStatusRequest\x1a!.hyapp.robot.v1.RoomRobotResponse\x12b\n" +
"\x0fDeleteRoomRobot\x12&.hyapp.robot.v1.DeleteRoomRobotRequest\x1a'.hyapp.robot.v1.DeleteRoomRobotResponseB(Z&hyapp.local/api/proto/robot/v1;robotv1b\x06proto3"
var file_proto_robot_v1_robot_proto_rawDesc = []byte{
0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2f, 0x76, 0x31,
0x2f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x68, 0x79,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x22, 0xa1, 0x01, 0x0a,
0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a,
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x63,
0x61, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x61, 0x6c,
0x6c, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65,
0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f,
0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x74, 0x5f,
0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x65, 0x6e,
0x74, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64,
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65,
0x22, 0xe9, 0x02, 0x0a, 0x05, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70,
0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70,
0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x73,
0x63, 0x6f, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x62, 0x6f,
0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x69,
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12,
0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x18, 0x04, 0x20,
0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x12, 0x17,
0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52,
0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
0x2d, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x64,
0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x22,
0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18,
0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74,
0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x25, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75,
0x73, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0c, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x73, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x1d, 0x0a,
0x0a, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28,
0x03, 0x52, 0x09, 0x75, 0x73, 0x65, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xae, 0x01, 0x0a,
0x15, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62,
0x6f, 0x74, 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, 0x67, 0x61, 0x6d, 0x65, 0x5f,
0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x61, 0x6d, 0x65, 0x49, 0x64,
0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65,
0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67,
0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18,
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x22, 0x8e, 0x01,
0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x72, 0x6f, 0x62, 0x6f,
0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52,
0x06, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x65, 0x78, 0x74, 0x5f,
0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x65,
0x78, 0x74, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 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, 0x22, 0x80,
0x01, 0x0a, 0x19, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x47, 0x61, 0x6d, 0x65, 0x52,
0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04,
0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 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, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x67, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64,
0x73, 0x22, 0x71, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x47, 0x61, 0x6d,
0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x2d, 0x0a, 0x06, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x06, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x12, 0x24,
0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73,
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69,
0x6d, 0x65, 0x4d, 0x73, 0x22, 0xcb, 0x01, 0x0a, 0x14, 0x50, 0x69, 0x63, 0x6b, 0x47, 0x61, 0x6d,
0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a,
0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 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, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x67, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x74, 0x63, 0x68,
0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68,
0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61,
0x74, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x65,
0x63, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x65, 0x78, 0x63, 0x6c,
0x75, 0x64, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03,
0x28, 0x03, 0x52, 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49,
0x64, 0x73, 0x22, 0x66, 0x0a, 0x11, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x72, 0x6f, 0x62, 0x6f, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72,
0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x05, 0x72,
0x6f, 0x62, 0x6f, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x19, 0x53,
0x65, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72,
0x6f, 0x62, 0x6f, 0x74, 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, 0x67, 0x61, 0x6d,
0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x61, 0x6d, 0x65,
0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20,
0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73,
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x22, 0x7b, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x61, 0x6d,
0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a,
0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 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, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x67, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f,
0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64,
0x22, 0x59, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f,
0x62, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f,
0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x15,
0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f,
0x74, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73,
0x63, 0x65, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x6d,
0x53, 0x63, 0x65, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x0a,
0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x75,
0x72, 0x73, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x75, 0x72, 0x73,
0x6f, 0x72, 0x22, 0x8e, 0x01, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52,
0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a,
0x06, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e,
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x6f, 0x62, 0x6f, 0x74, 0x52, 0x06, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b,
0x6e, 0x65, 0x78, 0x74, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 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, 0x22, 0x86, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x65, 0x6e, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x63, 0x65, 0x6e,
0x65, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20,
0x03, 0x28, 0x03, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x22, 0x71, 0x0a, 0x1a,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f,
0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x72, 0x6f,
0x62, 0x6f, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x62, 0x6f,
0x74, 0x52, 0x06, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x22,
0x9c, 0x01, 0x0a, 0x19, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a,
0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x12, 0x17, 0x0a,
0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x81,
0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62,
0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
0x72, 0x6f, 0x62, 0x6f, 0x74, 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, 0x72, 0x6f,
0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65,
0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72,
0x49, 0x64, 0x22, 0x59, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d,
0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07,
0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x22, 0xa5, 0x01,
0x0a, 0x14, 0x50, 0x69, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62,
0x6f, 0x74, 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, 0x72, 0x6f, 0x6f, 0x6d, 0x5f,
0x73, 0x63, 0x65, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x6f,
0x6d, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69,
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12,
0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d,
0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65,
0x64, 0x41, 0x74, 0x4d, 0x73, 0x22, 0x66, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62,
0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x72, 0x6f,
0x62, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x62, 0x6f, 0x74,
0x52, 0x05, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x32, 0x82, 0x04,
0x0a, 0x10, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x12, 0x5f, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f,
0x62, 0x6f, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62,
0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f,
0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x47,
0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62,
0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x47, 0x61,
0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x58, 0x0a, 0x0d, 0x50, 0x69, 0x63, 0x6b, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f,
0x74, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e,
0x76, 0x31, 0x2e, 0x50, 0x69, 0x63, 0x6b, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62,
0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x12, 0x53, 0x65,
0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76,
0x31, 0x2e, 0x53, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79,
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x6d,
0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62,
0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f,
0x74, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e,
0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62,
0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x32, 0x82, 0x04, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x52,
0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52,
0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76,
0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x12, 0x29,
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f,
0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0d, 0x50, 0x69, 0x63, 0x6b, 0x52, 0x6f, 0x6f,
0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72,
0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x6d,
0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68,
0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f,
0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x62, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,
0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f,
0x62, 0x6f, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76,
0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f,
0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72,
0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f,
0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27,
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2e, 0x76, 0x31, 0x2e,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x28, 0x5a, 0x26, 0x68, 0x79, 0x61, 0x70, 0x70,
0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x76,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proto_robot_v1_robot_proto_rawDescOnce sync.Once
file_proto_robot_v1_robot_proto_rawDescData []byte
file_proto_robot_v1_robot_proto_rawDescData = file_proto_robot_v1_robot_proto_rawDesc
)
func file_proto_robot_v1_robot_proto_rawDescGZIP() []byte {
file_proto_robot_v1_robot_proto_rawDescOnce.Do(func() {
file_proto_robot_v1_robot_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_robot_v1_robot_proto_rawDesc), len(file_proto_robot_v1_robot_proto_rawDesc)))
file_proto_robot_v1_robot_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_robot_v1_robot_proto_rawDescData)
})
return file_proto_robot_v1_robot_proto_rawDescData
}
@ -1538,7 +1697,7 @@ func file_proto_robot_v1_robot_proto_init() {
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_robot_v1_robot_proto_rawDesc), len(file_proto_robot_v1_robot_proto_rawDesc)),
RawDescriptor: file_proto_robot_v1_robot_proto_rawDesc,
NumEnums: 0,
NumMessages: 20,
NumExtensions: 0,
@ -1549,6 +1708,7 @@ func file_proto_robot_v1_robot_proto_init() {
MessageInfos: file_proto_robot_v1_robot_proto_msgTypes,
}.Build()
File_proto_robot_v1_robot_proto = out.File
file_proto_robot_v1_robot_proto_rawDesc = nil
file_proto_robot_v1_robot_proto_goTypes = nil
file_proto_robot_v1_robot_proto_depIdxs = nil
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc-gen-go-grpc v1.5.1
// - protoc v7.35.0
// source: proto/robot/v1/robot.proto
@ -115,19 +115,19 @@ type GameRobotServiceServer interface {
type UnimplementedGameRobotServiceServer struct{}
func (UnimplementedGameRobotServiceServer) ListGameRobots(context.Context, *ListGameRobotsRequest) (*ListGameRobotsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListGameRobots not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListGameRobots not implemented")
}
func (UnimplementedGameRobotServiceServer) RegisterGameRobots(context.Context, *RegisterGameRobotsRequest) (*RegisterGameRobotsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RegisterGameRobots not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RegisterGameRobots not implemented")
}
func (UnimplementedGameRobotServiceServer) PickGameRobot(context.Context, *PickGameRobotRequest) (*GameRobotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PickGameRobot not implemented")
return nil, status.Errorf(codes.Unimplemented, "method PickGameRobot not implemented")
}
func (UnimplementedGameRobotServiceServer) SetGameRobotStatus(context.Context, *SetGameRobotStatusRequest) (*GameRobotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetGameRobotStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetGameRobotStatus not implemented")
}
func (UnimplementedGameRobotServiceServer) DeleteGameRobot(context.Context, *DeleteGameRobotRequest) (*DeleteGameRobotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteGameRobot not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteGameRobot not implemented")
}
func (UnimplementedGameRobotServiceServer) mustEmbedUnimplementedGameRobotServiceServer() {}
func (UnimplementedGameRobotServiceServer) testEmbeddedByValue() {}
@ -140,7 +140,7 @@ type UnsafeGameRobotServiceServer interface {
}
func RegisterGameRobotServiceServer(s grpc.ServiceRegistrar, srv GameRobotServiceServer) {
// If the following call panics, it indicates UnimplementedGameRobotServiceServer was
// If the following call pancis, it indicates UnimplementedGameRobotServiceServer 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.
@ -369,19 +369,19 @@ type RoomRobotServiceServer interface {
type UnimplementedRoomRobotServiceServer struct{}
func (UnimplementedRoomRobotServiceServer) ListRoomRobots(context.Context, *ListRoomRobotsRequest) (*ListRoomRobotsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomRobots not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomRobots not implemented")
}
func (UnimplementedRoomRobotServiceServer) RegisterRoomRobots(context.Context, *RegisterRoomRobotsRequest) (*RegisterRoomRobotsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RegisterRoomRobots not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RegisterRoomRobots not implemented")
}
func (UnimplementedRoomRobotServiceServer) PickRoomRobot(context.Context, *PickRoomRobotRequest) (*RoomRobotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PickRoomRobot not implemented")
return nil, status.Errorf(codes.Unimplemented, "method PickRoomRobot not implemented")
}
func (UnimplementedRoomRobotServiceServer) SetRoomRobotStatus(context.Context, *SetRoomRobotStatusRequest) (*RoomRobotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetRoomRobotStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetRoomRobotStatus not implemented")
}
func (UnimplementedRoomRobotServiceServer) DeleteRoomRobot(context.Context, *DeleteRoomRobotRequest) (*DeleteRoomRobotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteRoomRobot not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteRoomRobot not implemented")
}
func (UnimplementedRoomRobotServiceServer) mustEmbedUnimplementedRoomRobotServiceServer() {}
func (UnimplementedRoomRobotServiceServer) testEmbeddedByValue() {}
@ -394,7 +394,7 @@ type UnsafeRoomRobotServiceServer interface {
}
func RegisterRoomRobotServiceServer(s grpc.ServiceRegistrar, srv RoomRobotServiceServer) {
// If the following call panics, it indicates UnimplementedRoomRobotServiceServer was
// If the following call pancis, it indicates UnimplementedRoomRobotServiceServer 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

View File

@ -268,6 +268,59 @@ message AdminUpdateRoomSeatConfigResponse {
int64 server_time_ms = 2;
}
message AdminHumanRoomRobotCountryPool {
string country_code = 1;
repeated int64 robot_user_ids = 2;
}
message AdminHumanRoomRobotConfig {
string app_code = 1;
bool enabled = 2;
int32 candidate_room_max_online = 3;
int32 room_full_stop_online = 4;
int64 robot_stay_min_ms = 5;
int64 robot_stay_max_ms = 6;
int64 robot_replace_min_ms = 7;
int64 robot_replace_max_ms = 8;
int64 normal_gift_interval_ms = 9;
repeated string gift_ids = 10;
repeated string lucky_gift_ids = 11;
repeated string super_lucky_gift_ids = 12;
int64 lucky_combo_min = 13;
int64 lucky_combo_max = 14;
int64 lucky_pause_min_ms = 15;
int64 lucky_pause_max_ms = 16;
int64 max_gift_senders = 17;
repeated AdminHumanRoomRobotCountryPool country_pools = 18;
uint64 updated_by_admin_id = 19;
int64 created_at_ms = 20;
int64 updated_at_ms = 21;
int64 normal_gift_interval_min_ms = 22;
int64 normal_gift_interval_max_ms = 23;
int32 room_target_min_online = 24;
int32 room_target_max_online = 25;
}
message AdminGetHumanRoomRobotConfigRequest {
RequestMeta meta = 1;
}
message AdminGetHumanRoomRobotConfigResponse {
AdminHumanRoomRobotConfig config = 1;
int64 server_time_ms = 2;
}
message AdminUpdateHumanRoomRobotConfigRequest {
RequestMeta meta = 1;
AdminHumanRoomRobotConfig config = 2;
uint64 admin_id = 3;
}
message AdminUpdateHumanRoomRobotConfigResponse {
AdminHumanRoomRobotConfig config = 1;
int64 server_time_ms = 2;
}
message AdminRoomPinRoom {
string room_id = 1;
string room_short_id = 2;
@ -346,6 +399,11 @@ message AdminRobotRoomGiftRule {
int64 lucky_combo_max = 5;
int64 lucky_pause_min_ms = 6;
int64 lucky_pause_max_ms = 7;
int64 robot_stay_min_ms = 8;
int64 robot_stay_max_ms = 9;
int64 robot_replace_min_ms = 10;
int64 robot_replace_max_ms = 11;
int64 max_gift_senders = 12;
}
message AdminRobotRoom {
@ -362,6 +420,8 @@ message AdminRobotRoom {
uint64 created_by_admin_id = 11;
int64 created_at_ms = 12;
int64 updated_at_ms = 13;
int32 active_robot_count = 14;
int32 seat_count = 15;
}
message AdminListRobotRoomsRequest {
@ -388,6 +448,8 @@ message AdminCreateRobotRoomRequest {
int64 visible_region_id = 8;
AdminRobotRoomGiftRule gift_rule = 9;
uint64 admin_id = 10;
string owner_country_code = 11;
int32 seat_count = 12;
}
message AdminCreateRobotRoomResponse {
@ -1005,6 +1067,8 @@ message ListRoomsRequest {
string country_code = 8;
// viewer_country_code
string viewer_country_code = 9;
// all_visible_regions gateway true visible_region_id
bool all_visible_regions = 10;
}
// ListRoomFeedsRequest Mine visited/friend/following/followed
@ -1232,6 +1296,7 @@ service RoomCommandService {
rpc AdminDeleteRoom(AdminDeleteRoomRequest) returns (AdminDeleteRoomResponse);
rpc AdminUpdateRoomRocketConfig(AdminUpdateRoomRocketConfigRequest) returns (AdminUpdateRoomRocketConfigResponse);
rpc AdminUpdateRoomSeatConfig(AdminUpdateRoomSeatConfigRequest) returns (AdminUpdateRoomSeatConfigResponse);
rpc AdminUpdateHumanRoomRobotConfig(AdminUpdateHumanRoomRobotConfigRequest) returns (AdminUpdateHumanRoomRobotConfigResponse);
rpc AdminCreateRoomPin(AdminCreateRoomPinRequest) returns (AdminCreateRoomPinResponse);
rpc AdminCancelRoomPin(AdminCancelRoomPinRequest) returns (AdminCancelRoomPinResponse);
rpc AdminCreateRobotRoom(AdminCreateRobotRoomRequest) returns (AdminCreateRobotRoomResponse);
@ -1268,6 +1333,7 @@ service RoomQueryService {
rpc AdminGetRoom(AdminGetRoomRequest) returns (AdminGetRoomResponse);
rpc AdminGetRoomRocketConfig(AdminGetRoomRocketConfigRequest) returns (AdminGetRoomRocketConfigResponse);
rpc AdminGetRoomSeatConfig(AdminGetRoomSeatConfigRequest) returns (AdminGetRoomSeatConfigResponse);
rpc AdminGetHumanRoomRobotConfig(AdminGetHumanRoomRobotConfigRequest) returns (AdminGetHumanRoomRobotConfigResponse);
rpc AdminListRoomPins(AdminListRoomPinsRequest) returns (AdminListRoomPinsResponse);
rpc AdminListRobotRooms(AdminListRobotRoomsRequest) returns (AdminListRobotRoomsResponse);
rpc AdminFilterAvailableRoomRobots(AdminFilterAvailableRoomRobotsRequest) returns (AdminFilterAvailableRoomRobotsResponse);

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc-gen-go-grpc v1.5.1
// - protoc v7.35.0
// source: proto/room/v1/room.proto
@ -19,40 +19,41 @@ import (
const _ = grpc.SupportPackageIsVersion9
const (
RoomCommandService_CreateRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/CreateRoom"
RoomCommandService_UpdateRoomProfile_FullMethodName = "/hyapp.room.v1.RoomCommandService/UpdateRoomProfile"
RoomCommandService_SaveRoomBackground_FullMethodName = "/hyapp.room.v1.RoomCommandService/SaveRoomBackground"
RoomCommandService_SetRoomBackground_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetRoomBackground"
RoomCommandService_JoinRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/JoinRoom"
RoomCommandService_RoomHeartbeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/RoomHeartbeat"
RoomCommandService_LeaveRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/LeaveRoom"
RoomCommandService_CloseRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/CloseRoom"
RoomCommandService_AdminUpdateRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminUpdateRoom"
RoomCommandService_AdminDeleteRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminDeleteRoom"
RoomCommandService_AdminUpdateRoomRocketConfig_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminUpdateRoomRocketConfig"
RoomCommandService_AdminUpdateRoomSeatConfig_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminUpdateRoomSeatConfig"
RoomCommandService_AdminCreateRoomPin_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminCreateRoomPin"
RoomCommandService_AdminCancelRoomPin_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminCancelRoomPin"
RoomCommandService_AdminCreateRobotRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminCreateRobotRoom"
RoomCommandService_AdminSetRobotRoomStatus_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminSetRobotRoomStatus"
RoomCommandService_MicUp_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicUp"
RoomCommandService_MicDown_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicDown"
RoomCommandService_ChangeMicSeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/ChangeMicSeat"
RoomCommandService_ConfirmMicPublishing_FullMethodName = "/hyapp.room.v1.RoomCommandService/ConfirmMicPublishing"
RoomCommandService_MicHeartbeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicHeartbeat"
RoomCommandService_SetMicMute_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetMicMute"
RoomCommandService_ApplyRTCEvent_FullMethodName = "/hyapp.room.v1.RoomCommandService/ApplyRTCEvent"
RoomCommandService_SetMicSeatLock_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetMicSeatLock"
RoomCommandService_SetChatEnabled_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetChatEnabled"
RoomCommandService_SetRoomPassword_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetRoomPassword"
RoomCommandService_SetRoomAdmin_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetRoomAdmin"
RoomCommandService_MuteUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/MuteUser"
RoomCommandService_KickUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/KickUser"
RoomCommandService_UnbanUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/UnbanUser"
RoomCommandService_SystemEvictUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/SystemEvictUser"
RoomCommandService_SendGift_FullMethodName = "/hyapp.room.v1.RoomCommandService/SendGift"
RoomCommandService_FollowRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/FollowRoom"
RoomCommandService_UnfollowRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/UnfollowRoom"
RoomCommandService_CreateRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/CreateRoom"
RoomCommandService_UpdateRoomProfile_FullMethodName = "/hyapp.room.v1.RoomCommandService/UpdateRoomProfile"
RoomCommandService_SaveRoomBackground_FullMethodName = "/hyapp.room.v1.RoomCommandService/SaveRoomBackground"
RoomCommandService_SetRoomBackground_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetRoomBackground"
RoomCommandService_JoinRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/JoinRoom"
RoomCommandService_RoomHeartbeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/RoomHeartbeat"
RoomCommandService_LeaveRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/LeaveRoom"
RoomCommandService_CloseRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/CloseRoom"
RoomCommandService_AdminUpdateRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminUpdateRoom"
RoomCommandService_AdminDeleteRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminDeleteRoom"
RoomCommandService_AdminUpdateRoomRocketConfig_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminUpdateRoomRocketConfig"
RoomCommandService_AdminUpdateRoomSeatConfig_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminUpdateRoomSeatConfig"
RoomCommandService_AdminUpdateHumanRoomRobotConfig_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminUpdateHumanRoomRobotConfig"
RoomCommandService_AdminCreateRoomPin_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminCreateRoomPin"
RoomCommandService_AdminCancelRoomPin_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminCancelRoomPin"
RoomCommandService_AdminCreateRobotRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminCreateRobotRoom"
RoomCommandService_AdminSetRobotRoomStatus_FullMethodName = "/hyapp.room.v1.RoomCommandService/AdminSetRobotRoomStatus"
RoomCommandService_MicUp_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicUp"
RoomCommandService_MicDown_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicDown"
RoomCommandService_ChangeMicSeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/ChangeMicSeat"
RoomCommandService_ConfirmMicPublishing_FullMethodName = "/hyapp.room.v1.RoomCommandService/ConfirmMicPublishing"
RoomCommandService_MicHeartbeat_FullMethodName = "/hyapp.room.v1.RoomCommandService/MicHeartbeat"
RoomCommandService_SetMicMute_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetMicMute"
RoomCommandService_ApplyRTCEvent_FullMethodName = "/hyapp.room.v1.RoomCommandService/ApplyRTCEvent"
RoomCommandService_SetMicSeatLock_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetMicSeatLock"
RoomCommandService_SetChatEnabled_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetChatEnabled"
RoomCommandService_SetRoomPassword_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetRoomPassword"
RoomCommandService_SetRoomAdmin_FullMethodName = "/hyapp.room.v1.RoomCommandService/SetRoomAdmin"
RoomCommandService_MuteUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/MuteUser"
RoomCommandService_KickUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/KickUser"
RoomCommandService_UnbanUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/UnbanUser"
RoomCommandService_SystemEvictUser_FullMethodName = "/hyapp.room.v1.RoomCommandService/SystemEvictUser"
RoomCommandService_SendGift_FullMethodName = "/hyapp.room.v1.RoomCommandService/SendGift"
RoomCommandService_FollowRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/FollowRoom"
RoomCommandService_UnfollowRoom_FullMethodName = "/hyapp.room.v1.RoomCommandService/UnfollowRoom"
)
// RoomCommandServiceClient is the client API for RoomCommandService service.
@ -73,6 +74,7 @@ type RoomCommandServiceClient interface {
AdminDeleteRoom(ctx context.Context, in *AdminDeleteRoomRequest, opts ...grpc.CallOption) (*AdminDeleteRoomResponse, error)
AdminUpdateRoomRocketConfig(ctx context.Context, in *AdminUpdateRoomRocketConfigRequest, opts ...grpc.CallOption) (*AdminUpdateRoomRocketConfigResponse, error)
AdminUpdateRoomSeatConfig(ctx context.Context, in *AdminUpdateRoomSeatConfigRequest, opts ...grpc.CallOption) (*AdminUpdateRoomSeatConfigResponse, error)
AdminUpdateHumanRoomRobotConfig(ctx context.Context, in *AdminUpdateHumanRoomRobotConfigRequest, opts ...grpc.CallOption) (*AdminUpdateHumanRoomRobotConfigResponse, error)
AdminCreateRoomPin(ctx context.Context, in *AdminCreateRoomPinRequest, opts ...grpc.CallOption) (*AdminCreateRoomPinResponse, error)
AdminCancelRoomPin(ctx context.Context, in *AdminCancelRoomPinRequest, opts ...grpc.CallOption) (*AdminCancelRoomPinResponse, error)
AdminCreateRobotRoom(ctx context.Context, in *AdminCreateRobotRoomRequest, opts ...grpc.CallOption) (*AdminCreateRobotRoomResponse, error)
@ -225,6 +227,16 @@ func (c *roomCommandServiceClient) AdminUpdateRoomSeatConfig(ctx context.Context
return out, nil
}
func (c *roomCommandServiceClient) AdminUpdateHumanRoomRobotConfig(ctx context.Context, in *AdminUpdateHumanRoomRobotConfigRequest, opts ...grpc.CallOption) (*AdminUpdateHumanRoomRobotConfigResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AdminUpdateHumanRoomRobotConfigResponse)
err := c.cc.Invoke(ctx, RoomCommandService_AdminUpdateHumanRoomRobotConfig_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *roomCommandServiceClient) AdminCreateRoomPin(ctx context.Context, in *AdminCreateRoomPinRequest, opts ...grpc.CallOption) (*AdminCreateRoomPinResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AdminCreateRoomPinResponse)
@ -463,6 +475,7 @@ type RoomCommandServiceServer interface {
AdminDeleteRoom(context.Context, *AdminDeleteRoomRequest) (*AdminDeleteRoomResponse, error)
AdminUpdateRoomRocketConfig(context.Context, *AdminUpdateRoomRocketConfigRequest) (*AdminUpdateRoomRocketConfigResponse, error)
AdminUpdateRoomSeatConfig(context.Context, *AdminUpdateRoomSeatConfigRequest) (*AdminUpdateRoomSeatConfigResponse, error)
AdminUpdateHumanRoomRobotConfig(context.Context, *AdminUpdateHumanRoomRobotConfigRequest) (*AdminUpdateHumanRoomRobotConfigResponse, error)
AdminCreateRoomPin(context.Context, *AdminCreateRoomPinRequest) (*AdminCreateRoomPinResponse, error)
AdminCancelRoomPin(context.Context, *AdminCancelRoomPinRequest) (*AdminCancelRoomPinResponse, error)
AdminCreateRobotRoom(context.Context, *AdminCreateRobotRoomRequest) (*AdminCreateRobotRoomResponse, error)
@ -496,106 +509,109 @@ type RoomCommandServiceServer interface {
type UnimplementedRoomCommandServiceServer struct{}
func (UnimplementedRoomCommandServiceServer) CreateRoom(context.Context, *CreateRoomRequest) (*CreateRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) UpdateRoomProfile(context.Context, *UpdateRoomProfileRequest) (*UpdateRoomProfileResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateRoomProfile not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateRoomProfile not implemented")
}
func (UnimplementedRoomCommandServiceServer) SaveRoomBackground(context.Context, *SaveRoomBackgroundRequest) (*SaveRoomBackgroundResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SaveRoomBackground not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SaveRoomBackground not implemented")
}
func (UnimplementedRoomCommandServiceServer) SetRoomBackground(context.Context, *SetRoomBackgroundRequest) (*SetRoomBackgroundResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetRoomBackground not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetRoomBackground not implemented")
}
func (UnimplementedRoomCommandServiceServer) JoinRoom(context.Context, *JoinRoomRequest) (*JoinRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method JoinRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method JoinRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) RoomHeartbeat(context.Context, *RoomHeartbeatRequest) (*RoomHeartbeatResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RoomHeartbeat not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RoomHeartbeat not implemented")
}
func (UnimplementedRoomCommandServiceServer) LeaveRoom(context.Context, *LeaveRoomRequest) (*LeaveRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method LeaveRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method LeaveRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) CloseRoom(context.Context, *CloseRoomRequest) (*CloseRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CloseRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CloseRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminUpdateRoom(context.Context, *AdminUpdateRoomRequest) (*AdminUpdateRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminUpdateRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminDeleteRoom(context.Context, *AdminDeleteRoomRequest) (*AdminDeleteRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminDeleteRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminDeleteRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminUpdateRoomRocketConfig(context.Context, *AdminUpdateRoomRocketConfigRequest) (*AdminUpdateRoomRocketConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminUpdateRoomRocketConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateRoomRocketConfig not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminUpdateRoomSeatConfig(context.Context, *AdminUpdateRoomSeatConfigRequest) (*AdminUpdateRoomSeatConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminUpdateRoomSeatConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateRoomSeatConfig not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminUpdateHumanRoomRobotConfig(context.Context, *AdminUpdateHumanRoomRobotConfigRequest) (*AdminUpdateHumanRoomRobotConfigResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateHumanRoomRobotConfig not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminCreateRoomPin(context.Context, *AdminCreateRoomPinRequest) (*AdminCreateRoomPinResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminCreateRoomPin not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminCreateRoomPin not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminCancelRoomPin(context.Context, *AdminCancelRoomPinRequest) (*AdminCancelRoomPinResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminCancelRoomPin not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminCancelRoomPin not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminCreateRobotRoom(context.Context, *AdminCreateRobotRoomRequest) (*AdminCreateRobotRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminCreateRobotRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminCreateRobotRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) AdminSetRobotRoomStatus(context.Context, *AdminSetRobotRoomStatusRequest) (*AdminSetRobotRoomStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminSetRobotRoomStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminSetRobotRoomStatus not implemented")
}
func (UnimplementedRoomCommandServiceServer) MicUp(context.Context, *MicUpRequest) (*MicUpResponse, error) {
return nil, status.Error(codes.Unimplemented, "method MicUp not implemented")
return nil, status.Errorf(codes.Unimplemented, "method MicUp not implemented")
}
func (UnimplementedRoomCommandServiceServer) MicDown(context.Context, *MicDownRequest) (*MicDownResponse, error) {
return nil, status.Error(codes.Unimplemented, "method MicDown not implemented")
return nil, status.Errorf(codes.Unimplemented, "method MicDown not implemented")
}
func (UnimplementedRoomCommandServiceServer) ChangeMicSeat(context.Context, *ChangeMicSeatRequest) (*ChangeMicSeatResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ChangeMicSeat not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ChangeMicSeat not implemented")
}
func (UnimplementedRoomCommandServiceServer) ConfirmMicPublishing(context.Context, *ConfirmMicPublishingRequest) (*ConfirmMicPublishingResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConfirmMicPublishing not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConfirmMicPublishing not implemented")
}
func (UnimplementedRoomCommandServiceServer) MicHeartbeat(context.Context, *MicHeartbeatRequest) (*MicHeartbeatResponse, error) {
return nil, status.Error(codes.Unimplemented, "method MicHeartbeat not implemented")
return nil, status.Errorf(codes.Unimplemented, "method MicHeartbeat not implemented")
}
func (UnimplementedRoomCommandServiceServer) SetMicMute(context.Context, *SetMicMuteRequest) (*SetMicMuteResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetMicMute not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetMicMute not implemented")
}
func (UnimplementedRoomCommandServiceServer) ApplyRTCEvent(context.Context, *ApplyRTCEventRequest) (*ApplyRTCEventResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ApplyRTCEvent not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ApplyRTCEvent not implemented")
}
func (UnimplementedRoomCommandServiceServer) SetMicSeatLock(context.Context, *SetMicSeatLockRequest) (*SetMicSeatLockResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetMicSeatLock not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetMicSeatLock not implemented")
}
func (UnimplementedRoomCommandServiceServer) SetChatEnabled(context.Context, *SetChatEnabledRequest) (*SetChatEnabledResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetChatEnabled not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetChatEnabled not implemented")
}
func (UnimplementedRoomCommandServiceServer) SetRoomPassword(context.Context, *SetRoomPasswordRequest) (*SetRoomPasswordResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetRoomPassword not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetRoomPassword not implemented")
}
func (UnimplementedRoomCommandServiceServer) SetRoomAdmin(context.Context, *SetRoomAdminRequest) (*SetRoomAdminResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetRoomAdmin not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetRoomAdmin not implemented")
}
func (UnimplementedRoomCommandServiceServer) MuteUser(context.Context, *MuteUserRequest) (*MuteUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method MuteUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method MuteUser not implemented")
}
func (UnimplementedRoomCommandServiceServer) KickUser(context.Context, *KickUserRequest) (*KickUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method KickUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method KickUser not implemented")
}
func (UnimplementedRoomCommandServiceServer) UnbanUser(context.Context, *UnbanUserRequest) (*UnbanUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UnbanUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UnbanUser not implemented")
}
func (UnimplementedRoomCommandServiceServer) SystemEvictUser(context.Context, *SystemEvictUserRequest) (*SystemEvictUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SystemEvictUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SystemEvictUser not implemented")
}
func (UnimplementedRoomCommandServiceServer) SendGift(context.Context, *SendGiftRequest) (*SendGiftResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SendGift not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SendGift not implemented")
}
func (UnimplementedRoomCommandServiceServer) FollowRoom(context.Context, *FollowRoomRequest) (*FollowRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method FollowRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method FollowRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) UnfollowRoom(context.Context, *UnfollowRoomRequest) (*UnfollowRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UnfollowRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UnfollowRoom not implemented")
}
func (UnimplementedRoomCommandServiceServer) mustEmbedUnimplementedRoomCommandServiceServer() {}
func (UnimplementedRoomCommandServiceServer) testEmbeddedByValue() {}
@ -608,7 +624,7 @@ type UnsafeRoomCommandServiceServer interface {
}
func RegisterRoomCommandServiceServer(s grpc.ServiceRegistrar, srv RoomCommandServiceServer) {
// If the following call panics, it indicates UnimplementedRoomCommandServiceServer was
// If the following call pancis, 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.
@ -834,6 +850,24 @@ func _RoomCommandService_AdminUpdateRoomSeatConfig_Handler(srv interface{}, ctx
return interceptor(ctx, in, info, handler)
}
func _RoomCommandService_AdminUpdateHumanRoomRobotConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdminUpdateHumanRoomRobotConfigRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoomCommandServiceServer).AdminUpdateHumanRoomRobotConfig(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: RoomCommandService_AdminUpdateHumanRoomRobotConfig_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoomCommandServiceServer).AdminUpdateHumanRoomRobotConfig(ctx, req.(*AdminUpdateHumanRoomRobotConfigRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RoomCommandService_AdminCreateRoomPin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdminCreateRoomPinRequest)
if err := dec(in); err != nil {
@ -1285,6 +1319,10 @@ var RoomCommandService_ServiceDesc = grpc.ServiceDesc{
MethodName: "AdminUpdateRoomSeatConfig",
Handler: _RoomCommandService_AdminUpdateRoomSeatConfig_Handler,
},
{
MethodName: "AdminUpdateHumanRoomRobotConfig",
Handler: _RoomCommandService_AdminUpdateHumanRoomRobotConfig_Handler,
},
{
MethodName: "AdminCreateRoomPin",
Handler: _RoomCommandService_AdminCreateRoomPin_Handler,
@ -1440,10 +1478,10 @@ type RoomGuardServiceServer interface {
type UnimplementedRoomGuardServiceServer struct{}
func (UnimplementedRoomGuardServiceServer) CheckSpeakPermission(context.Context, *CheckSpeakPermissionRequest) (*CheckSpeakPermissionResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CheckSpeakPermission not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CheckSpeakPermission not implemented")
}
func (UnimplementedRoomGuardServiceServer) VerifyRoomPresence(context.Context, *VerifyRoomPresenceRequest) (*VerifyRoomPresenceResponse, error) {
return nil, status.Error(codes.Unimplemented, "method VerifyRoomPresence not implemented")
return nil, status.Errorf(codes.Unimplemented, "method VerifyRoomPresence not implemented")
}
func (UnimplementedRoomGuardServiceServer) mustEmbedUnimplementedRoomGuardServiceServer() {}
func (UnimplementedRoomGuardServiceServer) testEmbeddedByValue() {}
@ -1456,7 +1494,7 @@ type UnsafeRoomGuardServiceServer interface {
}
func RegisterRoomGuardServiceServer(s grpc.ServiceRegistrar, srv RoomGuardServiceServer) {
// If the following call panics, it indicates UnimplementedRoomGuardServiceServer was
// If the following call pancis, 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.
@ -1527,6 +1565,7 @@ const (
RoomQueryService_AdminGetRoom_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminGetRoom"
RoomQueryService_AdminGetRoomRocketConfig_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminGetRoomRocketConfig"
RoomQueryService_AdminGetRoomSeatConfig_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminGetRoomSeatConfig"
RoomQueryService_AdminGetHumanRoomRobotConfig_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminGetHumanRoomRobotConfig"
RoomQueryService_AdminListRoomPins_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminListRoomPins"
RoomQueryService_AdminListRobotRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminListRobotRooms"
RoomQueryService_AdminFilterAvailableRoomRobots_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminFilterAvailableRoomRobots"
@ -1552,6 +1591,7 @@ type RoomQueryServiceClient interface {
AdminGetRoom(ctx context.Context, in *AdminGetRoomRequest, opts ...grpc.CallOption) (*AdminGetRoomResponse, error)
AdminGetRoomRocketConfig(ctx context.Context, in *AdminGetRoomRocketConfigRequest, opts ...grpc.CallOption) (*AdminGetRoomRocketConfigResponse, error)
AdminGetRoomSeatConfig(ctx context.Context, in *AdminGetRoomSeatConfigRequest, opts ...grpc.CallOption) (*AdminGetRoomSeatConfigResponse, error)
AdminGetHumanRoomRobotConfig(ctx context.Context, in *AdminGetHumanRoomRobotConfigRequest, opts ...grpc.CallOption) (*AdminGetHumanRoomRobotConfigResponse, error)
AdminListRoomPins(ctx context.Context, in *AdminListRoomPinsRequest, opts ...grpc.CallOption) (*AdminListRoomPinsResponse, error)
AdminListRobotRooms(ctx context.Context, in *AdminListRobotRoomsRequest, opts ...grpc.CallOption) (*AdminListRobotRoomsResponse, error)
AdminFilterAvailableRoomRobots(ctx context.Context, in *AdminFilterAvailableRoomRobotsRequest, opts ...grpc.CallOption) (*AdminFilterAvailableRoomRobotsResponse, error)
@ -1615,6 +1655,16 @@ func (c *roomQueryServiceClient) AdminGetRoomSeatConfig(ctx context.Context, in
return out, nil
}
func (c *roomQueryServiceClient) AdminGetHumanRoomRobotConfig(ctx context.Context, in *AdminGetHumanRoomRobotConfigRequest, opts ...grpc.CallOption) (*AdminGetHumanRoomRobotConfigResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AdminGetHumanRoomRobotConfigResponse)
err := c.cc.Invoke(ctx, RoomQueryService_AdminGetHumanRoomRobotConfig_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *roomQueryServiceClient) AdminListRoomPins(ctx context.Context, in *AdminListRoomPinsRequest, opts ...grpc.CallOption) (*AdminListRoomPinsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AdminListRoomPinsResponse)
@ -1755,6 +1805,7 @@ type RoomQueryServiceServer interface {
AdminGetRoom(context.Context, *AdminGetRoomRequest) (*AdminGetRoomResponse, error)
AdminGetRoomRocketConfig(context.Context, *AdminGetRoomRocketConfigRequest) (*AdminGetRoomRocketConfigResponse, error)
AdminGetRoomSeatConfig(context.Context, *AdminGetRoomSeatConfigRequest) (*AdminGetRoomSeatConfigResponse, error)
AdminGetHumanRoomRobotConfig(context.Context, *AdminGetHumanRoomRobotConfigRequest) (*AdminGetHumanRoomRobotConfigResponse, error)
AdminListRoomPins(context.Context, *AdminListRoomPinsRequest) (*AdminListRoomPinsResponse, error)
AdminListRobotRooms(context.Context, *AdminListRobotRoomsRequest) (*AdminListRobotRoomsResponse, error)
AdminFilterAvailableRoomRobots(context.Context, *AdminFilterAvailableRoomRobotsRequest) (*AdminFilterAvailableRoomRobotsResponse, error)
@ -1779,55 +1830,58 @@ type RoomQueryServiceServer interface {
type UnimplementedRoomQueryServiceServer struct{}
func (UnimplementedRoomQueryServiceServer) AdminListRooms(context.Context, *AdminListRoomsRequest) (*AdminListRoomsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminListRooms not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminListRooms not implemented")
}
func (UnimplementedRoomQueryServiceServer) AdminGetRoom(context.Context, *AdminGetRoomRequest) (*AdminGetRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminGetRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminGetRoom not implemented")
}
func (UnimplementedRoomQueryServiceServer) AdminGetRoomRocketConfig(context.Context, *AdminGetRoomRocketConfigRequest) (*AdminGetRoomRocketConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminGetRoomRocketConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminGetRoomRocketConfig not implemented")
}
func (UnimplementedRoomQueryServiceServer) AdminGetRoomSeatConfig(context.Context, *AdminGetRoomSeatConfigRequest) (*AdminGetRoomSeatConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminGetRoomSeatConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminGetRoomSeatConfig not implemented")
}
func (UnimplementedRoomQueryServiceServer) AdminGetHumanRoomRobotConfig(context.Context, *AdminGetHumanRoomRobotConfigRequest) (*AdminGetHumanRoomRobotConfigResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AdminGetHumanRoomRobotConfig not implemented")
}
func (UnimplementedRoomQueryServiceServer) AdminListRoomPins(context.Context, *AdminListRoomPinsRequest) (*AdminListRoomPinsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminListRoomPins not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminListRoomPins not implemented")
}
func (UnimplementedRoomQueryServiceServer) AdminListRobotRooms(context.Context, *AdminListRobotRoomsRequest) (*AdminListRobotRoomsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminListRobotRooms not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminListRobotRooms not implemented")
}
func (UnimplementedRoomQueryServiceServer) AdminFilterAvailableRoomRobots(context.Context, *AdminFilterAvailableRoomRobotsRequest) (*AdminFilterAvailableRoomRobotsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminFilterAvailableRoomRobots not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminFilterAvailableRoomRobots not implemented")
}
func (UnimplementedRoomQueryServiceServer) ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRooms not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRooms not implemented")
}
func (UnimplementedRoomQueryServiceServer) ListRoomFeeds(context.Context, *ListRoomFeedsRequest) (*ListRoomsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomFeeds not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomFeeds not implemented")
}
func (UnimplementedRoomQueryServiceServer) ListRoomGiftLeaderboard(context.Context, *ListRoomGiftLeaderboardRequest) (*ListRoomGiftLeaderboardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomGiftLeaderboard not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomGiftLeaderboard not implemented")
}
func (UnimplementedRoomQueryServiceServer) GetMyRoom(context.Context, *GetMyRoomRequest) (*GetMyRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetMyRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetMyRoom not implemented")
}
func (UnimplementedRoomQueryServiceServer) GetCurrentRoom(context.Context, *GetCurrentRoomRequest) (*GetCurrentRoomResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetCurrentRoom not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetCurrentRoom not implemented")
}
func (UnimplementedRoomQueryServiceServer) GetRoomSnapshot(context.Context, *GetRoomSnapshotRequest) (*GetRoomSnapshotResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoomSnapshot not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRoomSnapshot not implemented")
}
func (UnimplementedRoomQueryServiceServer) ListRoomBackgrounds(context.Context, *ListRoomBackgroundsRequest) (*ListRoomBackgroundsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomBackgrounds not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomBackgrounds not implemented")
}
func (UnimplementedRoomQueryServiceServer) GetRoomRocket(context.Context, *GetRoomRocketRequest) (*GetRoomRocketResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoomRocket not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRoomRocket not implemented")
}
func (UnimplementedRoomQueryServiceServer) ListRoomOnlineUsers(context.Context, *ListRoomOnlineUsersRequest) (*ListRoomOnlineUsersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomOnlineUsers not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomOnlineUsers not implemented")
}
func (UnimplementedRoomQueryServiceServer) ListRoomBannedUsers(context.Context, *ListRoomBannedUsersRequest) (*ListRoomBannedUsersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoomBannedUsers not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoomBannedUsers not implemented")
}
func (UnimplementedRoomQueryServiceServer) mustEmbedUnimplementedRoomQueryServiceServer() {}
func (UnimplementedRoomQueryServiceServer) testEmbeddedByValue() {}
@ -1840,7 +1894,7 @@ type UnsafeRoomQueryServiceServer interface {
}
func RegisterRoomQueryServiceServer(s grpc.ServiceRegistrar, srv RoomQueryServiceServer) {
// If the following call panics, it indicates UnimplementedRoomQueryServiceServer was
// If the following call pancis, 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.
@ -1922,6 +1976,24 @@ func _RoomQueryService_AdminGetRoomSeatConfig_Handler(srv interface{}, ctx conte
return interceptor(ctx, in, info, handler)
}
func _RoomQueryService_AdminGetHumanRoomRobotConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdminGetHumanRoomRobotConfigRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoomQueryServiceServer).AdminGetHumanRoomRobotConfig(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: RoomQueryService_AdminGetHumanRoomRobotConfig_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoomQueryServiceServer).AdminGetHumanRoomRobotConfig(ctx, req.(*AdminGetHumanRoomRobotConfigRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RoomQueryService_AdminListRoomPins_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdminListRoomPinsRequest)
if err := dec(in); err != nil {
@ -2179,6 +2251,10 @@ var RoomQueryService_ServiceDesc = grpc.ServiceDesc{
MethodName: "AdminGetRoomSeatConfig",
Handler: _RoomQueryService_AdminGetRoomSeatConfig_Handler,
},
{
MethodName: "AdminGetHumanRoomRobotConfig",
Handler: _RoomQueryService_AdminGetHumanRoomRobotConfig_Handler,
},
{
MethodName: "AdminListRoomPins",
Handler: _RoomQueryService_AdminListRoomPins_Handler,

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc-gen-go v1.35.1
// protoc v7.35.0
// source: proto/user/v1/auth.proto
@ -11,7 +11,6 @@ import (
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
@ -23,12 +22,13 @@ const (
// LoginPasswordRequest 使用当前 display_user_id 和已设置密码登录。
type LoginPasswordRequest struct {
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
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
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"`
}
func (x *LoginPasswordRequest) Reset() {
@ -84,29 +84,30 @@ func (x *LoginPasswordRequest) GetPassword() string {
// LoginThirdPartyRequest 使用三方凭证登录或注册。
type LoginThirdPartyRequest struct {
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
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"`
}
func (x *LoginThirdPartyRequest) Reset() {
@ -281,13 +282,14 @@ func (x *LoginThirdPartyRequest) GetCampaign() string {
// AuthResponse 返回标准认证令牌。
type AuthResponse struct {
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
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"`
}
func (x *AuthResponse) Reset() {
@ -350,12 +352,13 @@ func (x *AuthResponse) GetOnboardingStatus() string {
// SetPasswordRequest 为已经三方登录的用户首次设置密码。
type SetPasswordRequest struct {
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
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"`
}
func (x *SetPasswordRequest) Reset() {
@ -411,10 +414,11 @@ func (x *SetPasswordRequest) GetPassword() string {
// SetPasswordResponse 返回密码是否已经成功设置。
type SetPasswordResponse struct {
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
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PasswordSet bool `protobuf:"varint,1,opt,name=password_set,json=passwordSet,proto3" json:"password_set,omitempty"`
}
func (x *SetPasswordResponse) Reset() {
@ -456,28 +460,29 @@ func (x *SetPasswordResponse) GetPasswordSet() bool {
// QuickCreateAccountRequest 为后台快速创建完整资料账号source=game_robot 时账号不可登录。
type QuickCreateAccountRequest struct {
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
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"`
}
func (x *QuickCreateAccountRequest) Reset() {
@ -645,11 +650,12 @@ func (x *QuickCreateAccountRequest) GetTimezone() string {
// QuickCreateAccountResponse 返回新账号身份普通账号含登录态source=game_robot 时 token 只含 user_id/display_user_id。
type QuickCreateAccountResponse struct {
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
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
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"`
}
func (x *QuickCreateAccountResponse) Reset() {
@ -698,11 +704,12 @@ func (x *QuickCreateAccountResponse) GetPasswordSet() bool {
// RefreshTokenRequest 使用 refresh token 换取新 token。
type RefreshTokenRequest struct {
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
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
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"`
}
func (x *RefreshTokenRequest) Reset() {
@ -751,10 +758,11 @@ func (x *RefreshTokenRequest) GetRefreshToken() string {
// RefreshTokenResponse 返回轮换后的令牌。
type RefreshTokenResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Token *AuthToken `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Token *AuthToken `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
}
func (x *RefreshTokenResponse) Reset() {
@ -796,12 +804,13 @@ func (x *RefreshTokenResponse) GetToken() *AuthToken {
// LogoutRequest 失效指定会话或 refresh token。
type LogoutRequest struct {
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
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
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"`
}
func (x *LogoutRequest) Reset() {
@ -857,10 +866,11 @@ func (x *LogoutRequest) GetRefreshToken() string {
// LogoutResponse 返回会话是否被失效。
type LogoutResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Revoked bool `protobuf:"varint,1,opt,name=revoked,proto3" json:"revoked,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Revoked bool `protobuf:"varint,1,opt,name=revoked,proto3" json:"revoked,omitempty"`
}
func (x *LogoutResponse) Reset() {
@ -902,15 +912,16 @@ func (x *LogoutResponse) GetRevoked() bool {
// RecordLoginBlockedRequest 记录 gateway 入口快拦拒绝的登录审计。
type RecordLoginBlockedRequest struct {
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
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
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"`
}
func (x *RecordLoginBlockedRequest) Reset() {
@ -987,10 +998,11 @@ func (x *RecordLoginBlockedRequest) GetBlockReason() string {
// RecordLoginBlockedResponse 返回审计写入是否成功。
type RecordLoginBlockedResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Recorded bool `protobuf:"varint,1,opt,name=recorded,proto3" json:"recorded,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Recorded bool `protobuf:"varint,1,opt,name=recorded,proto3" json:"recorded,omitempty"`
}
func (x *RecordLoginBlockedResponse) Reset() {
@ -1032,12 +1044,13 @@ func (x *RecordLoginBlockedResponse) GetRecorded() bool {
// AppHeartbeatRequest 刷新当前登录会话的 App 在线心跳。
type AppHeartbeatRequest struct {
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
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
}
func (x *AppHeartbeatRequest) Reset() {
@ -1093,13 +1106,14 @@ func (x *AppHeartbeatRequest) GetSessionId() string {
// AppHeartbeatResponse 返回本次会话心跳写入时间,并在当前会话仍有效时顺手重签 access token。
type AppHeartbeatResponse struct {
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"`
Token *AuthToken `protobuf:"bytes,4,opt,name=token,proto3" json:"token,omitempty"`
unknownFields protoimpl.UnknownFields
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
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"`
Token *AuthToken `protobuf:"bytes,4,opt,name=token,proto3" json:"token,omitempty"`
}
func (x *AppHeartbeatResponse) Reset() {
@ -1162,127 +1176,244 @@ func (x *AppHeartbeatResponse) GetToken() *AuthToken {
var File_proto_user_v1_auth_proto protoreflect.FileDescriptor
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\"\xb0\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\fserverTimeMs\x12.\n" +
"\x05token\x18\x04 \x01(\v2\x18.hyapp.user.v1.AuthTokenR\x05token2\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_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, 0xb0, 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, 0x12,
0x2e, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 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, 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,
}
var (
file_proto_user_v1_auth_proto_rawDescOnce sync.Once
file_proto_user_v1_auth_proto_rawDescData []byte
file_proto_user_v1_auth_proto_rawDescData = file_proto_user_v1_auth_proto_rawDesc
)
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(unsafe.Slice(unsafe.StringData(file_proto_user_v1_auth_proto_rawDesc), len(file_proto_user_v1_auth_proto_rawDesc)))
file_proto_user_v1_auth_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_user_v1_auth_proto_rawDescData)
})
return file_proto_user_v1_auth_proto_rawDescData
}
@ -1353,7 +1484,7 @@ func file_proto_user_v1_auth_proto_init() {
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_user_v1_auth_proto_rawDesc), len(file_proto_user_v1_auth_proto_rawDesc)),
RawDescriptor: file_proto_user_v1_auth_proto_rawDesc,
NumEnums: 0,
NumMessages: 15,
NumExtensions: 0,
@ -1364,6 +1495,7 @@ 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
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc-gen-go-grpc v1.5.1
// - 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.Error(codes.Unimplemented, "method LoginPassword not implemented")
return nil, status.Errorf(codes.Unimplemented, "method LoginPassword not implemented")
}
func (UnimplementedAuthServiceServer) LoginThirdParty(context.Context, *LoginThirdPartyRequest) (*AuthResponse, error) {
return nil, status.Error(codes.Unimplemented, "method LoginThirdParty not implemented")
return nil, status.Errorf(codes.Unimplemented, "method LoginThirdParty not implemented")
}
func (UnimplementedAuthServiceServer) SetPassword(context.Context, *SetPasswordRequest) (*SetPasswordResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetPassword not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetPassword not implemented")
}
func (UnimplementedAuthServiceServer) QuickCreateAccount(context.Context, *QuickCreateAccountRequest) (*QuickCreateAccountResponse, error) {
return nil, status.Error(codes.Unimplemented, "method QuickCreateAccount not implemented")
return nil, status.Errorf(codes.Unimplemented, "method QuickCreateAccount not implemented")
}
func (UnimplementedAuthServiceServer) RefreshToken(context.Context, *RefreshTokenRequest) (*RefreshTokenResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RefreshToken not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RefreshToken not implemented")
}
func (UnimplementedAuthServiceServer) Logout(context.Context, *LogoutRequest) (*LogoutResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Logout not implemented")
return nil, status.Errorf(codes.Unimplemented, "method Logout not implemented")
}
func (UnimplementedAuthServiceServer) RecordLoginBlocked(context.Context, *RecordLoginBlockedRequest) (*RecordLoginBlockedResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RecordLoginBlocked not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RecordLoginBlocked not implemented")
}
func (UnimplementedAuthServiceServer) AppHeartbeat(context.Context, *AppHeartbeatRequest) (*AppHeartbeatResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AppHeartbeat not implemented")
return nil, status.Errorf(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 panics, it indicates UnimplementedAuthServiceServer was
// If the following call pancis, 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

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc-gen-go-grpc v1.5.1
// - protoc v7.35.0
// source: proto/user/v1/host.proto
@ -327,67 +327,67 @@ type UserHostServiceServer interface {
type UnimplementedUserHostServiceServer struct{}
func (UnimplementedUserHostServiceServer) SearchAgencies(context.Context, *SearchAgenciesRequest) (*SearchAgenciesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SearchAgencies not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SearchAgencies not implemented")
}
func (UnimplementedUserHostServiceServer) ApplyToAgency(context.Context, *ApplyToAgencyRequest) (*ApplyToAgencyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ApplyToAgency not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ApplyToAgency not implemented")
}
func (UnimplementedUserHostServiceServer) ReviewAgencyApplication(context.Context, *ReviewAgencyApplicationRequest) (*ReviewAgencyApplicationResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ReviewAgencyApplication not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ReviewAgencyApplication not implemented")
}
func (UnimplementedUserHostServiceServer) KickAgencyHost(context.Context, *KickAgencyHostRequest) (*KickAgencyHostResponse, error) {
return nil, status.Error(codes.Unimplemented, "method KickAgencyHost not implemented")
return nil, status.Errorf(codes.Unimplemented, "method KickAgencyHost not implemented")
}
func (UnimplementedUserHostServiceServer) InviteAgency(context.Context, *InviteAgencyRequest) (*InviteAgencyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method InviteAgency not implemented")
return nil, status.Errorf(codes.Unimplemented, "method InviteAgency not implemented")
}
func (UnimplementedUserHostServiceServer) InviteBD(context.Context, *InviteBDRequest) (*InviteBDResponse, error) {
return nil, status.Error(codes.Unimplemented, "method InviteBD not implemented")
return nil, status.Errorf(codes.Unimplemented, "method InviteBD not implemented")
}
func (UnimplementedUserHostServiceServer) InviteHost(context.Context, *InviteHostRequest) (*InviteHostResponse, error) {
return nil, status.Error(codes.Unimplemented, "method InviteHost not implemented")
return nil, status.Errorf(codes.Unimplemented, "method InviteHost not implemented")
}
func (UnimplementedUserHostServiceServer) ListBDLeaderBDs(context.Context, *ListBDLeaderBDsRequest) (*ListBDLeaderBDsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListBDLeaderBDs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListBDLeaderBDs not implemented")
}
func (UnimplementedUserHostServiceServer) ListBDLeaderAgencies(context.Context, *ListBDLeaderAgenciesRequest) (*ListBDLeaderAgenciesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListBDLeaderAgencies not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListBDLeaderAgencies not implemented")
}
func (UnimplementedUserHostServiceServer) ListBDAgencies(context.Context, *ListBDAgenciesRequest) (*ListBDAgenciesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListBDAgencies not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListBDAgencies not implemented")
}
func (UnimplementedUserHostServiceServer) ListRoleInvitations(context.Context, *ListRoleInvitationsRequest) (*ListRoleInvitationsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRoleInvitations not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRoleInvitations not implemented")
}
func (UnimplementedUserHostServiceServer) ProcessRoleInvitation(context.Context, *ProcessRoleInvitationRequest) (*ProcessRoleInvitationResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessRoleInvitation not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessRoleInvitation not implemented")
}
func (UnimplementedUserHostServiceServer) GetHostProfile(context.Context, *GetHostProfileRequest) (*GetHostProfileResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetHostProfile not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetHostProfile not implemented")
}
func (UnimplementedUserHostServiceServer) GetBDProfile(context.Context, *GetBDProfileRequest) (*GetBDProfileResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetBDProfile not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetBDProfile not implemented")
}
func (UnimplementedUserHostServiceServer) GetCoinSellerProfile(context.Context, *GetCoinSellerProfileRequest) (*GetCoinSellerProfileResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetCoinSellerProfile not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetCoinSellerProfile not implemented")
}
func (UnimplementedUserHostServiceServer) ListActiveCoinSellersInMyRegion(context.Context, *ListActiveCoinSellersInMyRegionRequest) (*ListActiveCoinSellersInMyRegionResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListActiveCoinSellersInMyRegion not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListActiveCoinSellersInMyRegion not implemented")
}
func (UnimplementedUserHostServiceServer) GetUserRoleSummary(context.Context, *GetUserRoleSummaryRequest) (*GetUserRoleSummaryResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserRoleSummary not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetUserRoleSummary not implemented")
}
func (UnimplementedUserHostServiceServer) GetAgency(context.Context, *GetAgencyRequest) (*GetAgencyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetAgency not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetAgency not implemented")
}
func (UnimplementedUserHostServiceServer) CheckBusinessCapability(context.Context, *CheckBusinessCapabilityRequest) (*CheckBusinessCapabilityResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CheckBusinessCapability not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CheckBusinessCapability not implemented")
}
func (UnimplementedUserHostServiceServer) GetAgencyMembers(context.Context, *GetAgencyMembersRequest) (*GetAgencyMembersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetAgencyMembers not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetAgencyMembers not implemented")
}
func (UnimplementedUserHostServiceServer) GetAgencyApplications(context.Context, *GetAgencyApplicationsRequest) (*GetAgencyApplicationsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetAgencyApplications not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetAgencyApplications not implemented")
}
func (UnimplementedUserHostServiceServer) mustEmbedUnimplementedUserHostServiceServer() {}
func (UnimplementedUserHostServiceServer) testEmbeddedByValue() {}
@ -400,7 +400,7 @@ type UnsafeUserHostServiceServer interface {
}
func RegisterUserHostServiceServer(s grpc.ServiceRegistrar, srv UserHostServiceServer) {
// If the following call panics, it indicates UnimplementedUserHostServiceServer was
// If the following call pancis, 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.
@ -1037,31 +1037,31 @@ type UserHostAdminServiceServer interface {
type UnimplementedUserHostAdminServiceServer struct{}
func (UnimplementedUserHostAdminServiceServer) CreateBDLeader(context.Context, *CreateBDLeaderRequest) (*CreateBDLeaderResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateBDLeader not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateBDLeader not implemented")
}
func (UnimplementedUserHostAdminServiceServer) CreateBD(context.Context, *CreateBDRequest) (*CreateBDResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateBD not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateBD not implemented")
}
func (UnimplementedUserHostAdminServiceServer) SetBDStatus(context.Context, *SetBDStatusRequest) (*SetBDStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetBDStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetBDStatus not implemented")
}
func (UnimplementedUserHostAdminServiceServer) CreateCoinSeller(context.Context, *CreateCoinSellerRequest) (*CreateCoinSellerResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateCoinSeller not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateCoinSeller not implemented")
}
func (UnimplementedUserHostAdminServiceServer) SetCoinSellerStatus(context.Context, *SetCoinSellerStatusRequest) (*SetCoinSellerStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetCoinSellerStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetCoinSellerStatus not implemented")
}
func (UnimplementedUserHostAdminServiceServer) CreateAgency(context.Context, *CreateAgencyRequest) (*CreateAgencyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateAgency not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateAgency not implemented")
}
func (UnimplementedUserHostAdminServiceServer) CloseAgency(context.Context, *CloseAgencyRequest) (*CloseAgencyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CloseAgency not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CloseAgency not implemented")
}
func (UnimplementedUserHostAdminServiceServer) DeleteAgency(context.Context, *DeleteAgencyRequest) (*DeleteAgencyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteAgency not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteAgency not implemented")
}
func (UnimplementedUserHostAdminServiceServer) SetAgencyJoinEnabled(context.Context, *SetAgencyJoinEnabledRequest) (*SetAgencyJoinEnabledResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetAgencyJoinEnabled not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetAgencyJoinEnabled not implemented")
}
func (UnimplementedUserHostAdminServiceServer) mustEmbedUnimplementedUserHostAdminServiceServer() {}
func (UnimplementedUserHostAdminServiceServer) testEmbeddedByValue() {}
@ -1074,7 +1074,7 @@ type UnsafeUserHostAdminServiceServer interface {
}
func RegisterUserHostAdminServiceServer(s grpc.ServiceRegistrar, srv UserHostAdminServiceServer) {
// If the following call panics, it indicates UnimplementedUserHostAdminServiceServer was
// If the following call pancis, 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

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc-gen-go-grpc v1.5.1
// - protoc v7.35.0
// source: proto/user/v1/user.proto
@ -262,52 +262,52 @@ type UserServiceServer interface {
type UnimplementedUserServiceServer struct{}
func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
}
func (UnimplementedUserServiceServer) GetInviteAttribution(context.Context, *GetInviteAttributionRequest) (*GetInviteAttributionResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetInviteAttribution not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetInviteAttribution not implemented")
}
func (UnimplementedUserServiceServer) BusinessUserLookup(context.Context, *BusinessUserLookupRequest) (*BusinessUserLookupResponse, error) {
return nil, status.Error(codes.Unimplemented, "method BusinessUserLookup not implemented")
return nil, status.Errorf(codes.Unimplemented, "method BusinessUserLookup not implemented")
}
func (UnimplementedUserServiceServer) GetMyProfileStats(context.Context, *GetMyProfileStatsRequest) (*GetMyProfileStatsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetMyProfileStats not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetMyProfileStats not implemented")
}
func (UnimplementedUserServiceServer) BatchGetUsers(context.Context, *BatchGetUsersRequest) (*BatchGetUsersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method BatchGetUsers not implemented")
return nil, status.Errorf(codes.Unimplemented, "method BatchGetUsers not implemented")
}
func (UnimplementedUserServiceServer) ListUserIDs(context.Context, *ListUserIDsRequest) (*ListUserIDsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListUserIDs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListUserIDs not implemented")
}
func (UnimplementedUserServiceServer) GetUserMicLifetimeStats(context.Context, *GetUserMicLifetimeStatsRequest) (*GetUserMicLifetimeStatsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserMicLifetimeStats not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetUserMicLifetimeStats not implemented")
}
func (UnimplementedUserServiceServer) UpdateUserProfile(context.Context, *UpdateUserProfileRequest) (*UpdateUserProfileResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateUserProfile not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateUserProfile not implemented")
}
func (UnimplementedUserServiceServer) UpdateUserProfileBackground(context.Context, *UpdateUserProfileBackgroundRequest) (*UpdateUserProfileBackgroundResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateUserProfileBackground not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateUserProfileBackground not implemented")
}
func (UnimplementedUserServiceServer) ChangeUserCountry(context.Context, *ChangeUserCountryRequest) (*ChangeUserCountryResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ChangeUserCountry not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ChangeUserCountry not implemented")
}
func (UnimplementedUserServiceServer) AdminChangeUserCountry(context.Context, *AdminChangeUserCountryRequest) (*ChangeUserCountryResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminChangeUserCountry not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminChangeUserCountry not implemented")
}
func (UnimplementedUserServiceServer) SetUserStatus(context.Context, *SetUserStatusRequest) (*SetUserStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetUserStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetUserStatus not implemented")
}
func (UnimplementedUserServiceServer) CreateManagerUserBlock(context.Context, *CreateManagerUserBlockRequest) (*CreateManagerUserBlockResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateManagerUserBlock not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateManagerUserBlock not implemented")
}
func (UnimplementedUserServiceServer) ListManagerUserBlocks(context.Context, *ListManagerUserBlocksRequest) (*ListManagerUserBlocksResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListManagerUserBlocks not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListManagerUserBlocks not implemented")
}
func (UnimplementedUserServiceServer) UnblockManagerUser(context.Context, *UnblockManagerUserRequest) (*UnblockManagerUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UnblockManagerUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UnblockManagerUser not implemented")
}
func (UnimplementedUserServiceServer) CompleteOnboarding(context.Context, *CompleteOnboardingRequest) (*CompleteOnboardingResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CompleteOnboarding not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CompleteOnboarding not implemented")
}
func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {}
func (UnimplementedUserServiceServer) testEmbeddedByValue() {}
@ -320,7 +320,7 @@ type UnsafeUserServiceServer interface {
}
func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) {
// If the following call panics, it indicates UnimplementedUserServiceServer was
// If the following call pancis, 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.
@ -873,37 +873,37 @@ type UserSocialServiceServer interface {
type UnimplementedUserSocialServiceServer struct{}
func (UnimplementedUserSocialServiceServer) RecordProfileVisit(context.Context, *RecordProfileVisitRequest) (*RecordProfileVisitResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RecordProfileVisit not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RecordProfileVisit not implemented")
}
func (UnimplementedUserSocialServiceServer) ListProfileVisitors(context.Context, *ListProfileVisitorsRequest) (*ListProfileVisitorsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListProfileVisitors not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListProfileVisitors not implemented")
}
func (UnimplementedUserSocialServiceServer) FollowUser(context.Context, *FollowUserRequest) (*FollowUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method FollowUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method FollowUser not implemented")
}
func (UnimplementedUserSocialServiceServer) UnfollowUser(context.Context, *UnfollowUserRequest) (*UnfollowUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UnfollowUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UnfollowUser not implemented")
}
func (UnimplementedUserSocialServiceServer) ListFollowing(context.Context, *ListFollowingRequest) (*ListFollowingResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListFollowing not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListFollowing not implemented")
}
func (UnimplementedUserSocialServiceServer) ApplyFriend(context.Context, *ApplyFriendRequest) (*ApplyFriendResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ApplyFriend not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ApplyFriend not implemented")
}
func (UnimplementedUserSocialServiceServer) AcceptFriendApplication(context.Context, *AcceptFriendApplicationRequest) (*AcceptFriendApplicationResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AcceptFriendApplication not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AcceptFriendApplication not implemented")
}
func (UnimplementedUserSocialServiceServer) DeleteFriend(context.Context, *DeleteFriendRequest) (*DeleteFriendResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteFriend not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteFriend not implemented")
}
func (UnimplementedUserSocialServiceServer) ListFriends(context.Context, *ListFriendsRequest) (*ListFriendsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListFriends not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListFriends not implemented")
}
func (UnimplementedUserSocialServiceServer) ListFriendApplications(context.Context, *ListFriendApplicationsRequest) (*ListFriendApplicationsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListFriendApplications not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListFriendApplications not implemented")
}
func (UnimplementedUserSocialServiceServer) SubmitReport(context.Context, *SubmitReportRequest) (*SubmitReportResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SubmitReport not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SubmitReport not implemented")
}
func (UnimplementedUserSocialServiceServer) mustEmbedUnimplementedUserSocialServiceServer() {}
func (UnimplementedUserSocialServiceServer) testEmbeddedByValue() {}
@ -916,7 +916,7 @@ type UnsafeUserSocialServiceServer interface {
}
func RegisterUserSocialServiceServer(s grpc.ServiceRegistrar, srv UserSocialServiceServer) {
// If the following call panics, it indicates UnimplementedUserSocialServiceServer was
// If the following call pancis, 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.
@ -1320,28 +1320,28 @@ type UserCPServiceServer interface {
type UnimplementedUserCPServiceServer struct{}
func (UnimplementedUserCPServiceServer) ListCPApplications(context.Context, *ListCPApplicationsRequest) (*ListCPApplicationsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCPApplications not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCPApplications not implemented")
}
func (UnimplementedUserCPServiceServer) AcceptCPApplication(context.Context, *AcceptCPApplicationRequest) (*AcceptCPApplicationResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AcceptCPApplication not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AcceptCPApplication not implemented")
}
func (UnimplementedUserCPServiceServer) RejectCPApplication(context.Context, *RejectCPApplicationRequest) (*RejectCPApplicationResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RejectCPApplication not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RejectCPApplication not implemented")
}
func (UnimplementedUserCPServiceServer) ListCPRelationships(context.Context, *ListCPRelationshipsRequest) (*ListCPRelationshipsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCPRelationships not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCPRelationships not implemented")
}
func (UnimplementedUserCPServiceServer) ListCPIntimacyLeaderboard(context.Context, *ListCPIntimacyLeaderboardRequest) (*ListCPIntimacyLeaderboardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCPIntimacyLeaderboard not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCPIntimacyLeaderboard not implemented")
}
func (UnimplementedUserCPServiceServer) PrepareBreakCPRelationship(context.Context, *PrepareBreakCPRelationshipRequest) (*PrepareBreakCPRelationshipResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PrepareBreakCPRelationship not implemented")
return nil, status.Errorf(codes.Unimplemented, "method PrepareBreakCPRelationship not implemented")
}
func (UnimplementedUserCPServiceServer) ConfirmBreakCPRelationship(context.Context, *ConfirmBreakCPRelationshipRequest) (*ConfirmBreakCPRelationshipResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConfirmBreakCPRelationship not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConfirmBreakCPRelationship not implemented")
}
func (UnimplementedUserCPServiceServer) CancelBreakCPRelationship(context.Context, *CancelBreakCPRelationshipRequest) (*CancelBreakCPRelationshipResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CancelBreakCPRelationship not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CancelBreakCPRelationship not implemented")
}
func (UnimplementedUserCPServiceServer) mustEmbedUnimplementedUserCPServiceServer() {}
func (UnimplementedUserCPServiceServer) testEmbeddedByValue() {}
@ -1354,7 +1354,7 @@ type UnsafeUserCPServiceServer interface {
}
func RegisterUserCPServiceServer(s grpc.ServiceRegistrar, srv UserCPServiceServer) {
// If the following call panics, it indicates UnimplementedUserCPServiceServer was
// If the following call pancis, 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.
@ -1614,10 +1614,10 @@ type UserCPInternalServiceServer interface {
type UnimplementedUserCPInternalServiceServer struct{}
func (UnimplementedUserCPInternalServiceServer) ConsumeRoomGiftCPEvent(context.Context, *ConsumeRoomGiftCPEventRequest) (*ConsumeRoomGiftCPEventResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConsumeRoomGiftCPEvent not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConsumeRoomGiftCPEvent not implemented")
}
func (UnimplementedUserCPInternalServiceServer) ListCPWeeklyRankEntries(context.Context, *ListCPWeeklyRankEntriesRequest) (*ListCPWeeklyRankEntriesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCPWeeklyRankEntries not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCPWeeklyRankEntries not implemented")
}
func (UnimplementedUserCPInternalServiceServer) mustEmbedUnimplementedUserCPInternalServiceServer() {}
func (UnimplementedUserCPInternalServiceServer) testEmbeddedByValue() {}
@ -1630,7 +1630,7 @@ type UnsafeUserCPInternalServiceServer interface {
}
func RegisterUserCPInternalServiceServer(s grpc.ServiceRegistrar, srv UserCPInternalServiceServer) {
// If the following call panics, it indicates UnimplementedUserCPInternalServiceServer was
// If the following call pancis, 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.
@ -1797,19 +1797,19 @@ type UserCronServiceServer interface {
type UnimplementedUserCronServiceServer struct{}
func (UnimplementedUserCronServiceServer) ProcessLoginIPRiskBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessLoginIPRiskBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessLoginIPRiskBatch not implemented")
}
func (UnimplementedUserCronServiceServer) ProcessRegionRebuildBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessRegionRebuildBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessRegionRebuildBatch not implemented")
}
func (UnimplementedUserCronServiceServer) CompensateMicOpenSessions(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CompensateMicOpenSessions not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CompensateMicOpenSessions not implemented")
}
func (UnimplementedUserCronServiceServer) ExpireManagerUserBlocks(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ExpireManagerUserBlocks not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ExpireManagerUserBlocks not implemented")
}
func (UnimplementedUserCronServiceServer) RefreshCPIntimacyLeaderboard(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RefreshCPIntimacyLeaderboard not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RefreshCPIntimacyLeaderboard not implemented")
}
func (UnimplementedUserCronServiceServer) mustEmbedUnimplementedUserCronServiceServer() {}
func (UnimplementedUserCronServiceServer) testEmbeddedByValue() {}
@ -1822,7 +1822,7 @@ type UnsafeUserCronServiceServer interface {
}
func RegisterUserCronServiceServer(s grpc.ServiceRegistrar, srv UserCronServiceServer) {
// If the following call panics, it indicates UnimplementedUserCronServiceServer was
// If the following call pancis, 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.
@ -2016,10 +2016,10 @@ type UserDeviceServiceServer interface {
type UnimplementedUserDeviceServiceServer struct{}
func (UnimplementedUserDeviceServiceServer) BindPushToken(context.Context, *BindPushTokenRequest) (*BindPushTokenResponse, error) {
return nil, status.Error(codes.Unimplemented, "method BindPushToken not implemented")
return nil, status.Errorf(codes.Unimplemented, "method BindPushToken not implemented")
}
func (UnimplementedUserDeviceServiceServer) DeletePushToken(context.Context, *DeletePushTokenRequest) (*DeletePushTokenResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeletePushToken not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeletePushToken not implemented")
}
func (UnimplementedUserDeviceServiceServer) mustEmbedUnimplementedUserDeviceServiceServer() {}
func (UnimplementedUserDeviceServiceServer) testEmbeddedByValue() {}
@ -2032,7 +2032,7 @@ type UnsafeUserDeviceServiceServer interface {
}
func RegisterUserDeviceServiceServer(s grpc.ServiceRegistrar, srv UserDeviceServiceServer) {
// If the following call panics, it indicates UnimplementedUserDeviceServiceServer was
// If the following call pancis, it indicates UnimplementedUserDeviceServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
@ -2147,7 +2147,7 @@ type AppRegistryServiceServer interface {
type UnimplementedAppRegistryServiceServer struct{}
func (UnimplementedAppRegistryServiceServer) ResolveApp(context.Context, *ResolveAppRequest) (*ResolveAppResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ResolveApp not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ResolveApp not implemented")
}
func (UnimplementedAppRegistryServiceServer) mustEmbedUnimplementedAppRegistryServiceServer() {}
func (UnimplementedAppRegistryServiceServer) testEmbeddedByValue() {}
@ -2160,7 +2160,7 @@ type UnsafeAppRegistryServiceServer interface {
}
func RegisterAppRegistryServiceServer(s grpc.ServiceRegistrar, srv AppRegistryServiceServer) {
// If the following call panics, it indicates UnimplementedAppRegistryServiceServer was
// If the following call pancis, 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.
@ -2268,10 +2268,10 @@ type CountryAdminServiceServer interface {
type UnimplementedCountryAdminServiceServer struct{}
func (UnimplementedCountryAdminServiceServer) ListCountries(context.Context, *ListCountriesRequest) (*ListCountriesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCountries not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCountries not implemented")
}
func (UnimplementedCountryAdminServiceServer) UpdateCountry(context.Context, *UpdateCountryRequest) (*CountryResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateCountry not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateCountry not implemented")
}
func (UnimplementedCountryAdminServiceServer) mustEmbedUnimplementedCountryAdminServiceServer() {}
func (UnimplementedCountryAdminServiceServer) testEmbeddedByValue() {}
@ -2284,7 +2284,7 @@ type UnsafeCountryAdminServiceServer interface {
}
func RegisterCountryAdminServiceServer(s grpc.ServiceRegistrar, srv CountryAdminServiceServer) {
// If the following call panics, it indicates UnimplementedCountryAdminServiceServer was
// If the following call pancis, 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.
@ -2412,10 +2412,10 @@ type CountryQueryServiceServer interface {
type UnimplementedCountryQueryServiceServer struct{}
func (UnimplementedCountryQueryServiceServer) ListRegistrationCountries(context.Context, *ListRegistrationCountriesRequest) (*ListRegistrationCountriesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRegistrationCountries not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRegistrationCountries not implemented")
}
func (UnimplementedCountryQueryServiceServer) ListLoginRiskBlockedCountries(context.Context, *ListLoginRiskBlockedCountriesRequest) (*ListLoginRiskBlockedCountriesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListLoginRiskBlockedCountries not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListLoginRiskBlockedCountries not implemented")
}
func (UnimplementedCountryQueryServiceServer) mustEmbedUnimplementedCountryQueryServiceServer() {}
func (UnimplementedCountryQueryServiceServer) testEmbeddedByValue() {}
@ -2428,7 +2428,7 @@ type UnsafeCountryQueryServiceServer interface {
}
func RegisterCountryQueryServiceServer(s grpc.ServiceRegistrar, srv CountryQueryServiceServer) {
// If the following call panics, it indicates UnimplementedCountryQueryServiceServer was
// If the following call pancis, 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.
@ -2584,16 +2584,16 @@ type RegionAdminServiceServer interface {
type UnimplementedRegionAdminServiceServer struct{}
func (UnimplementedRegionAdminServiceServer) ListRegions(context.Context, *ListRegionsRequest) (*ListRegionsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRegions not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRegions not implemented")
}
func (UnimplementedRegionAdminServiceServer) GetRegion(context.Context, *GetRegionRequest) (*RegionResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRegion not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRegion not implemented")
}
func (UnimplementedRegionAdminServiceServer) UpdateRegion(context.Context, *UpdateRegionRequest) (*RegionResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateRegion not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateRegion not implemented")
}
func (UnimplementedRegionAdminServiceServer) ReplaceRegionCountries(context.Context, *ReplaceRegionCountriesRequest) (*RegionResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ReplaceRegionCountries not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ReplaceRegionCountries not implemented")
}
func (UnimplementedRegionAdminServiceServer) mustEmbedUnimplementedRegionAdminServiceServer() {}
func (UnimplementedRegionAdminServiceServer) testEmbeddedByValue() {}
@ -2606,7 +2606,7 @@ type UnsafeRegionAdminServiceServer interface {
}
func RegisterRegionAdminServiceServer(s grpc.ServiceRegistrar, srv RegionAdminServiceServer) {
// If the following call panics, it indicates UnimplementedRegionAdminServiceServer was
// If the following call pancis, 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.
@ -2843,25 +2843,25 @@ type UserIdentityServiceServer interface {
type UnimplementedUserIdentityServiceServer struct{}
func (UnimplementedUserIdentityServiceServer) GetUserIdentity(context.Context, *GetUserIdentityRequest) (*GetUserIdentityResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserIdentity not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetUserIdentity not implemented")
}
func (UnimplementedUserIdentityServiceServer) ResolveDisplayUserID(context.Context, *ResolveDisplayUserIDRequest) (*ResolveDisplayUserIDResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ResolveDisplayUserID not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ResolveDisplayUserID not implemented")
}
func (UnimplementedUserIdentityServiceServer) ChangeDisplayUserID(context.Context, *ChangeDisplayUserIDRequest) (*ChangeDisplayUserIDResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ChangeDisplayUserID not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ChangeDisplayUserID not implemented")
}
func (UnimplementedUserIdentityServiceServer) ApplyPrettyDisplayUserID(context.Context, *ApplyPrettyDisplayUserIDRequest) (*ApplyPrettyDisplayUserIDResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ApplyPrettyDisplayUserID not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ApplyPrettyDisplayUserID not implemented")
}
func (UnimplementedUserIdentityServiceServer) ListAvailablePrettyDisplayIDs(context.Context, *ListAvailablePrettyDisplayIDsRequest) (*ListAvailablePrettyDisplayIDsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListAvailablePrettyDisplayIDs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListAvailablePrettyDisplayIDs not implemented")
}
func (UnimplementedUserIdentityServiceServer) ApplyPrettyDisplayIDFromPool(context.Context, *ApplyPrettyDisplayIDFromPoolRequest) (*ApplyPrettyDisplayIDFromPoolResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ApplyPrettyDisplayIDFromPool not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ApplyPrettyDisplayIDFromPool not implemented")
}
func (UnimplementedUserIdentityServiceServer) ExpirePrettyDisplayUserID(context.Context, *ExpirePrettyDisplayUserIDRequest) (*ExpirePrettyDisplayUserIDResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ExpirePrettyDisplayUserID not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ExpirePrettyDisplayUserID not implemented")
}
func (UnimplementedUserIdentityServiceServer) mustEmbedUnimplementedUserIdentityServiceServer() {}
func (UnimplementedUserIdentityServiceServer) testEmbeddedByValue() {}
@ -2874,7 +2874,7 @@ type UnsafeUserIdentityServiceServer interface {
}
func RegisterUserIdentityServiceServer(s grpc.ServiceRegistrar, srv UserIdentityServiceServer) {
// If the following call panics, it indicates UnimplementedUserIdentityServiceServer was
// If the following call pancis, 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.
@ -3177,25 +3177,25 @@ type UserPrettyDisplayIDAdminServiceServer interface {
type UnimplementedUserPrettyDisplayIDAdminServiceServer struct{}
func (UnimplementedUserPrettyDisplayIDAdminServiceServer) ListPrettyDisplayIDPools(context.Context, *ListPrettyDisplayIDPoolsRequest) (*ListPrettyDisplayIDPoolsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListPrettyDisplayIDPools not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListPrettyDisplayIDPools not implemented")
}
func (UnimplementedUserPrettyDisplayIDAdminServiceServer) CreatePrettyDisplayIDPool(context.Context, *CreatePrettyDisplayIDPoolRequest) (*PrettyDisplayIDPoolResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreatePrettyDisplayIDPool not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreatePrettyDisplayIDPool not implemented")
}
func (UnimplementedUserPrettyDisplayIDAdminServiceServer) UpdatePrettyDisplayIDPool(context.Context, *UpdatePrettyDisplayIDPoolRequest) (*PrettyDisplayIDPoolResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdatePrettyDisplayIDPool not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdatePrettyDisplayIDPool not implemented")
}
func (UnimplementedUserPrettyDisplayIDAdminServiceServer) GeneratePrettyDisplayIDs(context.Context, *GeneratePrettyDisplayIDsRequest) (*GeneratePrettyDisplayIDsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GeneratePrettyDisplayIDs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GeneratePrettyDisplayIDs not implemented")
}
func (UnimplementedUserPrettyDisplayIDAdminServiceServer) ListPrettyDisplayIDs(context.Context, *ListPrettyDisplayIDsRequest) (*ListPrettyDisplayIDsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListPrettyDisplayIDs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListPrettyDisplayIDs not implemented")
}
func (UnimplementedUserPrettyDisplayIDAdminServiceServer) SetPrettyDisplayIDStatus(context.Context, *SetPrettyDisplayIDStatusRequest) (*PrettyDisplayIDResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetPrettyDisplayIDStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetPrettyDisplayIDStatus not implemented")
}
func (UnimplementedUserPrettyDisplayIDAdminServiceServer) AdminGrantPrettyDisplayID(context.Context, *AdminGrantPrettyDisplayIDRequest) (*AdminGrantPrettyDisplayIDResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminGrantPrettyDisplayID not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminGrantPrettyDisplayID not implemented")
}
func (UnimplementedUserPrettyDisplayIDAdminServiceServer) mustEmbedUnimplementedUserPrettyDisplayIDAdminServiceServer() {
}
@ -3209,7 +3209,7 @@ type UnsafeUserPrettyDisplayIDAdminServiceServer interface {
}
func RegisterUserPrettyDisplayIDAdminServiceServer(s grpc.ServiceRegistrar, srv UserPrettyDisplayIDAdminServiceServer) {
// If the following call panics, it indicates UnimplementedUserPrettyDisplayIDAdminServiceServer was
// If the following call pancis, it indicates UnimplementedUserPrettyDisplayIDAdminServiceServer 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

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc-gen-go-grpc v1.5.1
// - 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.Error(codes.Unimplemented, "method ProcessHostSalaryDailySettlementBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessHostSalaryDailySettlementBatch not implemented")
}
func (UnimplementedWalletCronServiceServer) ProcessHostSalaryHalfMonthSettlementBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessHostSalaryHalfMonthSettlementBatch not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ProcessHostSalaryHalfMonthSettlementBatch not implemented")
}
func (UnimplementedWalletCronServiceServer) ProcessHostSalaryMonthEndBatch(context.Context, *CronBatchRequest) (*CronBatchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessHostSalaryMonthEndBatch not implemented")
return nil, status.Errorf(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 panics, it indicates UnimplementedWalletCronServiceServer was
// If the following call pancis, 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.
@ -1289,247 +1289,247 @@ type WalletServiceServer interface {
type UnimplementedWalletServiceServer struct{}
func (UnimplementedWalletServiceServer) DebitGift(context.Context, *DebitGiftRequest) (*DebitGiftResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DebitGift not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DebitGift not implemented")
}
func (UnimplementedWalletServiceServer) BatchDebitGift(context.Context, *BatchDebitGiftRequest) (*BatchDebitGiftResponse, error) {
return nil, status.Error(codes.Unimplemented, "method BatchDebitGift not implemented")
return nil, status.Errorf(codes.Unimplemented, "method BatchDebitGift not implemented")
}
func (UnimplementedWalletServiceServer) DebitRobotGift(context.Context, *DebitRobotGiftRequest) (*DebitGiftResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DebitRobotGift not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DebitRobotGift not implemented")
}
func (UnimplementedWalletServiceServer) GetBalances(context.Context, *GetBalancesRequest) (*GetBalancesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetBalances not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetBalances not implemented")
}
func (UnimplementedWalletServiceServer) GetActiveHostSalaryPolicy(context.Context, *GetActiveHostSalaryPolicyRequest) (*GetActiveHostSalaryPolicyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetActiveHostSalaryPolicy not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetActiveHostSalaryPolicy not implemented")
}
func (UnimplementedWalletServiceServer) GetHostSalaryProgress(context.Context, *GetHostSalaryProgressRequest) (*GetHostSalaryProgressResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetHostSalaryProgress not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetHostSalaryProgress not implemented")
}
func (UnimplementedWalletServiceServer) AdminCreditAsset(context.Context, *AdminCreditAssetRequest) (*AdminCreditAssetResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminCreditAsset not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminCreditAsset not implemented")
}
func (UnimplementedWalletServiceServer) AdminCreditCoinSellerStock(context.Context, *AdminCreditCoinSellerStockRequest) (*AdminCreditCoinSellerStockResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdminCreditCoinSellerStock not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AdminCreditCoinSellerStock not implemented")
}
func (UnimplementedWalletServiceServer) TransferCoinFromSeller(context.Context, *TransferCoinFromSellerRequest) (*TransferCoinFromSellerResponse, error) {
return nil, status.Error(codes.Unimplemented, "method TransferCoinFromSeller not implemented")
return nil, status.Errorf(codes.Unimplemented, "method TransferCoinFromSeller not implemented")
}
func (UnimplementedWalletServiceServer) ListCoinSellerSalaryExchangeRateTiers(context.Context, *ListCoinSellerSalaryExchangeRateTiersRequest) (*ListCoinSellerSalaryExchangeRateTiersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListCoinSellerSalaryExchangeRateTiers not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListCoinSellerSalaryExchangeRateTiers not implemented")
}
func (UnimplementedWalletServiceServer) ExchangeSalaryToCoin(context.Context, *ExchangeSalaryToCoinRequest) (*ExchangeSalaryToCoinResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ExchangeSalaryToCoin not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ExchangeSalaryToCoin not implemented")
}
func (UnimplementedWalletServiceServer) TransferSalaryToCoinSeller(context.Context, *TransferSalaryToCoinSellerRequest) (*TransferSalaryToCoinSellerResponse, error) {
return nil, status.Error(codes.Unimplemented, "method TransferSalaryToCoinSeller not implemented")
return nil, status.Errorf(codes.Unimplemented, "method TransferSalaryToCoinSeller not implemented")
}
func (UnimplementedWalletServiceServer) ListResources(context.Context, *ListResourcesRequest) (*ListResourcesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListResources not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListResources not implemented")
}
func (UnimplementedWalletServiceServer) GetResource(context.Context, *GetResourceRequest) (*GetResourceResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetResource not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetResource not implemented")
}
func (UnimplementedWalletServiceServer) CreateResource(context.Context, *CreateResourceRequest) (*ResourceResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateResource not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateResource not implemented")
}
func (UnimplementedWalletServiceServer) UpdateResource(context.Context, *UpdateResourceRequest) (*ResourceResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateResource not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateResource not implemented")
}
func (UnimplementedWalletServiceServer) SetResourceStatus(context.Context, *SetResourceStatusRequest) (*ResourceResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetResourceStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetResourceStatus not implemented")
}
func (UnimplementedWalletServiceServer) ListResourceGroups(context.Context, *ListResourceGroupsRequest) (*ListResourceGroupsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListResourceGroups not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListResourceGroups not implemented")
}
func (UnimplementedWalletServiceServer) GetResourceGroup(context.Context, *GetResourceGroupRequest) (*GetResourceGroupResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetResourceGroup not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetResourceGroup not implemented")
}
func (UnimplementedWalletServiceServer) CreateResourceGroup(context.Context, *CreateResourceGroupRequest) (*ResourceGroupResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateResourceGroup not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateResourceGroup not implemented")
}
func (UnimplementedWalletServiceServer) UpdateResourceGroup(context.Context, *UpdateResourceGroupRequest) (*ResourceGroupResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateResourceGroup not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateResourceGroup not implemented")
}
func (UnimplementedWalletServiceServer) SetResourceGroupStatus(context.Context, *SetResourceGroupStatusRequest) (*ResourceGroupResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetResourceGroupStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetResourceGroupStatus not implemented")
}
func (UnimplementedWalletServiceServer) ListGiftConfigs(context.Context, *ListGiftConfigsRequest) (*ListGiftConfigsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListGiftConfigs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListGiftConfigs not implemented")
}
func (UnimplementedWalletServiceServer) ListGiftTypeConfigs(context.Context, *ListGiftTypeConfigsRequest) (*ListGiftTypeConfigsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListGiftTypeConfigs not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListGiftTypeConfigs not implemented")
}
func (UnimplementedWalletServiceServer) CreateGiftConfig(context.Context, *CreateGiftConfigRequest) (*GiftConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateGiftConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateGiftConfig not implemented")
}
func (UnimplementedWalletServiceServer) UpdateGiftConfig(context.Context, *UpdateGiftConfigRequest) (*GiftConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateGiftConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateGiftConfig not implemented")
}
func (UnimplementedWalletServiceServer) SetGiftConfigStatus(context.Context, *SetGiftConfigStatusRequest) (*GiftConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetGiftConfigStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetGiftConfigStatus not implemented")
}
func (UnimplementedWalletServiceServer) DeleteGiftConfig(context.Context, *DeleteGiftConfigRequest) (*GiftConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteGiftConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteGiftConfig not implemented")
}
func (UnimplementedWalletServiceServer) UpsertGiftTypeConfig(context.Context, *UpsertGiftTypeConfigRequest) (*GiftTypeConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertGiftTypeConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertGiftTypeConfig not implemented")
}
func (UnimplementedWalletServiceServer) GrantResource(context.Context, *GrantResourceRequest) (*ResourceGrantResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GrantResource not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GrantResource not implemented")
}
func (UnimplementedWalletServiceServer) GrantResourceGroup(context.Context, *GrantResourceGroupRequest) (*ResourceGrantResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GrantResourceGroup not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GrantResourceGroup not implemented")
}
func (UnimplementedWalletServiceServer) ListUserResources(context.Context, *ListUserResourcesRequest) (*ListUserResourcesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListUserResources not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListUserResources not implemented")
}
func (UnimplementedWalletServiceServer) EquipUserResource(context.Context, *EquipUserResourceRequest) (*EquipUserResourceResponse, error) {
return nil, status.Error(codes.Unimplemented, "method EquipUserResource not implemented")
return nil, status.Errorf(codes.Unimplemented, "method EquipUserResource not implemented")
}
func (UnimplementedWalletServiceServer) UnequipUserResource(context.Context, *UnequipUserResourceRequest) (*UnequipUserResourceResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UnequipUserResource not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UnequipUserResource not implemented")
}
func (UnimplementedWalletServiceServer) BatchGetUserEquippedResources(context.Context, *BatchGetUserEquippedResourcesRequest) (*BatchGetUserEquippedResourcesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method BatchGetUserEquippedResources not implemented")
return nil, status.Errorf(codes.Unimplemented, "method BatchGetUserEquippedResources not implemented")
}
func (UnimplementedWalletServiceServer) ListResourceGrants(context.Context, *ListResourceGrantsRequest) (*ListResourceGrantsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListResourceGrants not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListResourceGrants not implemented")
}
func (UnimplementedWalletServiceServer) ListResourceShopItems(context.Context, *ListResourceShopItemsRequest) (*ListResourceShopItemsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListResourceShopItems not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListResourceShopItems not implemented")
}
func (UnimplementedWalletServiceServer) UpsertResourceShopItems(context.Context, *UpsertResourceShopItemsRequest) (*UpsertResourceShopItemsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpsertResourceShopItems not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpsertResourceShopItems not implemented")
}
func (UnimplementedWalletServiceServer) SetResourceShopItemStatus(context.Context, *SetResourceShopItemStatusRequest) (*ResourceShopItemResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetResourceShopItemStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetResourceShopItemStatus not implemented")
}
func (UnimplementedWalletServiceServer) PurchaseResourceShopItem(context.Context, *PurchaseResourceShopItemRequest) (*PurchaseResourceShopItemResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PurchaseResourceShopItem not implemented")
return nil, status.Errorf(codes.Unimplemented, "method PurchaseResourceShopItem not implemented")
}
func (UnimplementedWalletServiceServer) ListRechargeBills(context.Context, *ListRechargeBillsRequest) (*ListRechargeBillsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRechargeBills not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRechargeBills not implemented")
}
func (UnimplementedWalletServiceServer) GetWalletOverview(context.Context, *GetWalletOverviewRequest) (*GetWalletOverviewResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetWalletOverview not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetWalletOverview not implemented")
}
func (UnimplementedWalletServiceServer) GetWalletValueSummary(context.Context, *GetWalletValueSummaryRequest) (*GetWalletValueSummaryResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetWalletValueSummary not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetWalletValueSummary not implemented")
}
func (UnimplementedWalletServiceServer) GetUserGiftWall(context.Context, *GetUserGiftWallRequest) (*GetUserGiftWallResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserGiftWall not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetUserGiftWall not implemented")
}
func (UnimplementedWalletServiceServer) ListRechargeProducts(context.Context, *ListRechargeProductsRequest) (*ListRechargeProductsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRechargeProducts not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRechargeProducts not implemented")
}
func (UnimplementedWalletServiceServer) ConfirmGooglePayment(context.Context, *ConfirmGooglePaymentRequest) (*ConfirmGooglePaymentResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ConfirmGooglePayment not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ConfirmGooglePayment not implemented")
}
func (UnimplementedWalletServiceServer) ListAdminRechargeProducts(context.Context, *ListAdminRechargeProductsRequest) (*ListAdminRechargeProductsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListAdminRechargeProducts not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListAdminRechargeProducts not implemented")
}
func (UnimplementedWalletServiceServer) CreateRechargeProduct(context.Context, *CreateRechargeProductRequest) (*RechargeProductResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateRechargeProduct not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateRechargeProduct not implemented")
}
func (UnimplementedWalletServiceServer) UpdateRechargeProduct(context.Context, *UpdateRechargeProductRequest) (*RechargeProductResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateRechargeProduct not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateRechargeProduct not implemented")
}
func (UnimplementedWalletServiceServer) DeleteRechargeProduct(context.Context, *DeleteRechargeProductRequest) (*DeleteRechargeProductResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteRechargeProduct not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeleteRechargeProduct not implemented")
}
func (UnimplementedWalletServiceServer) ListThirdPartyPaymentChannels(context.Context, *ListThirdPartyPaymentChannelsRequest) (*ListThirdPartyPaymentChannelsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListThirdPartyPaymentChannels not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListThirdPartyPaymentChannels not implemented")
}
func (UnimplementedWalletServiceServer) SetThirdPartyPaymentMethodStatus(context.Context, *SetThirdPartyPaymentMethodStatusRequest) (*ThirdPartyPaymentMethodResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SetThirdPartyPaymentMethodStatus not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SetThirdPartyPaymentMethodStatus not implemented")
}
func (UnimplementedWalletServiceServer) UpdateThirdPartyPaymentRate(context.Context, *UpdateThirdPartyPaymentRateRequest) (*ThirdPartyPaymentMethodResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateThirdPartyPaymentRate not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateThirdPartyPaymentRate not implemented")
}
func (UnimplementedWalletServiceServer) ListH5RechargeOptions(context.Context, *H5RechargeOptionsRequest) (*H5RechargeOptionsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListH5RechargeOptions not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListH5RechargeOptions not implemented")
}
func (UnimplementedWalletServiceServer) CreateH5RechargeOrder(context.Context, *CreateH5RechargeOrderRequest) (*H5RechargeOrderResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateH5RechargeOrder not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateH5RechargeOrder not implemented")
}
func (UnimplementedWalletServiceServer) SubmitH5RechargeTx(context.Context, *SubmitH5RechargeTxRequest) (*H5RechargeOrderResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SubmitH5RechargeTx not implemented")
return nil, status.Errorf(codes.Unimplemented, "method SubmitH5RechargeTx not implemented")
}
func (UnimplementedWalletServiceServer) GetH5RechargeOrder(context.Context, *GetH5RechargeOrderRequest) (*H5RechargeOrderResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetH5RechargeOrder not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetH5RechargeOrder not implemented")
}
func (UnimplementedWalletServiceServer) HandleMifapayNotify(context.Context, *HandleMifapayNotifyRequest) (*HandleMifapayNotifyResponse, error) {
return nil, status.Error(codes.Unimplemented, "method HandleMifapayNotify not implemented")
return nil, status.Errorf(codes.Unimplemented, "method HandleMifapayNotify not implemented")
}
func (UnimplementedWalletServiceServer) GetDiamondExchangeConfig(context.Context, *GetDiamondExchangeConfigRequest) (*GetDiamondExchangeConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetDiamondExchangeConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetDiamondExchangeConfig not implemented")
}
func (UnimplementedWalletServiceServer) ListWalletTransactions(context.Context, *ListWalletTransactionsRequest) (*ListWalletTransactionsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListWalletTransactions not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListWalletTransactions not implemented")
}
func (UnimplementedWalletServiceServer) ListVipPackages(context.Context, *ListVipPackagesRequest) (*ListVipPackagesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListVipPackages not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListVipPackages not implemented")
}
func (UnimplementedWalletServiceServer) GetMyVip(context.Context, *GetMyVipRequest) (*GetMyVipResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetMyVip not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetMyVip not implemented")
}
func (UnimplementedWalletServiceServer) PurchaseVip(context.Context, *PurchaseVipRequest) (*PurchaseVipResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PurchaseVip not implemented")
return nil, status.Errorf(codes.Unimplemented, "method PurchaseVip not implemented")
}
func (UnimplementedWalletServiceServer) DebitCPBreakupFee(context.Context, *DebitCPBreakupFeeRequest) (*DebitCPBreakupFeeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DebitCPBreakupFee not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DebitCPBreakupFee not implemented")
}
func (UnimplementedWalletServiceServer) GrantVip(context.Context, *GrantVipRequest) (*GrantVipResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GrantVip not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GrantVip not implemented")
}
func (UnimplementedWalletServiceServer) ListAdminVipLevels(context.Context, *ListAdminVipLevelsRequest) (*ListAdminVipLevelsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListAdminVipLevels not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListAdminVipLevels not implemented")
}
func (UnimplementedWalletServiceServer) UpdateAdminVipLevels(context.Context, *UpdateAdminVipLevelsRequest) (*UpdateAdminVipLevelsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateAdminVipLevels not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateAdminVipLevels not implemented")
}
func (UnimplementedWalletServiceServer) CreditTaskReward(context.Context, *CreditTaskRewardRequest) (*CreditTaskRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreditTaskReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreditTaskReward not implemented")
}
func (UnimplementedWalletServiceServer) CreditLuckyGiftReward(context.Context, *CreditLuckyGiftRewardRequest) (*CreditLuckyGiftRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreditLuckyGiftReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreditLuckyGiftReward not implemented")
}
func (UnimplementedWalletServiceServer) CreditRoomTurnoverReward(context.Context, *CreditRoomTurnoverRewardRequest) (*CreditRoomTurnoverRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreditRoomTurnoverReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreditRoomTurnoverReward not implemented")
}
func (UnimplementedWalletServiceServer) CreditInviteActivityReward(context.Context, *CreditInviteActivityRewardRequest) (*CreditInviteActivityRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreditInviteActivityReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreditInviteActivityReward not implemented")
}
func (UnimplementedWalletServiceServer) CreditAgencyOpeningReward(context.Context, *CreditAgencyOpeningRewardRequest) (*CreditAgencyOpeningRewardResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreditAgencyOpeningReward not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreditAgencyOpeningReward not implemented")
}
func (UnimplementedWalletServiceServer) ApplyGameCoinChange(context.Context, *ApplyGameCoinChangeRequest) (*ApplyGameCoinChangeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ApplyGameCoinChange not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ApplyGameCoinChange not implemented")
}
func (UnimplementedWalletServiceServer) GetRedPacketConfig(context.Context, *GetRedPacketConfigRequest) (*GetRedPacketConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRedPacketConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRedPacketConfig not implemented")
}
func (UnimplementedWalletServiceServer) UpdateRedPacketConfig(context.Context, *UpdateRedPacketConfigRequest) (*UpdateRedPacketConfigResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateRedPacketConfig not implemented")
return nil, status.Errorf(codes.Unimplemented, "method UpdateRedPacketConfig not implemented")
}
func (UnimplementedWalletServiceServer) CreateRedPacket(context.Context, *CreateRedPacketRequest) (*CreateRedPacketResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateRedPacket not implemented")
return nil, status.Errorf(codes.Unimplemented, "method CreateRedPacket not implemented")
}
func (UnimplementedWalletServiceServer) ClaimRedPacket(context.Context, *ClaimRedPacketRequest) (*ClaimRedPacketResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ClaimRedPacket not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ClaimRedPacket not implemented")
}
func (UnimplementedWalletServiceServer) ListRedPackets(context.Context, *ListRedPacketsRequest) (*ListRedPacketsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListRedPackets not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRedPackets not implemented")
}
func (UnimplementedWalletServiceServer) GetRedPacket(context.Context, *GetRedPacketRequest) (*GetRedPacketResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRedPacket not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRedPacket not implemented")
}
func (UnimplementedWalletServiceServer) ExpireRedPackets(context.Context, *ExpireRedPacketsRequest) (*ExpireRedPacketsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ExpireRedPackets not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ExpireRedPackets not implemented")
}
func (UnimplementedWalletServiceServer) RetryRedPacketRefund(context.Context, *RetryRedPacketRefundRequest) (*RetryRedPacketRefundResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RetryRedPacketRefund not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RetryRedPacketRefund not implemented")
}
func (UnimplementedWalletServiceServer) mustEmbedUnimplementedWalletServiceServer() {}
func (UnimplementedWalletServiceServer) testEmbeddedByValue() {}
@ -1542,7 +1542,7 @@ type UnsafeWalletServiceServer interface {
}
func RegisterWalletServiceServer(s grpc.ServiceRegistrar, srv WalletServiceServer) {
// If the following call panics, it indicates UnimplementedWalletServiceServer was
// If the following call pancis, it indicates UnimplementedWalletServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.

View File

@ -24,6 +24,7 @@ services:
command: ["sh", "mqbroker", "-n", "rocketmq-namesrv:9876", "-c", "/home/rocketmq/broker.conf"]
ports:
- "19009:10909"
- "10911:10911"
- "19011:10911"
volumes:
- ${DEPLOY_PLATFORM_ROOT:-../deploy-platform}/deploy/rocketmq/broker.conf:/home/rocketmq/broker.conf:ro

View File

@ -111,6 +111,29 @@ type RoomEvent struct {
Attributes map[string]string `json:"attributes,omitempty"`
}
func (event RoomEvent) MarshalJSON() ([]byte, error) {
type roomEventAlias RoomEvent
payload, err := json.Marshal(roomEventAlias(event))
if err != nil {
return nil, err
}
var merged map[string]any
if err := json.Unmarshal(payload, &merged); err != nil {
return nil, err
}
for key, value := range event.Attributes {
if strings.TrimSpace(key) == "" {
continue
}
if _, exists := merged[key]; exists {
// 顶层协议字段由 RoomEvent 结构体负责attributes 只能补充展示字段,不能覆盖事件身份。
continue
}
merged[key] = value
}
return json.Marshal(merged)
}
// RoomEntryVehicleSnapshot 是房间系统消息里可直接渲染的座驾素材快照。
// 它故意不包含 wallet 内部状态,只保留客户端展示和过期兜底需要的字段。
type RoomEntryVehicleSnapshot struct {

View File

@ -48,6 +48,24 @@ func TestRealTencentIMCreateSendAndDestroyGroup(t *testing.T) {
if err := realImportAccount(ctx, client, memberUserID); err != nil {
t.Fatalf("real Tencent IM account import failed: %v", err)
}
c2cEventID := fmt.Sprintf("codex_real_im_c2c_%d", nowMS)
c2cPayload, err := json.Marshal(map[string]any{
"event_id": c2cEventID,
"event_type": "codex_real_im_c2c_probe",
"sent_at_ms": nowMS,
})
if err != nil {
t.Fatalf("marshal c2c smoke payload failed: %v", err)
}
if err := client.PublishUserCustomMessage(ctx, CustomUserMessage{
ToAccount: strconv.FormatInt(memberUserID, 10),
EventID: c2cEventID,
Desc: "codex_real_im_c2c_probe",
Ext: "im_c2c_smoke",
PayloadJSON: c2cPayload,
}); err != nil {
t.Fatalf("real Tencent IM send C2C custom message failed: %v", err)
}
if err := realAddGroupMember(ctx, client, groupID, memberUserID); err != nil {
t.Fatalf("real Tencent IM add group member failed: %v", err)
}
@ -82,7 +100,7 @@ func TestRealTencentIMCreateSendAndDestroyGroup(t *testing.T) {
t.Fatalf("real Tencent IM delete group member failed: %v", err)
}
t.Logf("real Tencent IM smoke passed: sdk_app_id=%d group_id=%s event_id=%s removed_user_id=%d", cfg.SDKAppID, groupID, eventID, memberUserID)
t.Logf("real Tencent IM smoke passed: sdk_app_id=%d group_id=%s group_event_id=%s c2c_event_id=%s removed_user_id=%d", cfg.SDKAppID, groupID, eventID, c2cEventID, memberUserID)
}
func realImportAccount(ctx context.Context, client *RESTClient, userID int64) error {

View File

@ -97,6 +97,60 @@ func TestRESTClientPublishRoomEventBuildsCustomMessage(t *testing.T) {
}
}
func TestRESTClientPublishRoomEventFlattensAttributesForClientPayload(t *testing.T) {
var capturedBody map[string]any
client := newTestRESTClient(t, func(request *http.Request) (*http.Response, error) {
if err := json.NewDecoder(request.Body).Decode(&capturedBody); err != nil {
t.Fatalf("decode request body failed: %v", err)
}
return okRESTResponse(), nil
})
err := client.PublishRoomEvent(context.Background(), RoomEvent{
GroupID: "room_1001",
EventID: "evt-robot-lucky-1",
RoomID: "room-1001",
EventType: "lucky_gift_drawn",
ActorUserID: 10001,
TargetUserID: 10002,
GiftValue: 500,
Attributes: map[string]string{
"event_type": "should_not_override",
"draw_id": "robot_lucky_draw_1",
"gift_id": "gift_lucky_1",
"gift_count": "1",
"pool_id": "robot_lucky_display",
"multiplier_ppm": "5000000",
"effective_reward_coins": "500",
"reward_status": "granted",
},
})
if err != nil {
t.Fatalf("PublishRoomEvent failed: %v", err)
}
body, ok := capturedBody["MsgBody"].([]any)
if !ok || len(body) != 1 {
t.Fatalf("unexpected msg body: %+v", capturedBody["MsgBody"])
}
element := body[0].(map[string]any)
content := element["MsgContent"].(map[string]any)
var payload map[string]any
if err := json.Unmarshal([]byte(content["Data"].(string)), &payload); err != nil {
t.Fatalf("decode custom data failed: %v", err)
}
if payload["event_type"] != "lucky_gift_drawn" {
t.Fatalf("attributes must not override top-level event_type: %+v", payload)
}
if payload["draw_id"] != "robot_lucky_draw_1" || payload["effective_reward_coins"] != "500" || payload["reward_status"] != "granted" {
t.Fatalf("lucky gift attributes must be flattened for existing clients: %+v", payload)
}
attributes, ok := payload["attributes"].(map[string]any)
if !ok || attributes["effective_reward_coins"] != "500" {
t.Fatalf("attributes must still be kept for diagnostics and fallback clients: %+v", payload["attributes"])
}
}
func TestRESTClientPublishGroupCustomMessageBuildsBroadcastPayload(t *testing.T) {
var capturedBody map[string]any
client := newTestRESTClient(t, func(request *http.Request) (*http.Response, error) {

View File

@ -272,6 +272,7 @@ func main() {
userclient.NewGRPC(userConn),
auditHandler,
gamemanagementmodule.WithRobotProfileSource(robotProfileSource),
gamemanagementmodule.WithRobotAppearanceServices(walletclient.NewGRPC(walletConn), activityclient.NewGRPC(activityConn)),
),
GiftDiamond: giftdiamondmodule.New(walletDB, auditHandler),
Health: healthmodule.New(store, redisClient, jobStatus),
@ -291,7 +292,7 @@ func main() {
RegistrationReward: registrationrewardmodule.New(activityclient.NewGRPC(activityConn), userDB, auditHandler),
RegionBlock: regionblockmodule.New(userDB, auditHandler),
Resource: resourcemodule.New(walletclient.NewGRPC(walletConn), store, userDB, cfg.WalletService.RequestTimeout, auditHandler),
RoomAdmin: roomadminmodule.New(userDB, roomClient, robotClient, auditHandler),
RoomAdmin: roomadminmodule.New(userDB, store, roomClient, robotClient, auditHandler),
RoomRocket: roomrocketmodule.New(roomClient, auditHandler),
RoomTurnoverReward: roomturnoverrewardmodule.New(activityclient.NewGRPC(activityConn), userDB, auditHandler),
Search: searchmodule.New(store),

View File

@ -61,6 +61,7 @@ type Client interface {
UpsertLevelTrack(ctx context.Context, req *activityv1.UpsertLevelTrackRequest) (*activityv1.UpsertLevelTrackResponse, error)
UpsertLevelRule(ctx context.Context, req *activityv1.UpsertLevelRuleRequest) (*activityv1.UpsertLevelRuleResponse, error)
UpsertLevelTier(ctx context.Context, req *activityv1.UpsertLevelTierRequest) (*activityv1.UpsertLevelTierResponse, error)
SetUserLevel(ctx context.Context, req *activityv1.SetUserLevelRequest) (*activityv1.SetUserLevelResponse, error)
CreateInboxMessage(ctx context.Context, req *activityv1.CreateInboxMessageRequest) (*activityv1.CreateInboxMessageResponse, error)
CreateFanoutJob(ctx context.Context, req *activityv1.CreateFanoutJobRequest) (*activityv1.CreateFanoutJobResponse, error)
}
@ -79,6 +80,7 @@ type GRPCClient struct {
cpWeeklyRankClient activityv1.AdminCPWeeklyRankServiceClient
luckyGiftClient activityv1.AdminLuckyGiftServiceClient
broadcastClient activityv1.BroadcastServiceClient
levelClient activityv1.GrowthLevelServiceClient
growthClient activityv1.AdminGrowthLevelServiceClient
messageClient activityv1.MessageInboxServiceClient
}
@ -98,6 +100,7 @@ func NewGRPC(conn grpc.ClientConnInterface) *GRPCClient {
cpWeeklyRankClient: activityv1.NewAdminCPWeeklyRankServiceClient(conn),
luckyGiftClient: activityv1.NewAdminLuckyGiftServiceClient(conn),
broadcastClient: activityv1.NewBroadcastServiceClient(conn),
levelClient: activityv1.NewGrowthLevelServiceClient(conn),
growthClient: activityv1.NewAdminGrowthLevelServiceClient(conn),
messageClient: activityv1.NewMessageInboxServiceClient(conn),
}
@ -307,6 +310,10 @@ func (c *GRPCClient) UpsertLevelTier(ctx context.Context, req *activityv1.Upsert
return c.growthClient.UpsertLevelTier(ctx, req)
}
func (c *GRPCClient) SetUserLevel(ctx context.Context, req *activityv1.SetUserLevelRequest) (*activityv1.SetUserLevelResponse, error) {
return c.levelClient.SetUserLevel(ctx, req)
}
func (c *GRPCClient) CreateInboxMessage(ctx context.Context, req *activityv1.CreateInboxMessageRequest) (*activityv1.CreateInboxMessageResponse, error) {
return c.messageClient.CreateInboxMessage(ctx, req)
}

View File

@ -21,6 +21,8 @@ type Client interface {
UpdateRoomRocketConfig(ctx context.Context, req UpdateRoomRocketConfigRequest) (RoomRocketConfig, error)
GetRoomSeatConfig(ctx context.Context) (RoomSeatConfig, error)
UpdateRoomSeatConfig(ctx context.Context, req UpdateRoomSeatConfigRequest) (RoomSeatConfig, error)
GetHumanRoomRobotConfig(ctx context.Context) (HumanRoomRobotConfig, error)
UpdateHumanRoomRobotConfig(ctx context.Context, req UpdateHumanRoomRobotConfigRequest) (HumanRoomRobotConfig, error)
ListRoomPins(ctx context.Context, req ListRoomPinsRequest) (ListRoomPinsResult, error)
CreateRoomPin(ctx context.Context, req CreateRoomPinRequest) (RoomPin, error)
CancelRoomPin(ctx context.Context, req CancelRoomPinRequest) (RoomPin, error)
@ -162,6 +164,38 @@ type UpdateRoomSeatConfigRequest struct {
DefaultSeatCount int32
}
type HumanRoomRobotConfig struct {
AppCode string
Enabled bool
CandidateRoomMaxOnline int32
RoomFullStopOnline int32
RoomTargetMinOnline int32
RoomTargetMaxOnline int32
RobotStayMinMS int64
RobotStayMaxMS int64
RobotReplaceMinMS int64
RobotReplaceMaxMS int64
NormalGiftIntervalMS int64
NormalGiftIntervalMinMS int64
NormalGiftIntervalMaxMS int64
GiftIDs []string
LuckyGiftIDs []string
SuperLuckyGiftIDs []string
LuckyComboMin int64
LuckyComboMax int64
LuckyPauseMinMS int64
LuckyPauseMaxMS int64
MaxGiftSenders int64
UpdatedByAdminID uint64
CreatedAtMS int64
UpdatedAtMS int64
}
type UpdateHumanRoomRobotConfigRequest struct {
Config HumanRoomRobotConfig
AdminID uint64
}
type RoomPinRoom struct {
RoomID string
RoomShortID string
@ -226,6 +260,11 @@ type RobotRoomGiftRule struct {
LuckyComboMax int64
LuckyPauseMinMS int64
LuckyPauseMaxMS int64
RobotStayMinMS int64
RobotStayMaxMS int64
RobotReplaceMinMS int64
RobotReplaceMaxMS int64
MaxGiftSenders int64
}
type RobotRoom struct {
@ -238,6 +277,8 @@ type RobotRoom struct {
Status string
OwnerRobotUserID int64
RobotUserIDs []int64
ActiveRobotCount int32
SeatCount int32
GiftRule RobotRoomGiftRule
CreatedByAdminID uint64
CreatedAtMS int64
@ -263,6 +304,8 @@ type CreateRobotRoomRequest struct {
RoomName string
RoomAvatar string
VisibleRegionID int64
OwnerCountryCode string
SeatCount int32
GiftRule RobotRoomGiftRule
AdminID uint64
}
@ -415,6 +458,26 @@ func (c *GRPCClient) UpdateRoomSeatConfig(ctx context.Context, req UpdateRoomSea
return roomSeatConfigFromProto(resp.GetConfig()), nil
}
func (c *GRPCClient) GetHumanRoomRobotConfig(ctx context.Context) (HumanRoomRobotConfig, error) {
resp, err := c.queryClient.AdminGetHumanRoomRobotConfig(ctx, &roomv1.AdminGetHumanRoomRobotConfigRequest{Meta: requestMeta(ctx, "", 0, "admin-get-human-room-robot-config")})
if err != nil {
return HumanRoomRobotConfig{}, err
}
return humanRoomRobotConfigFromProto(resp.GetConfig()), nil
}
func (c *GRPCClient) UpdateHumanRoomRobotConfig(ctx context.Context, req UpdateHumanRoomRobotConfigRequest) (HumanRoomRobotConfig, error) {
resp, err := c.client.AdminUpdateHumanRoomRobotConfig(ctx, &roomv1.AdminUpdateHumanRoomRobotConfigRequest{
Meta: requestMeta(ctx, "", int64(req.AdminID), "admin-update-human-room-robot-config"),
Config: humanRoomRobotConfigToProto(req.Config),
AdminId: req.AdminID,
})
if err != nil {
return HumanRoomRobotConfig{}, err
}
return humanRoomRobotConfigFromProto(resp.GetConfig()), nil
}
func (c *GRPCClient) ListRoomPins(ctx context.Context, req ListRoomPinsRequest) (ListRoomPinsResult, error) {
resp, err := c.queryClient.AdminListRoomPins(ctx, &roomv1.AdminListRoomPinsRequest{
Meta: requestMeta(ctx, "", 0, "admin-list-room-pins"),
@ -491,6 +554,8 @@ func (c *GRPCClient) CreateRobotRoom(ctx context.Context, req CreateRobotRoomReq
RoomName: strings.TrimSpace(req.RoomName),
RoomAvatar: strings.TrimSpace(req.RoomAvatar),
VisibleRegionId: req.VisibleRegionID,
OwnerCountryCode: strings.ToUpper(strings.TrimSpace(req.OwnerCountryCode)),
SeatCount: req.SeatCount,
GiftRule: robotRoomGiftRuleToProto(req.GiftRule),
AdminId: req.AdminID,
})
@ -655,6 +720,69 @@ func roomSeatConfigFromProto(input *roomv1.AdminRoomSeatConfig) RoomSeatConfig {
}
}
func humanRoomRobotConfigFromProto(input *roomv1.AdminHumanRoomRobotConfig) HumanRoomRobotConfig {
if input == nil {
return HumanRoomRobotConfig{}
}
config := HumanRoomRobotConfig{
AppCode: input.GetAppCode(),
Enabled: input.GetEnabled(),
CandidateRoomMaxOnline: input.GetCandidateRoomMaxOnline(),
RoomFullStopOnline: input.GetRoomFullStopOnline(),
RoomTargetMinOnline: input.GetRoomTargetMinOnline(),
RoomTargetMaxOnline: input.GetRoomTargetMaxOnline(),
RobotStayMinMS: input.GetRobotStayMinMs(),
RobotStayMaxMS: input.GetRobotStayMaxMs(),
RobotReplaceMinMS: input.GetRobotReplaceMinMs(),
RobotReplaceMaxMS: input.GetRobotReplaceMaxMs(),
NormalGiftIntervalMS: input.GetNormalGiftIntervalMs(),
NormalGiftIntervalMinMS: input.GetNormalGiftIntervalMinMs(),
NormalGiftIntervalMaxMS: input.GetNormalGiftIntervalMaxMs(),
GiftIDs: append([]string(nil), input.GetGiftIds()...),
LuckyGiftIDs: append([]string(nil), input.GetLuckyGiftIds()...),
SuperLuckyGiftIDs: append([]string(nil), input.GetSuperLuckyGiftIds()...),
LuckyComboMin: input.GetLuckyComboMin(),
LuckyComboMax: input.GetLuckyComboMax(),
LuckyPauseMinMS: input.GetLuckyPauseMinMs(),
LuckyPauseMaxMS: input.GetLuckyPauseMaxMs(),
MaxGiftSenders: input.GetMaxGiftSenders(),
UpdatedByAdminID: input.GetUpdatedByAdminId(),
CreatedAtMS: input.GetCreatedAtMs(),
UpdatedAtMS: input.GetUpdatedAtMs(),
}
return config
}
func humanRoomRobotConfigToProto(input HumanRoomRobotConfig) *roomv1.AdminHumanRoomRobotConfig {
out := &roomv1.AdminHumanRoomRobotConfig{
AppCode: input.AppCode,
Enabled: input.Enabled,
CandidateRoomMaxOnline: input.CandidateRoomMaxOnline,
RoomFullStopOnline: input.RoomFullStopOnline,
RoomTargetMinOnline: input.RoomTargetMinOnline,
RoomTargetMaxOnline: input.RoomTargetMaxOnline,
RobotStayMinMs: input.RobotStayMinMS,
RobotStayMaxMs: input.RobotStayMaxMS,
RobotReplaceMinMs: input.RobotReplaceMinMS,
RobotReplaceMaxMs: input.RobotReplaceMaxMS,
NormalGiftIntervalMs: input.NormalGiftIntervalMS,
NormalGiftIntervalMinMs: input.NormalGiftIntervalMinMS,
NormalGiftIntervalMaxMs: input.NormalGiftIntervalMaxMS,
GiftIds: append([]string(nil), input.GiftIDs...),
LuckyGiftIds: append([]string(nil), input.LuckyGiftIDs...),
SuperLuckyGiftIds: append([]string(nil), input.SuperLuckyGiftIDs...),
LuckyComboMin: input.LuckyComboMin,
LuckyComboMax: input.LuckyComboMax,
LuckyPauseMinMs: input.LuckyPauseMinMS,
LuckyPauseMaxMs: input.LuckyPauseMaxMS,
MaxGiftSenders: input.MaxGiftSenders,
UpdatedByAdminId: input.UpdatedByAdminID,
CreatedAtMs: input.CreatedAtMS,
UpdatedAtMs: input.UpdatedAtMS,
}
return out
}
func roomPinFromProto(input *roomv1.AdminRoomPin) RoomPin {
if input == nil {
return RoomPin{}
@ -700,6 +828,8 @@ func robotRoomFromProto(input *roomv1.AdminRobotRoom) RobotRoom {
Status: input.GetStatus(),
OwnerRobotUserID: input.GetOwnerRobotUserId(),
RobotUserIDs: append([]int64(nil), input.GetRobotUserIds()...),
ActiveRobotCount: input.GetActiveRobotCount(),
SeatCount: input.GetSeatCount(),
GiftRule: robotRoomGiftRuleFromProto(input.GetGiftRule()),
CreatedByAdminID: input.GetCreatedByAdminId(),
CreatedAtMS: input.GetCreatedAtMs(),
@ -719,6 +849,11 @@ func robotRoomGiftRuleFromProto(input *roomv1.AdminRobotRoomGiftRule) RobotRoomG
LuckyComboMax: input.GetLuckyComboMax(),
LuckyPauseMinMS: input.GetLuckyPauseMinMs(),
LuckyPauseMaxMS: input.GetLuckyPauseMaxMs(),
RobotStayMinMS: input.GetRobotStayMinMs(),
RobotStayMaxMS: input.GetRobotStayMaxMs(),
RobotReplaceMinMS: input.GetRobotReplaceMinMs(),
RobotReplaceMaxMS: input.GetRobotReplaceMaxMs(),
MaxGiftSenders: input.GetMaxGiftSenders(),
}
}
@ -731,6 +866,11 @@ func robotRoomGiftRuleToProto(input RobotRoomGiftRule) *roomv1.AdminRobotRoomGif
LuckyComboMax: input.LuckyComboMax,
LuckyPauseMinMs: input.LuckyPauseMinMS,
LuckyPauseMaxMs: input.LuckyPauseMaxMS,
RobotStayMinMs: input.RobotStayMinMS,
RobotStayMaxMs: input.RobotStayMaxMS,
RobotReplaceMinMs: input.RobotReplaceMinMS,
RobotReplaceMaxMs: input.RobotReplaceMaxMS,
MaxGiftSenders: input.MaxGiftSenders,
}
}

View File

@ -29,6 +29,7 @@ type Client interface {
UpsertGiftTypeConfig(ctx context.Context, req *walletv1.UpsertGiftTypeConfigRequest) (*walletv1.GiftTypeConfigResponse, error)
GrantResource(ctx context.Context, req *walletv1.GrantResourceRequest) (*walletv1.ResourceGrantResponse, error)
GrantResourceGroup(ctx context.Context, req *walletv1.GrantResourceGroupRequest) (*walletv1.ResourceGrantResponse, error)
EquipUserResource(ctx context.Context, req *walletv1.EquipUserResourceRequest) (*walletv1.EquipUserResourceResponse, error)
ListResourceGrants(ctx context.Context, req *walletv1.ListResourceGrantsRequest) (*walletv1.ListResourceGrantsResponse, error)
ListResourceShopItems(ctx context.Context, req *walletv1.ListResourceShopItemsRequest) (*walletv1.ListResourceShopItemsResponse, error)
UpsertResourceShopItems(ctx context.Context, req *walletv1.UpsertResourceShopItemsRequest) (*walletv1.UpsertResourceShopItemsResponse, error)
@ -137,6 +138,10 @@ func (c *GRPCClient) GrantResourceGroup(ctx context.Context, req *walletv1.Grant
return c.client.GrantResourceGroup(ctx, req)
}
func (c *GRPCClient) EquipUserResource(ctx context.Context, req *walletv1.EquipUserResourceRequest) (*walletv1.EquipUserResourceResponse, error) {
return c.client.EquipUserResource(ctx, req)
}
func (c *GRPCClient) ListResourceGrants(ctx context.Context, req *walletv1.ListResourceGrantsRequest) (*walletv1.ListResourceGrantsResponse, error) {
return c.client.ListResourceGrants(ctx, req)
}

View File

@ -97,7 +97,7 @@ type AppBanner struct {
CoverURL string `gorm:"size:1024;not null" json:"coverUrl"`
RoomSmallImageURL string `gorm:"column:room_small_image_url;size:1024;not null;default:'';comment:房间内小屏图 URL" json:"roomSmallImageUrl"`
BannerType string `gorm:"size:16;not null" json:"bannerType"`
DisplayScope string `gorm:"size:128;index:idx_admin_app_banners_display,not null;default:home;comment:显示范围,多选逗号分隔:首页、房间内或充值页" json:"displayScope"`
DisplayScope string `gorm:"size:128;index:idx_admin_app_banners_display,not null;default:home;comment:显示范围,多选逗号分隔:首页、房间内、充值页或我的页" json:"displayScope"`
Param string `gorm:"size:2048" json:"param"`
Status string `gorm:"size:24;index:idx_admin_app_banners_app_sort,not null;default:active" json:"status"`
Platform string `gorm:"size:24;index:idx_admin_app_banners_scope,not null" json:"platform"`

View File

@ -19,6 +19,7 @@ const (
bannerDisplayScopeHome = "home"
bannerDisplayScopeRoom = "room"
bannerDisplayScopeRecharge = "recharge"
bannerDisplayScopeMe = "me"
bannerStatusActive = "active"
bannerStatusDisabled = "disabled"
@ -27,7 +28,7 @@ const (
splashDefaultDisplayDurationMS = 3000
)
var bannerDisplayScopeOrder = []string{bannerDisplayScopeHome, bannerDisplayScopeRoom, bannerDisplayScopeRecharge}
var bannerDisplayScopeOrder = []string{bannerDisplayScopeHome, bannerDisplayScopeRoom, bannerDisplayScopeRecharge, bannerDisplayScopeMe}
type AppConfigService struct {
store *repository.Store
@ -963,6 +964,8 @@ func normalizeBannerDisplayScope(value string) string {
return bannerDisplayScopeRoom
case bannerDisplayScopeRecharge, "充值页":
return bannerDisplayScopeRecharge
case bannerDisplayScopeMe, "我的页", "我的":
return bannerDisplayScopeMe
default:
return value
}
@ -1017,7 +1020,7 @@ func validBannerDisplayScopes(scopes []string) bool {
return false
}
for _, scope := range scopes {
if scope != bannerDisplayScopeHome && scope != bannerDisplayScopeRoom && scope != bannerDisplayScopeRecharge {
if scope != bannerDisplayScopeHome && scope != bannerDisplayScopeRoom && scope != bannerDisplayScopeRecharge && scope != bannerDisplayScopeMe {
return false
}
}

View File

@ -94,12 +94,12 @@ func TestBannerModelFromRequestExpiresEndedActiveBanner(t *testing.T) {
}
func TestAppBannerFromModelReturnsDisplayScopes(t *testing.T) {
item := appBannerFromModel(bannerModel("home,room,recharge"))
item := appBannerFromModel(bannerModel("home,room,recharge,me"))
if item.DisplayScope != "home,room,recharge" {
if item.DisplayScope != "home,room,recharge,me" {
t.Fatalf("display scope should keep stored value: %+v", item)
}
if len(item.DisplayScopes) != 3 || item.DisplayScopes[0] != bannerDisplayScopeHome || item.DisplayScopes[1] != bannerDisplayScopeRoom || item.DisplayScopes[2] != bannerDisplayScopeRecharge {
if len(item.DisplayScopes) != 4 || item.DisplayScopes[0] != bannerDisplayScopeHome || item.DisplayScopes[1] != bannerDisplayScopeRoom || item.DisplayScopes[2] != bannerDisplayScopeRecharge || item.DisplayScopes[3] != bannerDisplayScopeMe {
t.Fatalf("display scopes mismatch: %+v", item.DisplayScopes)
}
}

View File

@ -4,8 +4,10 @@ import (
"strconv"
"strings"
"hyapp-admin-server/internal/integration/activityclient"
"hyapp-admin-server/internal/integration/gameclient"
"hyapp-admin-server/internal/integration/userclient"
"hyapp-admin-server/internal/integration/walletclient"
"hyapp-admin-server/internal/modules/shared"
"hyapp-admin-server/internal/response"
gamev1 "hyapp.local/api/proto/game/v1"
@ -16,6 +18,8 @@ import (
type Handler struct {
game gameclient.Client
user userclient.Client
wallet walletclient.Client
activity activityclient.Client
audit shared.OperationLogger
robotProfiles RobotProfileSource
}

View File

@ -0,0 +1,189 @@
package gamemanagement
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
activityv1 "hyapp.local/api/proto/activity/v1"
walletv1 "hyapp.local/api/proto/wallet/v1"
)
const (
robotResourceDurationDays = 9999
robotResourceDurationMS = int64(robotResourceDurationDays) * int64(24*time.Hour/time.Millisecond)
robotMinDisplayLevel = 5
robotMaxDisplayLevel = 30
)
type robotAppearanceCatalog struct {
avatarFrames []*walletv1.Resource
vehicles []*walletv1.Resource
longBadges []*walletv1.Resource
shortBadges []*walletv1.Resource
}
func (h *Handler) initializeGeneratedRobotAppearance(ctx context.Context, requestID string, appCode string, actorUserID int64, userID int64) error {
if h.wallet == nil || h.activity == nil {
return fmt.Errorf("机器人装扮初始化依赖未配置")
}
catalog, err := h.loadRobotAppearanceCatalog(ctx, requestID, appCode)
if err != nil {
return err
}
avatarFrame := randomRobotResource(catalog.avatarFrames)
vehicle := randomRobotResource(catalog.vehicles)
longBadge := randomRobotResource(catalog.longBadges)
shortBadge := randomRobotResource(catalog.shortBadges)
if avatarFrame == nil || vehicle == nil || longBadge == nil || shortBadge == nil {
return fmt.Errorf("机器人装扮资源库不完整: 头像框=%d 座驾=%d 长徽章=%d 短徽章=%d", len(catalog.avatarFrames), len(catalog.vehicles), len(catalog.longBadges), len(catalog.shortBadges))
}
if err := h.grantAndEquipRobotResource(ctx, requestID, appCode, actorUserID, userID, "avatar_frame", avatarFrame.GetResourceId(), true); err != nil {
return err
}
if err := h.grantAndEquipRobotResource(ctx, requestID, appCode, actorUserID, userID, "vehicle", vehicle.GetResourceId(), true); err != nil {
return err
}
if err := h.grantAndEquipRobotResource(ctx, requestID, appCode, actorUserID, userID, "long_badge", longBadge.GetResourceId(), false); err != nil {
return err
}
if err := h.grantAndEquipRobotResource(ctx, requestID, appCode, actorUserID, userID, "short_badge", shortBadge.GetResourceId(), false); err != nil {
return err
}
// 财富和魅力等级由 activity-service 按等级规则写入账户、展示投影和等级奖励 job
// admin-server 只给出目标等级,避免绕过成长系统直接伪造资料卡字段。
if err := h.setRobotDisplayLevel(ctx, requestID, appCode, actorUserID, userID, "wealth", int32(robotMinDisplayLevel+randomRobotInt(robotMaxDisplayLevel-robotMinDisplayLevel+1))); err != nil {
return err
}
if err := h.setRobotDisplayLevel(ctx, requestID, appCode, actorUserID, userID, "charm", int32(robotMinDisplayLevel+randomRobotInt(robotMaxDisplayLevel-robotMinDisplayLevel+1))); err != nil {
return err
}
return nil
}
func (h *Handler) loadRobotAppearanceCatalog(ctx context.Context, requestID string, appCode string) (robotAppearanceCatalog, error) {
avatarFrames, err := h.listRobotResources(ctx, requestID, appCode, "avatar_frame")
if err != nil {
return robotAppearanceCatalog{}, err
}
vehicles, err := h.listRobotResources(ctx, requestID, appCode, "vehicle")
if err != nil {
return robotAppearanceCatalog{}, err
}
badges, err := h.listRobotResources(ctx, requestID, appCode, "badge")
if err != nil {
return robotAppearanceCatalog{}, err
}
catalog := robotAppearanceCatalog{avatarFrames: avatarFrames, vehicles: vehicles}
for _, badge := range badges {
switch robotBadgeForm(badge.GetMetadataJson()) {
case "strip", "long":
catalog.longBadges = append(catalog.longBadges, badge)
case "tile", "short":
catalog.shortBadges = append(catalog.shortBadges, badge)
}
}
return catalog, nil
}
func (h *Handler) listRobotResources(ctx context.Context, requestID string, appCode string, resourceType string) ([]*walletv1.Resource, error) {
resp, err := h.wallet.ListResources(ctx, &walletv1.ListResourcesRequest{
RequestId: requestID,
AppCode: appCode,
ResourceType: resourceType,
Page: 1,
PageSize: 500,
ActiveOnly: true,
ManagerGrantOnly: true,
})
if err != nil {
return nil, fmt.Errorf("读取机器人%s资源失败: %w", resourceType, err)
}
resources := make([]*walletv1.Resource, 0, len(resp.GetResources()))
for _, item := range resp.GetResources() {
if item != nil && item.GetResourceId() > 0 && item.GetStatus() == "active" && item.GetManagerGrantEnabled() {
resources = append(resources, item)
}
}
return resources, nil
}
func (h *Handler) grantAndEquipRobotResource(ctx context.Context, requestID string, appCode string, actorUserID int64, userID int64, slot string, resourceID int64, equip bool) error {
grant, err := h.wallet.GrantResource(ctx, &walletv1.GrantResourceRequest{
CommandId: fmt.Sprintf("game_robot_init:%s:%d:%s:%d", requestID, userID, slot, resourceID),
AppCode: appCode,
TargetUserId: userID,
ResourceId: resourceID,
Quantity: 1,
DurationMs: robotResourceDurationMS,
Reason: "game_robot_init",
OperatorUserId: actorUserID,
GrantSource: "game_robot_init",
})
if err != nil {
return fmt.Errorf("发放机器人%s失败: %w", slot, err)
}
if !equip {
return nil
}
entitlementID := ""
for _, item := range grant.GetGrant().GetItems() {
if item.GetResourceId() == resourceID {
entitlementID = item.GetEntitlementId()
break
}
}
if _, err := h.wallet.EquipUserResource(ctx, &walletv1.EquipUserResourceRequest{
RequestId: fmt.Sprintf("%s:%s:equip", requestID, slot),
AppCode: appCode,
UserId: userID,
ResourceId: resourceID,
EntitlementId: entitlementID,
}); err != nil {
return fmt.Errorf("装备机器人%s失败: %w", slot, err)
}
return nil
}
func (h *Handler) setRobotDisplayLevel(ctx context.Context, requestID string, appCode string, actorUserID int64, userID int64, track string, level int32) error {
_, err := h.activity.SetUserLevel(ctx, &activityv1.SetUserLevelRequest{
Meta: activityRequestMeta(requestID, appCode),
CommandId: fmt.Sprintf("game_robot_init:%s:%d:%s:%d", requestID, userID, track, level),
UserId: userID,
Track: track,
Level: level,
OperatorUserId: actorUserID,
Reason: "game_robot_init",
})
if err != nil {
return fmt.Errorf("设置机器人%s等级失败: %w", track, err)
}
return nil
}
func robotBadgeForm(metadataJSON string) string {
var payload map[string]any
if err := json.Unmarshal([]byte(strings.TrimSpace(metadataJSON)), &payload); err != nil {
return ""
}
value, _ := payload["badge_form"].(string)
return strings.ToLower(strings.TrimSpace(value))
}
func randomRobotResource(items []*walletv1.Resource) *walletv1.Resource {
if len(items) == 0 {
return nil
}
return items[randomRobotInt(int64(len(items)))]
}
func activityRequestMeta(requestID string, appCode string) *activityv1.RequestMeta {
return &activityv1.RequestMeta{
RequestId: requestID,
Caller: "admin-server",
SentAtMs: time.Now().UnixMilli(),
AppCode: appCode,
}
}

View File

@ -9,6 +9,9 @@ import (
"net/url"
"strings"
"unicode/utf8"
"hyapp-admin-server/internal/integration/activityclient"
"hyapp-admin-server/internal/integration/walletclient"
)
type RobotProfile struct {
@ -39,6 +42,15 @@ func WithRobotProfileSource(source RobotProfileSource) Option {
}
}
// WithRobotAppearanceServices 注入机器人装扮和等级初始化依赖robot-service 只登记机器人事实,
// 因此创建账号后的资源发放和成长等级必须由 admin-server 编排到对应 owner service。
func WithRobotAppearanceServices(wallet walletclient.Client, activity activityclient.Client) Option {
return func(h *Handler) {
h.wallet = wallet
h.activity = activity
}
}
func (s *likeiRobotProfileSource) RandomRobotProfiles(ctx context.Context, count int) ([]RobotProfile, error) {
if s == nil || s.db == nil {
return nil, fmt.Errorf("likei robot profile source is not configured")

View File

@ -8,10 +8,14 @@ import (
"strings"
"testing"
"hyapp-admin-server/internal/integration/activityclient"
"hyapp-admin-server/internal/integration/gameclient"
"hyapp-admin-server/internal/integration/userclient"
"hyapp-admin-server/internal/integration/walletclient"
"hyapp-admin-server/internal/middleware"
activityv1 "hyapp.local/api/proto/activity/v1"
gamev1 "hyapp.local/api/proto/game/v1"
walletv1 "hyapp.local/api/proto/wallet/v1"
"github.com/gin-gonic/gin"
)
@ -59,6 +63,51 @@ func (c *fakeRobotGameClient) RegisterDiceRobots(_ context.Context, req *gamev1.
return &gamev1.RegisterDiceRobotsResponse{Robots: robots}, nil
}
type fakeRobotWalletClient struct {
walletclient.Client
grants []string
equips []int64
}
func (c *fakeRobotWalletClient) ListResources(_ context.Context, req *walletv1.ListResourcesRequest) (*walletv1.ListResourcesResponse, error) {
switch req.GetResourceType() {
case "avatar_frame":
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{{ResourceId: 101, ResourceType: "avatar_frame", Status: "active", ManagerGrantEnabled: true}}}, nil
case "vehicle":
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{{ResourceId: 201, ResourceType: "vehicle", Status: "active", ManagerGrantEnabled: true}}}, nil
case "badge":
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{
{ResourceId: 301, ResourceType: "badge", Status: "active", ManagerGrantEnabled: true, MetadataJson: `{"badge_form":"strip"}`},
{ResourceId: 302, ResourceType: "badge", Status: "active", ManagerGrantEnabled: true, MetadataJson: `{"badge_form":"tile"}`},
}}, nil
default:
return &walletv1.ListResourcesResponse{}, nil
}
}
func (c *fakeRobotWalletClient) GrantResource(_ context.Context, req *walletv1.GrantResourceRequest) (*walletv1.ResourceGrantResponse, error) {
c.grants = append(c.grants, req.GetCommandId())
return &walletv1.ResourceGrantResponse{Grant: &walletv1.ResourceGrant{Items: []*walletv1.ResourceGrantItem{{
ResourceId: req.GetResourceId(),
EntitlementId: "entitlement",
}}}}, nil
}
func (c *fakeRobotWalletClient) EquipUserResource(_ context.Context, req *walletv1.EquipUserResourceRequest) (*walletv1.EquipUserResourceResponse, error) {
c.equips = append(c.equips, req.GetResourceId())
return &walletv1.EquipUserResourceResponse{}, nil
}
type fakeRobotActivityClient struct {
activityclient.Client
levels []*activityv1.SetUserLevelRequest
}
func (c *fakeRobotActivityClient) SetUserLevel(_ context.Context, req *activityv1.SetUserLevelRequest) (*activityv1.SetUserLevelResponse, error) {
c.levels = append(c.levels, req)
return &activityv1.SetUserLevelResponse{Status: "consumed", Track: req.GetTrack(), NewLevel: req.GetLevel()}, nil
}
func TestGenerateDiceRobotsUsesLikeiProfiles(t *testing.T) {
gin.SetMode(gin.TestMode)
profiles := &fakeRobotProfileSource{profiles: []RobotProfile{
@ -67,7 +116,9 @@ func TestGenerateDiceRobotsUsesLikeiProfiles(t *testing.T) {
}}
users := &fakeRobotUserClient{}
games := &fakeRobotGameClient{}
handler := New(games, users, nil, WithRobotProfileSource(profiles))
wallets := &fakeRobotWalletClient{}
activities := &fakeRobotActivityClient{}
handler := New(games, users, nil, WithRobotProfileSource(profiles), WithRobotAppearanceServices(wallets, activities))
recorder := httptest.NewRecorder()
c, _ := gin.CreateTestContext(recorder)
@ -104,13 +155,21 @@ func TestGenerateDiceRobotsUsesLikeiProfiles(t *testing.T) {
if len(games.registered) != 2 || games.registered[0] != 9001 || games.registered[1] != 9002 {
t.Fatalf("registered user ids = %#v", games.registered)
}
if len(wallets.grants) != 8 || len(wallets.equips) != 4 || len(activities.levels) != 4 {
t.Fatalf("robot appearance init mismatch: grants=%d equips=%d levels=%d", len(wallets.grants), len(wallets.equips), len(activities.levels))
}
for _, level := range activities.levels {
if level.GetLevel() < robotMinDisplayLevel || level.GetLevel() > robotMaxDisplayLevel {
t.Fatalf("robot level out of range: %+v", level)
}
}
}
func TestGenerateDiceRobotsFallsBackToRandomProfilesWhenLikeiMissing(t *testing.T) {
gin.SetMode(gin.TestMode)
users := &fakeRobotUserClient{}
games := &fakeRobotGameClient{}
handler := New(games, users, nil)
handler := New(games, users, nil, WithRobotAppearanceServices(&fakeRobotWalletClient{}, &fakeRobotActivityClient{}))
recorder := httptest.NewRecorder()
c, _ := gin.CreateTestContext(recorder)

View File

@ -232,6 +232,13 @@ func (h *Handler) GenerateDiceRobots(c *gin.Context) {
}
userIDs := make([]int64, 0, req.Count)
requestID := middleware.CurrentRequestID(c)
meta := requestMeta(c)
appCode := meta.GetAppCode()
if appCode == "" {
appCode = "lalu"
meta.AppCode = appCode
}
actorUserID := int64(middleware.CurrentUserID(c))
accountLanguage := robotAccountLanguage(req.NicknameLanguage)
for index := int32(0); index < req.Count; index++ {
profile := profiles[index]
@ -262,10 +269,14 @@ func (h *Handler) GenerateDiceRobots(c *gin.Context) {
response.BadRequest(c, "创建机器人用户失败: "+err.Error())
return
}
if err := h.initializeGeneratedRobotAppearance(c.Request.Context(), requestID, appCode, actorUserID, created.UserID); err != nil {
response.BadRequest(c, "初始化机器人装扮失败: "+err.Error())
return
}
userIDs = append(userIDs, created.UserID)
}
resp, err := h.game.RegisterDiceRobots(c.Request.Context(), &gamev1.RegisterDiceRobotsRequest{
Meta: requestMeta(c),
Meta: meta,
GameId: strings.TrimSpace(firstQuery(c, "gameId", "game_id")),
UserIds: userIDs,
})

View File

@ -3,6 +3,7 @@ package roomadmin
import (
"database/sql"
"errors"
"log/slog"
"strconv"
"strings"
@ -10,6 +11,7 @@ import (
"hyapp-admin-server/internal/integration/roomclient"
"hyapp-admin-server/internal/middleware"
"hyapp-admin-server/internal/modules/shared"
"hyapp-admin-server/internal/repository"
"hyapp-admin-server/internal/response"
"github.com/gin-gonic/gin"
@ -20,8 +22,8 @@ type Handler struct {
audit shared.OperationLogger
}
func New(userDB *sql.DB, roomClient roomclient.Client, robotClient robotclient.Client, audit shared.OperationLogger) *Handler {
return &Handler{service: NewService(userDB, roomClient, robotClient), audit: audit}
func New(userDB *sql.DB, store *repository.Store, roomClient roomclient.Client, robotClient robotclient.Client, audit shared.OperationLogger) *Handler {
return &Handler{service: NewService(userDB, store, roomClient, robotClient), audit: audit}
}
func (h *Handler) ListRooms(c *gin.Context) {
@ -83,6 +85,10 @@ func (h *Handler) ListRobotRooms(c *gin.Context) {
query := parseRobotRoomListQuery(c)
items, total, err := h.service.ListRobotRooms(c.Request.Context(), query)
if err != nil {
slog.Error("roomadmin_list_robot_rooms_failed",
"request_id", middleware.CurrentRequestID(c),
"error", err.Error(),
)
response.ServerError(c, "获取机器人房间列表失败")
return
}
@ -121,6 +127,30 @@ func (h *Handler) StopRobotRoom(c *gin.Context) {
h.setRobotRoomStatus(c, "stopped", "stop-robot-room", "停止机器人房间失败")
}
func (h *Handler) GetHumanRoomRobotConfig(c *gin.Context) {
config, err := h.service.GetHumanRoomRobotConfig(c.Request.Context())
if err != nil {
response.ServerError(c, "获取真人房间机器人配置失败")
return
}
response.OK(c, config)
}
func (h *Handler) UpdateHumanRoomRobotConfig(c *gin.Context) {
var req updateHumanRoomRobotConfigRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "真人房间机器人配置参数不正确")
return
}
config, err := h.service.UpdateHumanRoomRobotConfig(c.Request.Context(), req, shared.ActorFromContext(c))
if err != nil {
writeMutationError(c, err, "更新真人房间机器人配置失败")
return
}
writeRoomAuditLog(c, h.audit, "update-human-room-robot-config", "room_human_robot_configs", "human-room-robot", "success", "update human room robot config")
response.OK(c, config)
}
func (h *Handler) GetRoomConfig(c *gin.Context) {
config, err := h.service.GetRoomConfig(c.Request.Context())
if err != nil {
@ -130,6 +160,30 @@ func (h *Handler) GetRoomConfig(c *gin.Context) {
response.OK(c, config)
}
func (h *Handler) GetRoomWhitelistConfig(c *gin.Context) {
config, err := h.service.GetRoomWhitelistConfig(c.Request.Context())
if err != nil {
response.ServerError(c, "获取房间白名单失败")
return
}
response.OK(c, config)
}
func (h *Handler) UpdateRoomWhitelistConfig(c *gin.Context) {
var req updateRoomWhitelistRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "房间白名单参数不正确")
return
}
config, err := h.service.UpdateRoomWhitelistConfig(c.Request.Context(), req)
if err != nil {
writeMutationError(c, err, "更新房间白名单失败")
return
}
writeRoomAuditLog(c, h.audit, "update-room-whitelist", "admin_app_configs", "room-region-whitelist", "success", "update room whitelist")
response.OK(c, config)
}
func (h *Handler) UpdateRoomConfig(c *gin.Context) {
var req updateRoomConfigRequest
if err := c.ShouldBindJSON(&req); err != nil {

View File

@ -40,6 +40,8 @@ type createRobotRoomRequest struct {
RoomName string `json:"roomName"`
RoomAvatar string `json:"roomAvatar"`
VisibleRegionID int64 `json:"visibleRegionId"`
OwnerCountryCode string `json:"-"`
SeatCount int32 `json:"seatCount"`
GiftIDs []string `json:"giftIds"`
LuckyGiftIDs []string `json:"luckyGiftIds"`
NormalGiftIntervalMS int64 `json:"normalGiftIntervalMs"`
@ -47,6 +49,11 @@ type createRobotRoomRequest struct {
LuckyComboMax int64 `json:"luckyComboMax"`
LuckyPauseMinMS int64 `json:"luckyPauseMinMs"`
LuckyPauseMaxMS int64 `json:"luckyPauseMaxMs"`
RobotStayMinMS int64 `json:"robotStayMinMs"`
RobotStayMaxMS int64 `json:"robotStayMaxMs"`
RobotReplaceMinMS int64 `json:"robotReplaceMinMs"`
RobotReplaceMaxMS int64 `json:"robotReplaceMaxMs"`
MaxGiftSenders int64 `json:"maxGiftSenders"`
}
type flexibleJSONInt64 int64
@ -126,3 +133,52 @@ type updateRoomConfigRequest struct {
AllowedSeatCounts []int32 `json:"allowedSeatCounts"`
DefaultSeatCount int32 `json:"defaultSeatCount"`
}
type updateRoomWhitelistRequest struct {
UserIDs flexibleJSONInt64StringSlice `json:"userIds"`
}
type updateHumanRoomRobotConfigRequest struct {
Enabled bool `json:"enabled"`
CandidateRoomMaxOnline int32 `json:"candidateRoomMaxOnline"`
RoomFullStopOnline int32 `json:"roomFullStopOnline"`
RoomTargetMinOnline int32 `json:"roomTargetMinOnline"`
RoomTargetMaxOnline int32 `json:"roomTargetMaxOnline"`
RobotStayMinMS int64 `json:"robotStayMinMs"`
RobotStayMaxMS int64 `json:"robotStayMaxMs"`
RobotReplaceMinMS int64 `json:"robotReplaceMinMs"`
RobotReplaceMaxMS int64 `json:"robotReplaceMaxMs"`
NormalGiftIntervalMS int64 `json:"normalGiftIntervalMs"`
NormalGiftIntervalMinMS int64 `json:"normalGiftIntervalMinMs"`
NormalGiftIntervalMaxMS int64 `json:"normalGiftIntervalMaxMs"`
GiftIDs []string `json:"giftIds"`
LuckyGiftIDs []string `json:"luckyGiftIds"`
SuperLuckyGiftIDs []string `json:"superLuckyGiftIds"`
LuckyComboMin int64 `json:"luckyComboMin"`
LuckyComboMax int64 `json:"luckyComboMax"`
LuckyPauseMinMS int64 `json:"luckyPauseMinMs"`
LuckyPauseMaxMS int64 `json:"luckyPauseMaxMs"`
MaxGiftSenders int64 `json:"maxGiftSenders"`
}
type flexibleJSONInt64StringSlice []string
func (values *flexibleJSONInt64StringSlice) UnmarshalJSON(data []byte) error {
// 房间白名单 user_id 是 int64 标识API 合约统一按字符串输出;这里兼容旧脚本传数字但拒绝小数。
var raw []json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
out := make([]string, 0, len(raw))
for _, item := range raw {
value, err := parseFlexibleJSONInt64(item)
if err != nil {
return err
}
if value > 0 {
out = append(out, strconv.FormatInt(value, 10))
}
}
*values = out
return nil
}

View File

@ -24,6 +24,8 @@ type RobotRoom struct {
Owner RoomOwner `json:"owner"`
RobotUserIDs []string `json:"robotUserIds"`
Robots []RoomOwner `json:"robots"`
ActiveRobotCount int32 `json:"activeRobotCount"`
SeatCount int32 `json:"seatCount"`
GiftRule RobotGiftRule `json:"giftRule"`
CreatedByAdminID uint64 `json:"createdByAdminId"`
CreatedAtMS int64 `json:"createdAtMs"`
@ -38,6 +40,11 @@ type RobotGiftRule struct {
LuckyComboMax int64 `json:"luckyComboMax"`
LuckyPauseMinMS int64 `json:"luckyPauseMinMs"`
LuckyPauseMaxMS int64 `json:"luckyPauseMaxMs"`
RobotStayMinMS int64 `json:"robotStayMinMs"`
RobotStayMaxMS int64 `json:"robotStayMaxMs"`
RobotReplaceMinMS int64 `json:"robotReplaceMinMs"`
RobotReplaceMaxMS int64 `json:"robotReplaceMaxMs"`
MaxGiftSenders int64 `json:"maxGiftSenders"`
}
type AvailableRoomRobot struct {
@ -49,6 +56,33 @@ type AvailableRoomRobot struct {
User RoomOwner `json:"user"`
}
type HumanRoomRobotConfig struct {
AppCode string `json:"appCode"`
Enabled bool `json:"enabled"`
CandidateRoomMaxOnline int32 `json:"candidateRoomMaxOnline"`
RoomFullStopOnline int32 `json:"roomFullStopOnline"`
RoomTargetMinOnline int32 `json:"roomTargetMinOnline"`
RoomTargetMaxOnline int32 `json:"roomTargetMaxOnline"`
RobotStayMinMS int64 `json:"robotStayMinMs"`
RobotStayMaxMS int64 `json:"robotStayMaxMs"`
RobotReplaceMinMS int64 `json:"robotReplaceMinMs"`
RobotReplaceMaxMS int64 `json:"robotReplaceMaxMs"`
NormalGiftIntervalMS int64 `json:"normalGiftIntervalMs"`
NormalGiftIntervalMinMS int64 `json:"normalGiftIntervalMinMs"`
NormalGiftIntervalMaxMS int64 `json:"normalGiftIntervalMaxMs"`
GiftIDs []string `json:"giftIds"`
LuckyGiftIDs []string `json:"luckyGiftIds"`
SuperLuckyGiftIDs []string `json:"superLuckyGiftIds"`
LuckyComboMin int64 `json:"luckyComboMin"`
LuckyComboMax int64 `json:"luckyComboMax"`
LuckyPauseMinMS int64 `json:"luckyPauseMinMs"`
LuckyPauseMaxMS int64 `json:"luckyPauseMaxMs"`
MaxGiftSenders int64 `json:"maxGiftSenders"`
UpdatedByAdminID uint64 `json:"updatedByAdminId"`
CreatedAtMS int64 `json:"createdAtMs"`
UpdatedAtMS int64 `json:"updatedAtMs"`
}
func (s *Service) ListRobotRooms(ctx context.Context, query robotRoomListQuery) ([]RobotRoom, int64, error) {
if s.roomClient == nil {
return nil, 0, fmt.Errorf("room service client is not configured")
@ -113,6 +147,53 @@ func (s *Service) ListAvailableRoomRobots(ctx context.Context) ([]AvailableRoomR
return availableRoomRobotsFromGamePool(result.Robots, available.AvailableUserIDs, owners), nil
}
func (s *Service) GetHumanRoomRobotConfig(ctx context.Context) (HumanRoomRobotConfig, error) {
if s.roomClient == nil {
return HumanRoomRobotConfig{}, fmt.Errorf("room service client is not configured")
}
config, err := s.roomClient.GetHumanRoomRobotConfig(ctx)
if err != nil {
return HumanRoomRobotConfig{}, err
}
return s.humanRoomRobotConfigFromClient(ctx, config)
}
func (s *Service) UpdateHumanRoomRobotConfig(ctx context.Context, req updateHumanRoomRobotConfigRequest, actor shared.Actor) (HumanRoomRobotConfig, error) {
if s.roomClient == nil {
return HumanRoomRobotConfig{}, fmt.Errorf("room service client is not configured")
}
config := roomclient.HumanRoomRobotConfig{
Enabled: req.Enabled,
CandidateRoomMaxOnline: req.CandidateRoomMaxOnline,
RoomFullStopOnline: req.RoomFullStopOnline,
RoomTargetMinOnline: req.RoomTargetMinOnline,
RoomTargetMaxOnline: req.RoomTargetMaxOnline,
RobotStayMinMS: req.RobotStayMinMS,
RobotStayMaxMS: req.RobotStayMaxMS,
RobotReplaceMinMS: req.RobotReplaceMinMS,
RobotReplaceMaxMS: req.RobotReplaceMaxMS,
NormalGiftIntervalMS: req.NormalGiftIntervalMS,
NormalGiftIntervalMinMS: req.NormalGiftIntervalMinMS,
NormalGiftIntervalMaxMS: req.NormalGiftIntervalMaxMS,
GiftIDs: normalizeStringList(req.GiftIDs),
LuckyGiftIDs: normalizeStringList(req.LuckyGiftIDs),
SuperLuckyGiftIDs: normalizeStringList(req.SuperLuckyGiftIDs),
LuckyComboMin: req.LuckyComboMin,
LuckyComboMax: req.LuckyComboMax,
LuckyPauseMinMS: req.LuckyPauseMinMS,
LuckyPauseMaxMS: req.LuckyPauseMaxMS,
MaxGiftSenders: req.MaxGiftSenders,
}
saved, err := s.roomClient.UpdateHumanRoomRobotConfig(ctx, roomclient.UpdateHumanRoomRobotConfigRequest{
Config: config,
AdminID: uint64(actor.UserID),
})
if err != nil {
return HumanRoomRobotConfig{}, mapRoomClientError(err)
}
return s.humanRoomRobotConfigFromClient(ctx, saved)
}
func availableRoomRobotsFromGamePool(robots []robotclient.Robot, availableUserIDs []int64, owners map[int64]RoomOwner) []AvailableRoomRobot {
allowed := make(map[int64]bool, len(availableUserIDs))
for _, userID := range availableUserIDs {
@ -135,6 +216,50 @@ func availableRoomRobotsFromGamePool(robots []robotclient.Robot, availableUserID
return items
}
func normalizeStringList(values []string) []string {
seen := make(map[string]bool, len(values))
out := make([]string, 0, len(values))
for _, value := range values {
value = strings.TrimSpace(value)
if value == "" || seen[value] {
continue
}
seen[value] = true
out = append(out, value)
}
return out
}
func (s *Service) humanRoomRobotConfigFromClient(_ context.Context, config roomclient.HumanRoomRobotConfig) (HumanRoomRobotConfig, error) {
out := HumanRoomRobotConfig{
AppCode: config.AppCode,
Enabled: config.Enabled,
CandidateRoomMaxOnline: config.CandidateRoomMaxOnline,
RoomFullStopOnline: config.RoomFullStopOnline,
RoomTargetMinOnline: config.RoomTargetMinOnline,
RoomTargetMaxOnline: config.RoomTargetMaxOnline,
RobotStayMinMS: config.RobotStayMinMS,
RobotStayMaxMS: config.RobotStayMaxMS,
RobotReplaceMinMS: config.RobotReplaceMinMS,
RobotReplaceMaxMS: config.RobotReplaceMaxMS,
NormalGiftIntervalMS: config.NormalGiftIntervalMS,
NormalGiftIntervalMinMS: config.NormalGiftIntervalMinMS,
NormalGiftIntervalMaxMS: config.NormalGiftIntervalMaxMS,
GiftIDs: append([]string(nil), config.GiftIDs...),
LuckyGiftIDs: append([]string(nil), config.LuckyGiftIDs...),
SuperLuckyGiftIDs: append([]string(nil), config.SuperLuckyGiftIDs...),
LuckyComboMin: config.LuckyComboMin,
LuckyComboMax: config.LuckyComboMax,
LuckyPauseMinMS: config.LuckyPauseMinMS,
LuckyPauseMaxMS: config.LuckyPauseMaxMS,
MaxGiftSenders: config.MaxGiftSenders,
UpdatedByAdminID: config.UpdatedByAdminID,
CreatedAtMS: config.CreatedAtMS,
UpdatedAtMS: config.UpdatedAtMS,
}
return out, nil
}
func (s *Service) CreateRobotRoom(ctx context.Context, req createRobotRoomRequest, actor shared.Actor) (RobotRoom, error) {
if s.roomClient == nil {
return RobotRoom{}, fmt.Errorf("room service client is not configured")
@ -155,6 +280,8 @@ func (s *Service) CreateRobotRoom(ctx context.Context, req createRobotRoomReques
RoomName: req.RoomName,
RoomAvatar: req.RoomAvatar,
VisibleRegionID: req.VisibleRegionID,
OwnerCountryCode: req.OwnerCountryCode,
SeatCount: req.SeatCount,
GiftRule: roomclient.RobotRoomGiftRule{
GiftIDs: req.GiftIDs,
LuckyGiftIDs: req.LuckyGiftIDs,
@ -163,6 +290,11 @@ func (s *Service) CreateRobotRoom(ctx context.Context, req createRobotRoomReques
LuckyComboMax: req.LuckyComboMax,
LuckyPauseMinMS: req.LuckyPauseMinMS,
LuckyPauseMaxMS: req.LuckyPauseMaxMS,
RobotStayMinMS: req.RobotStayMinMS,
RobotStayMaxMS: req.RobotStayMaxMS,
RobotReplaceMinMS: req.RobotReplaceMinMS,
RobotReplaceMaxMS: req.RobotReplaceMaxMS,
MaxGiftSenders: req.MaxGiftSenders,
},
AdminID: uint64(actor.UserID),
})
@ -189,13 +321,19 @@ func (s *Service) applyOwnerProfileToRobotRoomRequest(ctx context.Context, req *
if !ok {
return fmt.Errorf("%w: 房主机器人资料不存在", ErrInvalidArgument)
}
return applyOwnerProfileToRobotRoomRequest(req, owner)
}
func applyOwnerProfileToRobotRoomRequest(req *createRobotRoomRequest, owner RoomOwner) error {
roomName, roomAvatar, err := robotRoomProfileFromOwner(owner)
if err != nil {
return err
}
// 机器人房间对外展示必须跟随房主机器人资料,避免后台表单或脚本传入的自定义值让房间卡片和房主身份不一致。
// 机器人房间对外展示和区域归属必须跟随房主机器人资料,避免后台表单或脚本传入的自定义值让房间卡片、区域桶和国家筛选不一致。
req.RoomName = roomName
req.RoomAvatar = roomAvatar
req.VisibleRegionID = owner.VisibleRegionID
req.OwnerCountryCode = strings.ToUpper(strings.TrimSpace(owner.CountryCode))
return nil
}
@ -243,6 +381,12 @@ func normalizeCreateRobotRoomRequest(req createRobotRoomRequest) (createRobotRoo
if req.MinRobotCount <= 0 || req.MaxRobotCount < req.MinRobotCount {
return req, fmt.Errorf("%w: 机器人数量范围不正确", ErrInvalidArgument)
}
if req.SeatCount <= 0 {
req.SeatCount = 10
}
if !validRobotRoomSeatCount(req.SeatCount) {
return req, fmt.Errorf("%w: 麦位数不正确", ErrInvalidArgument)
}
candidateIDs := normalizeRobotRoomCandidateIDs([]int64(req.CandidateRobotUserIDs), ownerID)
if len(candidateIDs) == 0 {
return req, fmt.Errorf("%w: 请选择候选机器人", ErrInvalidArgument)
@ -262,10 +406,28 @@ func normalizeCreateRobotRoomRequest(req createRobotRoomRequest) (createRobotRoo
if req.LuckyPauseMinMS <= 0 || req.LuckyPauseMaxMS < req.LuckyPauseMinMS {
return req, fmt.Errorf("%w: 幸运礼物间隔范围不正确", ErrInvalidArgument)
}
if req.RobotStayMinMS < 0 || req.RobotStayMaxMS < req.RobotStayMinMS {
return req, fmt.Errorf("%w: 机器人停留时间范围不正确", ErrInvalidArgument)
}
if req.RobotReplaceMinMS < 0 || req.RobotReplaceMaxMS < req.RobotReplaceMinMS {
return req, fmt.Errorf("%w: 机器人补位时间范围不正确", ErrInvalidArgument)
}
if req.MaxGiftSenders < 0 {
return req, fmt.Errorf("%w: 同时送礼机器人数量不正确", ErrInvalidArgument)
}
req.CandidateRobotUserIDs = flexibleJSONInt64Slice(candidateIDs)
return req, nil
}
func validRobotRoomSeatCount(seatCount int32) bool {
switch seatCount {
case 10, 15, 20:
return true
default:
return false
}
}
func normalizeRobotRoomCandidateIDs(values []int64, ownerID int64) []int64 {
seen := make(map[int64]bool, len(values))
out := make([]int64, 0, len(values))
@ -303,6 +465,8 @@ func robotRoomFromClient(item roomclient.RobotRoom) RobotRoom {
Status: item.Status,
OwnerRobotUserID: strconv.FormatInt(item.OwnerRobotUserID, 10),
RobotUserIDs: robotUserIDs,
ActiveRobotCount: item.ActiveRobotCount,
SeatCount: item.SeatCount,
GiftRule: RobotGiftRule{
GiftIDs: item.GiftRule.GiftIDs,
LuckyGiftIDs: item.GiftRule.LuckyGiftIDs,
@ -311,6 +475,11 @@ func robotRoomFromClient(item roomclient.RobotRoom) RobotRoom {
LuckyComboMax: item.GiftRule.LuckyComboMax,
LuckyPauseMinMS: item.GiftRule.LuckyPauseMinMS,
LuckyPauseMaxMS: item.GiftRule.LuckyPauseMaxMS,
RobotStayMinMS: item.GiftRule.RobotStayMinMS,
RobotStayMaxMS: item.GiftRule.RobotStayMaxMS,
RobotReplaceMinMS: item.GiftRule.RobotReplaceMinMS,
RobotReplaceMaxMS: item.GiftRule.RobotReplaceMaxMS,
MaxGiftSenders: item.GiftRule.MaxGiftSenders,
},
CreatedByAdminID: item.CreatedByAdminID,
CreatedAtMS: item.CreatedAtMS,

View File

@ -17,11 +17,15 @@ func RegisterRoutes(protected *gin.RouterGroup, h *Handler) {
protected.DELETE("/admin/rooms/pins/:pin_id", middleware.RequirePermission("room-pin:cancel"), h.CancelRoomPin)
protected.GET("/admin/rooms/robot-rooms", middleware.RequirePermission("room-robot:view"), h.ListRobotRooms)
protected.GET("/admin/rooms/robot-rooms/available-robots", middleware.RequirePermission("room-robot:view"), h.ListAvailableRoomRobots)
protected.GET("/admin/rooms/robot-rooms/human-config", middleware.RequirePermission("room-robot:view"), h.GetHumanRoomRobotConfig)
protected.PUT("/admin/rooms/robot-rooms/human-config", middleware.RequirePermission("room-robot:update"), h.UpdateHumanRoomRobotConfig)
protected.POST("/admin/rooms/robot-rooms", middleware.RequirePermission("room-robot:create"), h.CreateRobotRoom)
protected.POST("/admin/rooms/robot-rooms/:room_id/start", middleware.RequirePermission("room-robot:update"), h.StartRobotRoom)
protected.POST("/admin/rooms/robot-rooms/:room_id/stop", middleware.RequirePermission("room-robot:update"), h.StopRobotRoom)
protected.GET("/admin/rooms/config", middleware.RequirePermission("room-config:view"), h.GetRoomConfig)
protected.PUT("/admin/rooms/config", middleware.RequirePermission("room-config:update"), h.UpdateRoomConfig)
protected.GET("/admin/rooms/whitelist", middleware.RequirePermission("room-whitelist:view"), h.GetRoomWhitelistConfig)
protected.PUT("/admin/rooms/whitelist", middleware.RequirePermission("room-whitelist:update"), h.UpdateRoomWhitelistConfig)
protected.PATCH("/admin/rooms/:room_id", middleware.RequirePermission("room:update"), h.UpdateRoom)
protected.DELETE("/admin/rooms/:room_id", middleware.RequirePermission("room:delete"), h.DeleteRoom)
}

View File

@ -15,6 +15,7 @@ import (
"hyapp-admin-server/internal/integration/robotclient"
"hyapp-admin-server/internal/integration/roomclient"
"hyapp-admin-server/internal/modules/shared"
"hyapp-admin-server/internal/repository"
)
var (
@ -24,15 +25,18 @@ var (
type Service struct {
userDB *sql.DB
store *repository.Store
roomClient roomclient.Client
robotClient robotclient.Client
}
type RoomOwner struct {
Avatar string `json:"avatar"`
DisplayUserID string `json:"displayUserId"`
UserID string `json:"userId"`
Username string `json:"username"`
Avatar string `json:"avatar"`
CountryCode string `json:"countryCode,omitempty"`
DisplayUserID string `json:"displayUserId"`
UserID string `json:"userId"`
Username string `json:"username"`
VisibleRegionID int64 `json:"visibleRegionId,omitempty"`
}
type Room struct {
@ -60,8 +64,8 @@ type Room struct {
VisibleRegionID int64 `json:"visibleRegionId"`
}
func NewService(userDB *sql.DB, roomClient roomclient.Client, robotClient robotclient.Client) *Service {
return &Service{userDB: userDB, roomClient: roomClient, robotClient: robotClient}
func NewService(userDB *sql.DB, store *repository.Store, roomClient roomclient.Client, robotClient robotclient.Client) *Service {
return &Service{userDB: userDB, store: store, roomClient: roomClient, robotClient: robotClient}
}
func (s *Service) ListRooms(ctx context.Context, query listQuery) ([]Room, int64, error) {
@ -463,7 +467,9 @@ func (s *Service) queryRoomOwners(ctx context.Context, ownerIDs []int64) (map[in
SELECT user_id,
current_display_user_id,
COALESCE(username, ''),
COALESCE(avatar, '')
COALESCE(avatar, ''),
COALESCE(country, ''),
COALESCE(region_id, 0)
FROM users
WHERE app_code = ? AND user_id IN (`+placeholders(len(ownerIDs))+`)
`, args...)
@ -475,7 +481,7 @@ func (s *Service) queryRoomOwners(ctx context.Context, ownerIDs []int64) (map[in
for rows.Next() {
var userID int64
var owner RoomOwner
if err := rows.Scan(&userID, &owner.DisplayUserID, &owner.Username, &owner.Avatar); err != nil {
if err := rows.Scan(&userID, &owner.DisplayUserID, &owner.Username, &owner.Avatar, &owner.CountryCode, &owner.VisibleRegionID); err != nil {
return nil, err
}
owner.UserID = strconv.FormatInt(userID, 10)

View File

@ -3,8 +3,13 @@ package roomadmin
import (
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gin-gonic/gin"
"hyapp-admin-server/internal/integration/robotclient"
)
@ -78,6 +83,30 @@ func TestRobotRoomProfileFromOwnerRequiresNameAndAvatar(t *testing.T) {
}
}
func TestApplyOwnerProfileToRobotRoomRequestFollowsOwnerRegionAndCountry(t *testing.T) {
req := createRobotRoomRequest{
RoomName: "manual name",
RoomAvatar: "https://cdn.example.com/manual.png",
VisibleRegionID: 999,
OwnerCountryCode: "XX",
}
err := applyOwnerProfileToRobotRoomRequest(&req, RoomOwner{
Username: " Robot Owner ",
Avatar: " https://cdn.example.com/owner.png ",
CountryCode: " ae ",
VisibleRegionID: 686,
})
if err != nil {
t.Fatalf("apply owner profile failed: %v", err)
}
if req.RoomName != "Robot Owner" || req.RoomAvatar != "https://cdn.example.com/owner.png" {
t.Fatalf("owner display profile mismatch: name=%q avatar=%q", req.RoomName, req.RoomAvatar)
}
if req.VisibleRegionID != 686 || req.OwnerCountryCode != "AE" {
t.Fatalf("owner region or country mismatch: region=%d country=%q", req.VisibleRegionID, req.OwnerCountryCode)
}
}
func TestCreateRobotRoomRequestAcceptsStringInt64IDs(t *testing.T) {
var req createRobotRoomRequest
if err := json.Unmarshal([]byte(`{
@ -108,6 +137,61 @@ func TestCreateRobotRoomRequestAcceptsStringInt64IDs(t *testing.T) {
}
}
func TestCreateRobotRoomRequestBindsStringInt64IDsFromHTTP(t *testing.T) {
gin.SetMode(gin.TestMode)
body := `{
"ownerRobotUserId":"325379237278126080",
"candidateRobotUserIds":["325455441691676672"],
"minRobotCount":2,
"maxRobotCount":8,
"giftIds":["84"],
"luckyGiftIds":["28"],
"normalGiftIntervalMs":10000,
"luckyComboMin":100,
"luckyComboMax":10000,
"luckyPauseMinMs":5000,
"luckyPauseMaxMs":20000
}`
req := httptest.NewRequest(http.MethodPost, "/admin/rooms/robot-rooms", strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(rec)
ctx.Request = req
var payload createRobotRoomRequest
if err := ctx.ShouldBindJSON(&payload); err != nil {
t.Fatalf("gin binding should accept string int64 ids: %v", err)
}
if got := int64(payload.OwnerRobotUserID); got != 325379237278126080 {
t.Fatalf("owner id mismatch: got %d", got)
}
if got := []int64(payload.CandidateRobotUserIDs); len(got) != 1 || got[0] != 325455441691676672 {
t.Fatalf("candidate ids mismatch: %+v", got)
}
}
func TestNormalizeRoomWhitelistUserIDsKeepsStringInt64Order(t *testing.T) {
got, err := normalizeRoomWhitelistUserIDs([]string{"325379237278126080", "1001", "1001"})
if err != nil {
t.Fatalf("normalize room whitelist failed: %v", err)
}
want := []string{"1001", "325379237278126080"}
if len(got) != len(want) {
t.Fatalf("whitelist length mismatch: got %+v want %+v", got, want)
}
for index := range want {
if got[index] != want[index] {
t.Fatalf("whitelist id %d mismatch: got %+v want %+v", index, got, want)
}
}
}
func TestNormalizeRoomWhitelistUserIDsRejectsInvalidID(t *testing.T) {
if _, err := normalizeRoomWhitelistUserIDs([]string{"1.2"}); !errors.Is(err, ErrInvalidArgument) {
t.Fatalf("invalid id should return ErrInvalidArgument, got %v", err)
}
}
func TestAvailableRoomRobotsFromGamePoolKeepsOnlyRoomAvailableUsers(t *testing.T) {
robots := []robotclient.Robot{
{UserID: 101, Status: "active", LastUsedAtMS: 1000, UsedCount: 2},

View File

@ -0,0 +1,112 @@
package roomadmin
import (
"context"
"encoding/json"
"errors"
"fmt"
"slices"
"strconv"
"strings"
"gorm.io/gorm"
"hyapp-admin-server/internal/appctx"
"hyapp-admin-server/internal/model"
)
const roomRegionWhitelistGroup = "room-region-whitelist"
type RoomWhitelistConfig struct {
UserIDs []string `json:"userIds"`
UpdatedAtMS int64 `json:"updatedAtMs"`
}
type roomRegionWhitelistValue struct {
UserIDs []string `json:"user_ids"`
}
// GetRoomWhitelistConfig 读取当前 app 的房间区域白名单;缺行时返回空集合,表示所有用户仍受区域限制。
func (s *Service) GetRoomWhitelistConfig(ctx context.Context) (RoomWhitelistConfig, error) {
if s.store == nil {
return RoomWhitelistConfig{}, fmt.Errorf("admin store is not configured")
}
item, err := s.store.GetAppConfig(roomRegionWhitelistGroup, appctx.FromContext(ctx))
if errors.Is(err, gorm.ErrRecordNotFound) {
return RoomWhitelistConfig{UserIDs: []string{}}, nil
}
if err != nil {
return RoomWhitelistConfig{}, err
}
userIDs, err := roomWhitelistIDsFromValue(item.Value)
if err != nil {
return RoomWhitelistConfig{}, err
}
return RoomWhitelistConfig{UserIDs: userIDs, UpdatedAtMS: item.UpdatedAtMS}, nil
}
// UpdateRoomWhitelistConfig 覆盖当前 app 的房间区域白名单gateway 会在最多五分钟内通过 Redis 缓存刷新结果。
func (s *Service) UpdateRoomWhitelistConfig(ctx context.Context, req updateRoomWhitelistRequest) (RoomWhitelistConfig, error) {
if s.store == nil {
return RoomWhitelistConfig{}, fmt.Errorf("admin store is not configured")
}
userIDs, err := normalizeRoomWhitelistUserIDs(req.UserIDs)
if err != nil {
return RoomWhitelistConfig{}, err
}
payload, err := json.Marshal(roomRegionWhitelistValue{UserIDs: userIDs})
if err != nil {
return RoomWhitelistConfig{}, err
}
item := model.AppConfig{
Group: roomRegionWhitelistGroup,
Key: appctx.FromContext(ctx),
Value: string(payload),
Description: "房间区域白名单用户,命中后 App 房间列表不按用户 region_id 过滤",
}
if err := s.store.UpsertAppConfigs([]model.AppConfig{item}); err != nil {
return RoomWhitelistConfig{}, err
}
return s.GetRoomWhitelistConfig(ctx)
}
func roomWhitelistIDsFromValue(raw string) ([]string, error) {
raw = strings.TrimSpace(raw)
if raw == "" {
return []string{}, nil
}
var payload roomRegionWhitelistValue
if strings.HasPrefix(raw, "[") {
if err := json.Unmarshal([]byte(raw), &payload.UserIDs); err != nil {
return nil, err
}
} else if err := json.Unmarshal([]byte(raw), &payload); err != nil {
return nil, err
}
return normalizeRoomWhitelistUserIDs(payload.UserIDs)
}
func normalizeRoomWhitelistUserIDs(values []string) ([]string, error) {
seen := make(map[int64]struct{}, len(values))
out := make([]int64, 0, len(values))
for _, value := range values {
value = strings.TrimSpace(value)
if value == "" {
continue
}
id, err := strconv.ParseInt(value, 10, 64)
if err != nil || id <= 0 {
return nil, fmt.Errorf("%w: 用户 ID 不正确", ErrInvalidArgument)
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
out = append(out, id)
}
slices.Sort(out)
result := make([]string, 0, len(out))
for _, id := range out {
result = append(result, strconv.FormatInt(id, 10))
}
return result, nil
}

View File

@ -36,6 +36,8 @@ var defaultPermissions = []model.Permission{
{Name: "房间置顶取消", Code: "room-pin:cancel", Kind: "button"},
{Name: "房间配置查看", Code: "room-config:view", Kind: "menu"},
{Name: "房间配置更新", Code: "room-config:update", Kind: "button"},
{Name: "房间白名单查看", Code: "room-whitelist:view", Kind: "menu"},
{Name: "房间白名单更新", Code: "room-whitelist:update", Kind: "button"},
{Name: "机器人房间查看", Code: "room-robot:view", Kind: "menu"},
{Name: "机器人房间创建", Code: "room-robot:create", Kind: "button"},
{Name: "机器人房间更新", Code: "room-robot:update", Kind: "button"},
@ -263,7 +265,8 @@ func (s *Store) seedMenus() error {
{ParentID: &roomsID, Title: "房间列表", Code: "room-list", Path: "/rooms", Icon: "room", PermissionCode: "room:view", Sort: 65, Visible: true},
{ParentID: &roomsID, Title: "房间置顶", Code: "room-pins", Path: "/rooms/pins", Icon: "push_pin", PermissionCode: "room-pin:view", Sort: 66, Visible: true},
{ParentID: &roomsID, Title: "房间配置", Code: "room-config", Path: "/rooms/config", Icon: "settings", PermissionCode: "room-config:view", Sort: 67, Visible: true},
{ParentID: &roomsID, Title: "机器人房间", Code: "room-robots", Path: "/rooms/robots", Icon: "team", PermissionCode: "room-robot:view", Sort: 68, Visible: true},
{ParentID: &roomsID, Title: "房间白名单", Code: "room-whitelist", Path: "/rooms/whitelist", Icon: "shield", PermissionCode: "room-whitelist:view", Sort: 68, Visible: true},
{ParentID: &roomsID, Title: "机器人房间", Code: "room-robots", Path: "/rooms/robots", Icon: "team", PermissionCode: "room-robot:view", Sort: 69, Visible: true},
{ParentID: &appConfigID, Title: "H5配置", Code: "app-config-h5", Path: "/app-config/h5", Icon: "settings", PermissionCode: "app-config:view", Sort: 66, Visible: true},
{ParentID: &appConfigID, Title: "BANNER配置", Code: "app-config-banners", Path: "/app-config/banners", Icon: "image", PermissionCode: "app-config:view", Sort: 67, Visible: true},
{ParentID: &appConfigID, Title: "开屏配置", Code: "app-config-splash-screens", Path: "/app-config/splash-screens", Icon: "image", PermissionCode: "app-config:view", Sort: 68, Visible: true},
@ -522,7 +525,7 @@ func defaultRolePermissionCodes(code string) []string {
"level-config:view", "level-config:update",
"pretty-id:view", "pretty-id:update", "pretty-id:generate", "pretty-id:grant",
"region-block:view", "region-block:update",
"room:view", "room:update", "room:delete", "room-pin:view", "room-pin:create", "room-pin:cancel", "room-config:view", "room-config:update", "room-robot:view", "room-robot:create", "room-robot:update",
"room:view", "room:update", "room:delete", "room-pin:view", "room-pin:create", "room-pin:cancel", "room-config:view", "room-config:update", "room-whitelist:view", "room-whitelist:update", "room-robot:view", "room-robot:create", "room-robot:update",
"app-config:view", "app-config:update",
"app-version:view", "app-version:create", "app-version:update", "app-version:delete",
"resource:view", "resource:create", "resource:update",
@ -554,7 +557,7 @@ func defaultRolePermissionCodes(code string) []string {
"upload:create",
}
case "auditor":
return []string{"overview:view", "log:view", "user:view", "app-user:view", "level-config:view", "pretty-id:view", "region-block:view", "room:view", "room-pin:view", "room-config:view", "room-robot:view", "app-config:view", "app-version:view", "resource:view", "resource-shop:view", "resource-group:view", "resource-grant:view", "gift:view", "emoji-pack:view", "host-agency-policy:view", "team-salary-policy:view", "host-salary-settlement:view", "coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "report:view", "gift-diamond:view", "full-server-notice:view", "lucky-gift:view", "payment-bill:view", "payment-third-party:view", "payment-product:view", "game:view", "daily-task:view", "achievement:view", "seven-day-checkin:view", "room-rocket:view", "red-packet:view", "cp-config:view", "vip-config:view", "weekly-star:view", "agency-opening:view", "role:view", "permission:view", "job:view"}
return []string{"overview:view", "log:view", "user:view", "app-user:view", "level-config:view", "pretty-id:view", "region-block:view", "room:view", "room-pin:view", "room-config:view", "room-whitelist:view", "room-robot:view", "app-config:view", "app-version:view", "resource:view", "resource-shop:view", "resource-group:view", "resource-grant:view", "gift:view", "emoji-pack:view", "host-agency-policy:view", "team-salary-policy:view", "host-salary-settlement:view", "coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "report:view", "gift-diamond:view", "full-server-notice:view", "lucky-gift:view", "payment-bill:view", "payment-third-party:view", "payment-product:view", "game:view", "daily-task:view", "achievement:view", "seven-day-checkin:view", "room-rocket:view", "red-packet:view", "cp-config:view", "vip-config:view", "weekly-star:view", "agency-opening:view", "role:view", "permission:view", "job:view"}
case "readonly":
return []string{
"overview:view",
@ -566,6 +569,7 @@ func defaultRolePermissionCodes(code string) []string {
"room:view",
"room-pin:view",
"room-config:view",
"room-whitelist:view",
"room-robot:view",
"app-config:view",
"app-version:view",
@ -620,7 +624,7 @@ func defaultRolePermissionMigrationCodes(code string) []string {
case "ops-admin":
return []string{
"app-user:update", "app-user:status", "app-user:password",
"room:view", "room:update", "room:delete", "room-pin:view", "room-pin:create", "room-pin:cancel", "room-config:view", "room-config:update", "room-robot:view", "room-robot:create", "room-robot:update",
"room:view", "room:update", "room:delete", "room-pin:view", "room-pin:create", "room-pin:cancel", "room-config:view", "room-config:update", "room-whitelist:view", "room-whitelist:update", "room-robot:view", "room-robot:create", "room-robot:update",
"app-config:view", "app-config:update",
"app-version:view", "app-version:create", "app-version:update", "app-version:delete",
"level-config:view", "level-config:update",
@ -651,7 +655,7 @@ func defaultRolePermissionMigrationCodes(code string) []string {
"agency-opening:view", "agency-opening:create", "agency-opening:update",
}
case "auditor", "readonly":
return []string{"level-config:view", "pretty-id:view", "region-block:view", "room:view", "room-pin:view", "room-config:view", "room-robot:view", "app-config:view", "app-version:view", "resource:view", "resource-shop:view", "resource-group:view", "resource-grant:view", "gift:view", "emoji-pack:view", "host-agency-policy:view", "team-salary-policy:view", "host-salary-settlement:view", "coin-seller:view", "coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "report:view", "gift-diamond:view", "full-server-notice:view", "lucky-gift:view", "payment-bill:view", "payment-third-party:view", "payment-product:view", "game:view", "daily-task:view", "achievement:view", "seven-day-checkin:view", "room-rocket:view", "red-packet:view", "cp-config:view", "vip-config:view", "weekly-star:view", "agency-opening:view"}
return []string{"level-config:view", "pretty-id:view", "region-block:view", "room:view", "room-pin:view", "room-config:view", "room-whitelist:view", "room-robot:view", "app-config:view", "app-version:view", "resource:view", "resource-shop:view", "resource-group:view", "resource-grant:view", "gift:view", "emoji-pack:view", "host-agency-policy:view", "team-salary-policy:view", "host-salary-settlement:view", "coin-seller:view", "coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "report:view", "gift-diamond:view", "full-server-notice:view", "lucky-gift:view", "payment-bill:view", "payment-third-party:view", "payment-product:view", "game:view", "daily-task:view", "achievement:view", "seven-day-checkin:view", "room-rocket:view", "red-packet:view", "cp-config:view", "vip-config:view", "weekly-star:view", "agency-opening:view"}
default:
return nil
}

View File

@ -5,7 +5,7 @@ SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE admin_app_banners
ADD COLUMN room_small_image_url VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '房间内小屏图 URL' AFTER cover_url,
ADD COLUMN display_scope VARCHAR(32) NOT NULL DEFAULT 'home' COMMENT '显示范围:首页、房间内或充值' AFTER banner_type,
ADD COLUMN display_scope VARCHAR(32) NOT NULL DEFAULT 'home' COMMENT '显示范围:首页、房间内、充值页或我的' AFTER banner_type,
ADD COLUMN starts_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '投放开始时间UTC epoch ms' AFTER status,
ADD COLUMN ends_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '投放结束时间UTC epoch ms' AFTER starts_at_ms,
ADD INDEX idx_admin_app_banners_display (app_code, display_scope, status, starts_at_ms, ends_at_ms, sort_order, id);

View File

@ -1,6 +1,6 @@
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
-- Banner 显示范围支持多选display_scope 以稳定逗号分隔值保存,例如 home,room,recharge
-- Banner 显示范围支持多选display_scope 以稳定逗号分隔值保存,例如 home,room,recharge,me
ALTER TABLE admin_app_banners
MODIFY COLUMN display_scope VARCHAR(128) NOT NULL DEFAULT 'home' COMMENT '显示范围,多选逗号分隔:首页、房间内或充值';
MODIFY COLUMN display_scope VARCHAR(128) NOT NULL DEFAULT 'home' COMMENT '显示范围,多选逗号分隔:首页、房间内、充值页或我的';

View File

@ -0,0 +1,41 @@
-- 房间白名单允许指定用户在 App 房间列表绕过 visible_region_id 过滤;本迁移只写后台菜单和权限事实。
SET @now_ms := UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000;
INSERT INTO admin_permissions (name, code, kind, description, created_at_ms, updated_at_ms) VALUES
('房间白名单查看', 'room-whitelist:view', 'menu', '允许查看房间白名单配置', @now_ms, @now_ms),
('房间白名单更新', 'room-whitelist:update', 'button', '允许更新房间白名单配置', @now_ms, @now_ms)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
kind = VALUES(kind),
description = VALUES(description),
updated_at_ms = VALUES(updated_at_ms);
INSERT INTO admin_menus (parent_id, title, code, path, icon, permission_code, sort, visible, created_at_ms, updated_at_ms)
SELECT parent.id, '房间白名单', 'room-whitelist', '/rooms/whitelist', 'shield', 'room-whitelist:view', 68, TRUE, @now_ms, @now_ms
FROM admin_menus parent
WHERE parent.code = 'rooms'
ON DUPLICATE KEY UPDATE
parent_id = VALUES(parent_id),
title = VALUES(title),
path = VALUES(path),
icon = VALUES(icon),
permission_code = VALUES(permission_code),
sort = VALUES(sort),
visible = VALUES(visible),
updated_at_ms = VALUES(updated_at_ms);
UPDATE admin_menus
SET sort = 69, updated_at_ms = @now_ms
WHERE code = 'room-robots' AND sort < 69;
INSERT IGNORE INTO admin_role_permissions (role_id, permission_id)
SELECT r.id, p.id
FROM admin_roles r
JOIN admin_permissions p ON p.code IN ('room-whitelist:view', 'room-whitelist:update')
WHERE r.code IN ('platform-admin', 'ops-admin');
INSERT IGNORE INTO admin_role_permissions (role_id, permission_id)
SELECT r.id, p.id
FROM admin_roles r
JOIN admin_permissions p ON p.code = 'room-whitelist:view'
WHERE r.code IN ('auditor', 'readonly');

View File

@ -37,9 +37,9 @@ lucky_gift_worker:
tencent_im:
# Docker 本地联调全局/区域播报群;必须与 gateway/room-service 使用同一组腾讯 IM 应用配置。
enabled: true
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: "24h"
endpoint: "adminapisgp.im.qcloud.com"
group_type: "ChatRoom"

View File

@ -37,9 +37,9 @@ lucky_gift_worker:
tencent_im:
# activity-service 只负责全局/区域播报群;必须与 gateway/room-service 使用同一组腾讯 IM 应用配置。
enabled: true
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: "24h"
endpoint: "adminapisgp.im.qcloud.com"
group_type: "ChatRoom"

View File

@ -236,8 +236,8 @@ func (s *Service) SetUserLevel(ctx context.Context, command domain.SetUserLevelC
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.Level < 1 || command.Level > 30 {
return domain.SetUserLevelResult{}, xerr.New(xerr.InvalidArgument, "level must be between 1 and 30")
}
if command.Reason == "" {
command.Reason = "manager_center_level"

View File

@ -12,9 +12,9 @@ launch_session_ttl: "15m"
tencent_im:
# Docker/testbox 联调房内猜拳 PK 房间群消息;必须和 gateway/room 使用同一个 IM 应用。
enabled: true
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: "24h"
endpoint: "adminapisgp.im.qcloud.com"
group_type: "ChatRoom"

View File

@ -12,9 +12,9 @@ launch_session_ttl: "15m"
tencent_im:
# 本地联调房内猜拳 PK 房间群消息;必须和 gateway/room 使用同一个 IM 应用。
enabled: true
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: "24h"
endpoint: "adminapisgp.im.qcloud.com"
group_type: "ChatRoom"

View File

@ -51,6 +51,12 @@ grpc_client:
app_config:
# App 运行时配置由后台 APP配置写入 hyapp_admingateway 只读下发给 App。
mysql_dsn: "hyapp:hyapp@tcp(mysql:3306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=UTC"
# 房间白名单等低频配置用 Redis 缓存 5 分钟,避免每次列表请求查后台库。
redis_addr: "redis:6379"
redis_password: ""
redis_db: 0
key_prefix: "gateway:app_config:"
cache_ttl: "5m"
leaderboard:
# 活动用户榜单只读 wallet_transactions 的送礼事实;时间窗口统一按 UTC 计算。
wallet_mysql_dsn: "hyapp:hyapp@tcp(mysql:3306)/hyapp_wallet?parseTime=true&charset=utf8mb4&loc=UTC"
@ -81,9 +87,9 @@ login_risk:
blocked_timezone_prefixes: []
tencent_im:
# Docker 本地联调腾讯云 IM UserSig必须与 room-service 使用同一组应用配置。
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: "24h"
user_sig_ttl: "24h"
endpoint: "adminapisgp.im.qcloud.com"

View File

@ -55,6 +55,12 @@ grpc_client:
app_config:
# App 运行时配置由后台 APP配置写入 hyapp_admingateway 只读下发给 App。
mysql_dsn: "TENCENT_MYSQL_USER:TENCENT_MYSQL_PASSWORD@tcp(TENCENT_MYSQL_HOST:3306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=UTC"
# 房间白名单等低频配置用 Redis 缓存 5 分钟,避免每次列表请求查后台库。
redis_addr: "TENCENT_REDIS_HOST:6379"
redis_password: "TENCENT_REDIS_PASSWORD"
redis_db: 0
key_prefix: "gateway:app_config:"
cache_ttl: "5m"
leaderboard:
# 活动用户榜单只读钱包送礼事实;线上建议配置只读账号。
wallet_mysql_dsn: "TENCENT_MYSQL_USER:TENCENT_MYSQL_PASSWORD@tcp(TENCENT_MYSQL_HOST:3306)/hyapp_wallet?parseTime=true&charset=utf8mb4&loc=UTC"

View File

@ -51,6 +51,12 @@ grpc_client:
app_config:
# App 运行时配置由后台 APP配置写入 hyapp_admingateway 只读下发给 App。
mysql_dsn: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=UTC"
# 房间白名单等低频配置用 Redis 缓存 5 分钟,避免每次列表请求查后台库。
redis_addr: "127.0.0.1:13379"
redis_password: ""
redis_db: 0
key_prefix: "gateway:app_config:"
cache_ttl: "5m"
leaderboard:
# 活动用户榜单只读 wallet_transactions 的送礼事实;时间窗口统一按 UTC 计算。
wallet_mysql_dsn: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_wallet?parseTime=true&charset=utf8mb4&loc=UTC"
@ -81,9 +87,9 @@ login_risk:
blocked_timezone_prefixes: []
tencent_im:
# 本地联调腾讯云 IM UserSigSDKAppID 和密钥必须与 room-service 保持一致。
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: "24h"
# 客户端 UserSig 有效期;线上建议 12h-7d按登录刷新策略决定。
user_sig_ttl: "24h"

View File

@ -345,7 +345,22 @@ func openAppConfigReader(cfg config.AppConfigConfig) (*appconfig.MySQLReader, er
return nil, nil
}
return appconfig.OpenMySQLReader(cfg.MySQLDSN)
reader, err := appconfig.OpenMySQLReader(cfg.MySQLDSN)
if err != nil {
return nil, err
}
if strings.TrimSpace(cfg.RedisAddr) == "" {
return reader, nil
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cacheClient, err := appconfig.OpenRedisCache(ctx, cfg.RedisAddr, cfg.RedisPassword, cfg.RedisDB)
if err != nil {
_ = reader.Close()
return nil, fmt.Errorf("connect app config redis: %w", err)
}
reader.SetRedisCache(cacheClient, cfg.KeyPrefix, cfg.CacheTTL)
return reader, nil
}
func openLeaderboardWalletDB(cfg config.LeaderboardConfig) (*sql.DB, error) {

View File

@ -4,17 +4,21 @@ package appconfig
import (
"context"
"database/sql"
"encoding/json"
"errors"
"strconv"
"strings"
"time"
mysqlDriver "github.com/go-sql-driver/mysql"
"github.com/redis/go-redis/v9"
)
const h5LinkGroup = "h5-links"
const roomRegionWhitelistGroup = "room-region-whitelist"
const listH5LinksSQL = "SELECT `key`, COALESCE(description, ''), COALESCE(value, ''), updated_at_ms FROM admin_app_configs WHERE `group` = ? ORDER BY `key` ASC"
const getRoomRegionWhitelistSQL = "SELECT COALESCE(value, '') FROM admin_app_configs WHERE `group` = ? AND `key` = ? LIMIT 1"
const bdLeaderPositionAliasSQL = `
SELECT position_alias
FROM admin_bd_leader_position_aliases
@ -185,11 +189,15 @@ type Reader interface {
ListSplashScreens(ctx context.Context, query SplashScreenQuery) ([]SplashScreen, error)
ListPopups(ctx context.Context, query PopupQuery) ([]Popup, error)
LatestVersion(ctx context.Context, query VersionQuery) (Version, error)
RoomRegionWhitelistAllows(ctx context.Context, appCode string, userID int64) (bool, error)
}
// MySQLReader 从 hyapp_admin 读取后台 App 配置。
type MySQLReader struct {
db *sql.DB
db *sql.DB
cache *redis.Client
cachePrefix string
cacheTTL time.Duration
}
// OpenMySQLReader 创建后台配置只读连接池。
@ -208,7 +216,44 @@ func (r *MySQLReader) Close() error {
return nil
}
return r.db.Close()
return errors.Join(r.db.Close(), r.closeCache())
}
func (r *MySQLReader) closeCache() error {
if r == nil || r.cache == nil {
return nil
}
return r.cache.Close()
}
// OpenRedisCache 创建 App 配置 Redis 缓存连接;启动期探测失败直接暴露配置问题。
func OpenRedisCache(ctx context.Context, addr string, password string, db int) (*redis.Client, error) {
client := redis.NewClient(&redis.Options{
Addr: strings.TrimSpace(addr),
Password: password,
DB: db,
})
if err := client.Ping(ctx).Err(); err != nil {
_ = client.Close()
return nil, err
}
return client, nil
}
// SetRedisCache 给低频后台配置挂 Redis 五分钟读缓存,避免房间列表每次都查 hyapp_admin。
func (r *MySQLReader) SetRedisCache(client *redis.Client, keyPrefix string, ttl time.Duration) {
if r == nil {
return
}
r.cache = client
r.cachePrefix = strings.TrimSpace(keyPrefix)
if r.cachePrefix == "" {
r.cachePrefix = "gateway:app_config:"
}
if ttl <= 0 {
ttl = 5 * time.Minute
}
r.cacheTTL = ttl
}
// ListH5Links 返回后台动态维护的 H5 入口集合。
@ -466,6 +511,102 @@ func (r *MySQLReader) LatestVersion(ctx context.Context, query VersionQuery) (Ve
return item, nil
}
// RoomRegionWhitelistAllows 判断用户是否可绕过房间区域限制;结果按 app+user 缓存五分钟。
func (r *MySQLReader) RoomRegionWhitelistAllows(ctx context.Context, appCode string, userID int64) (bool, error) {
if userID <= 0 {
return false, nil
}
if r == nil || r.db == nil {
return false, errors.New("app config reader is not configured")
}
app := normalizeAppCode(appCode)
if cached, ok, err := r.cachedRoomRegionWhitelist(ctx, app, userID); err == nil && ok {
return cached, nil
}
allowed, err := r.roomRegionWhitelistAllowsFromDB(ctx, app, userID)
if err != nil {
return false, err
}
r.storeRoomRegionWhitelistCache(ctx, app, userID, allowed)
return allowed, nil
}
func (r *MySQLReader) roomRegionWhitelistAllowsFromDB(ctx context.Context, appCode string, userID int64) (bool, error) {
var raw string
err := r.db.QueryRowContext(ctx, getRoomRegionWhitelistSQL, roomRegionWhitelistGroup, appCode).Scan(&raw)
if errors.Is(err, sql.ErrNoRows) || isMissingTableError(err) {
return false, nil
}
if err != nil {
return false, err
}
ids, err := parseRoomRegionWhitelist(raw)
if err != nil {
return false, err
}
_, ok := ids[userID]
return ok, nil
}
func (r *MySQLReader) cachedRoomRegionWhitelist(ctx context.Context, appCode string, userID int64) (bool, bool, error) {
if r == nil || r.cache == nil {
return false, false, nil
}
value, err := r.cache.Get(ctx, r.roomRegionWhitelistCacheKey(appCode, userID)).Result()
if errors.Is(err, redis.Nil) {
return false, false, nil
}
if err != nil {
return false, false, err
}
return value == "1", true, nil
}
func (r *MySQLReader) storeRoomRegionWhitelistCache(ctx context.Context, appCode string, userID int64, allowed bool) {
if r == nil || r.cache == nil {
return
}
value := "0"
if allowed {
value = "1"
}
// 缓存只优化读路径;写入失败时保持 DB 判定结果,不让 Redis 抖动阻断房间列表。
_ = r.cache.Set(ctx, r.roomRegionWhitelistCacheKey(appCode, userID), value, r.cacheTTL).Err()
}
func (r *MySQLReader) roomRegionWhitelistCacheKey(appCode string, userID int64) string {
return strings.TrimRight(r.cachePrefix, ":") + ":room_region_whitelist:" + normalizeAppCode(appCode) + ":" + strconv.FormatInt(userID, 10)
}
type roomRegionWhitelistPayload struct {
UserIDs []string `json:"user_ids"`
}
func parseRoomRegionWhitelist(raw string) (map[int64]struct{}, error) {
raw = strings.TrimSpace(raw)
if raw == "" {
return map[int64]struct{}{}, nil
}
var payload roomRegionWhitelistPayload
if strings.HasPrefix(raw, "[") {
if err := json.Unmarshal([]byte(raw), &payload.UserIDs); err != nil {
return nil, err
}
} else if err := json.Unmarshal([]byte(raw), &payload); err != nil {
return nil, err
}
out := make(map[int64]struct{}, len(payload.UserIDs))
for _, item := range payload.UserIDs {
id, err := strconv.ParseInt(strings.TrimSpace(item), 10, 64)
if err != nil || id <= 0 {
continue
}
out[id] = struct{}{}
}
return out, nil
}
// StaticReader 给测试和临时环境提供内存版 H5 配置读取。
type StaticReader struct {
Links []H5Link
@ -476,6 +617,7 @@ type StaticReader struct {
Version Version
Err error
PositionAliases map[string]string
RoomWhitelist map[string]bool
}
// ListH5Links 返回预置 H5 配置。
@ -556,6 +698,14 @@ func (r StaticReader) LatestVersion(_ context.Context, query VersionQuery) (Vers
return item, nil
}
// RoomRegionWhitelistAllows 返回内存白名单结果,测试可用 "app:user_id" 作为 key。
func (r StaticReader) RoomRegionWhitelistAllows(_ context.Context, appCode string, userID int64) (bool, error) {
if r.Err != nil {
return false, r.Err
}
return r.RoomWhitelist[bdLeaderPositionAliasKey(appCode, userID)], nil
}
func normalizeAppCode(value string) string {
value = strings.ToLower(strings.TrimSpace(value))
if value == "" {
@ -606,13 +756,15 @@ func NormalizeBannerDisplayScope(value string) string {
return "room"
case "recharge", "充值页":
return "recharge"
case "me", "我的页", "我的":
return "me"
default:
return ""
}
}
func bannerDisplayScopeList(value string) []string {
seen := make(map[string]struct{}, 3)
seen := make(map[string]struct{}, 4)
for _, part := range strings.Split(value, ",") {
scope := NormalizeBannerDisplayScope(part)
if scope != "" {
@ -620,7 +772,7 @@ func bannerDisplayScopeList(value string) []string {
}
}
out := make([]string, 0, len(seen))
for _, scope := range []string{"home", "room", "recharge"} {
for _, scope := range []string{"home", "room", "recharge", "me"} {
if _, ok := seen[scope]; ok {
out = append(out, scope)
}

View File

@ -8,6 +8,8 @@ func TestNormalizeBannerDisplayScopeAcceptsChineseLabels(t *testing.T) {
"首页": "home",
"房间内": "room",
"充值页": "recharge",
"我的页": "me",
"ME": "me",
"ROOM": "room",
"bad": "",
}
@ -19,8 +21,8 @@ func TestNormalizeBannerDisplayScopeAcceptsChineseLabels(t *testing.T) {
}
func TestBannerDisplayScopeListParsesMultiScopeValue(t *testing.T) {
got := bannerDisplayScopeList("room,home,recharge")
want := []string{"home", "room", "recharge"}
got := bannerDisplayScopeList("room,home,recharge,me")
want := []string{"home", "room", "recharge", "me"}
if len(got) != len(want) {
t.Fatalf("scope count mismatch: got %+v want %+v", got, want)
}
@ -30,3 +32,25 @@ func TestBannerDisplayScopeListParsesMultiScopeValue(t *testing.T) {
}
}
}
func TestParseRoomRegionWhitelistSupportsObjectAndArrayPayloads(t *testing.T) {
cases := []string{
`{"user_ids":["325379237278126080","1001","1001","0","bad"]}`,
`["325379237278126080","1001","1001","0","bad"]`,
}
for _, input := range cases {
got, err := parseRoomRegionWhitelist(input)
if err != nil {
t.Fatalf("parse whitelist %s failed: %v", input, err)
}
if _, ok := got[325379237278126080]; !ok {
t.Fatalf("long user id missing: %+v", got)
}
if _, ok := got[1001]; !ok {
t.Fatalf("small user id missing: %+v", got)
}
if _, ok := got[0]; ok {
t.Fatalf("zero user id must be ignored: %+v", got)
}
}
}

View File

@ -115,6 +115,16 @@ type LoginRiskFastGuardConfig struct {
type AppConfigConfig struct {
// MySQLDSN 指向后台管理库 hyapp_admingateway 只读 App 运行时配置表。
MySQLDSN string `yaml:"mysql_dsn"`
// RedisAddr 用于缓存低频后台配置判定,默认复用 auth_rate_limit Redis。
RedisAddr string `yaml:"redis_addr"`
// RedisPassword 是 Redis 鉴权密码,默认复用 auth_rate_limit Redis。
RedisPassword string `yaml:"redis_password"`
// RedisDB 是 Redis logical DB默认复用 auth_rate_limit Redis。
RedisDB int `yaml:"redis_db"`
// KeyPrefix 隔离 App 配置缓存 key避免和登录风控、频控共用命名空间。
KeyPrefix string `yaml:"key_prefix"`
// CacheTTL 控制后台配置读缓存时间;房间白名单默认五分钟。
CacheTTL time.Duration `yaml:"cache_ttl"`
}
// LeaderboardConfig 描述 App 活动榜单读取钱包送礼事实的只读数据源。
@ -296,7 +306,10 @@ func Default() Config {
RetryableStatusCodes: []string{"UNAVAILABLE"},
},
AppConfig: AppConfigConfig{
MySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=UTC",
MySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_admin?parseTime=true&charset=utf8mb4&loc=UTC",
RedisAddr: "127.0.0.1:13379",
KeyPrefix: "gateway:app_config:",
CacheTTL: 5 * time.Minute,
},
Leaderboard: LeaderboardConfig{
WalletMySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_wallet?parseTime=true&charset=utf8mb4&loc=UTC",
@ -424,6 +437,19 @@ func (cfg *Config) Normalize() error {
RetryableStatusCodes: runtimeGRPC.RetryableStatusCodes,
}
cfg.AppConfig.MySQLDSN = strings.TrimSpace(cfg.AppConfig.MySQLDSN)
cfg.AppConfig.RedisAddr = strings.TrimSpace(cfg.AppConfig.RedisAddr)
cfg.AppConfig.KeyPrefix = strings.TrimSpace(cfg.AppConfig.KeyPrefix)
if cfg.AppConfig.RedisAddr == "" {
cfg.AppConfig.RedisAddr = strings.TrimSpace(cfg.AuthRateLimit.RedisAddr)
cfg.AppConfig.RedisPassword = cfg.AuthRateLimit.RedisPassword
cfg.AppConfig.RedisDB = cfg.AuthRateLimit.RedisDB
}
if cfg.AppConfig.KeyPrefix == "" {
cfg.AppConfig.KeyPrefix = "gateway:app_config:"
}
if cfg.AppConfig.CacheTTL <= 0 {
cfg.AppConfig.CacheTTL = 5 * time.Minute
}
cfg.Leaderboard.WalletMySQLDSN = strings.TrimSpace(cfg.Leaderboard.WalletMySQLDSN)
cfg.LoginRisk.RedisAddr = strings.TrimSpace(cfg.LoginRisk.RedisAddr)
cfg.LoginRisk.KeyPrefix = strings.TrimSpace(cfg.LoginRisk.KeyPrefix)

View File

@ -17,6 +17,7 @@ type ConfigReader interface {
ListSplashScreens(ctx context.Context, query appconfig.SplashScreenQuery) ([]appconfig.SplashScreen, error)
ListPopups(ctx context.Context, query appconfig.PopupQuery) ([]appconfig.Popup, error)
LatestVersion(ctx context.Context, query appconfig.VersionQuery) (appconfig.Version, error)
RoomRegionWhitelistAllows(ctx context.Context, appCode string, userID int64) (bool, error)
}
// ObjectUploader 是 gateway 上传接口依赖的对象存储最小能力。

View File

@ -3699,8 +3699,8 @@ func TestListAppBannersReturnsAdminAppConfig(t *testing.T) {
CoverURL: "https://cdn.example.com/banner.png",
RoomSmallImageURL: "https://cdn.example.com/banner-small.png",
BannerType: "h5",
DisplayScope: "home,room",
DisplayScopes: []string{"home", "room"},
DisplayScope: "home,room,me",
DisplayScopes: []string{"home", "room", "me"},
Param: "https://h5.example.com/activity",
Platform: "android",
SortOrder: 10,
@ -3714,7 +3714,7 @@ func TestListAppBannersReturnsAdminAppConfig(t *testing.T) {
}}}
handler.SetAppConfigReader(reader)
router := handler.Routes(auth.NewVerifier("secret"))
request := httptest.NewRequest(http.MethodGet, "/api/v1/app/banners?display_scope=room&platform=android&country=CN&region_id=1", nil)
request := httptest.NewRequest(http.MethodGet, "/api/v1/app/banners?display_scope=me&platform=android&country=CN&region_id=1", nil)
request.Header.Set("X-Request-ID", "req-app-banners")
request.Header.Set("X-App-Package", "com.org.laluparty")
recorder := httptest.NewRecorder()
@ -3732,7 +3732,7 @@ func TestListAppBannersReturnsAdminAppConfig(t *testing.T) {
if response.Code != httpkit.CodeOK || !ok {
t.Fatalf("unexpected envelope: %+v", response)
}
if reader.bannerQuery.DisplayScope != "room" || reader.bannerQuery.Platform != "android" || reader.bannerQuery.RegionID != 1 || reader.bannerQuery.Country != "CN" {
if reader.bannerQuery.DisplayScope != "me" || reader.bannerQuery.Platform != "android" || reader.bannerQuery.RegionID != 1 || reader.bannerQuery.Country != "CN" {
t.Fatalf("banner query mismatch: %+v", reader.bannerQuery)
}
if data["total"].(float64) != 1 {
@ -3746,11 +3746,11 @@ func TestListAppBannersReturnsAdminAppConfig(t *testing.T) {
if !ok || first["cover_url"] != "https://cdn.example.com/banner.png" || first["type"] != "h5" || first["param"] != "https://h5.example.com/activity" {
t.Fatalf("banner item mismatch: %+v", first)
}
if first["display_scope"] != "home,room" || first["room_small_image_url"] != "https://cdn.example.com/banner-small.png" {
if first["display_scope"] != "home,room,me" || first["room_small_image_url"] != "https://cdn.example.com/banner-small.png" {
t.Fatalf("banner display fields mismatch: %+v", first)
}
displayScopes, ok := first["display_scopes"].([]any)
if !ok || len(displayScopes) != 2 || displayScopes[0] != "home" || displayScopes[1] != "room" {
if !ok || len(displayScopes) != 3 || displayScopes[0] != "home" || displayScopes[1] != "room" || displayScopes[2] != "me" {
t.Fatalf("banner display scopes mismatch: %+v", first)
}
if first["platform"] != "android" || first["sort_order"].(float64) != 10 || first["starts_at_ms"].(float64) != 1700000000000 || first["ends_at_ms"].(float64) != 1800000000000 || first["updated_at_ms"].(float64) != 1700000002000 {

View File

@ -5,6 +5,7 @@ import (
"hyapp/pkg/tencentrtc"
"hyapp/services/gateway-service/internal/client"
"hyapp/services/gateway-service/internal/transport/http/appapi"
"hyapp/services/gateway-service/internal/transport/http/httproutes"
)
@ -19,6 +20,7 @@ type Handler struct {
userRegionClient client.UserRegionClient
userSocialClient client.UserSocialClient
userHostClient client.UserHostClient
appConfigReader appapi.ConfigReader
walletClient client.WalletClient
growthLevelClient client.GrowthLevelClient
achievementClient client.AchievementClient
@ -34,6 +36,7 @@ type Config struct {
UserRegionClient client.UserRegionClient
UserSocialClient client.UserSocialClient
UserHostClient client.UserHostClient
AppConfigReader appapi.ConfigReader
WalletClient client.WalletClient
GrowthLevelClient client.GrowthLevelClient
AchievementClient client.AchievementClient
@ -50,6 +53,7 @@ func New(config Config) *Handler {
userRegionClient: config.UserRegionClient,
userSocialClient: config.UserSocialClient,
userHostClient: config.UserHostClient,
appConfigReader: config.AppConfigReader,
walletClient: config.WalletClient,
growthLevelClient: config.GrowthLevelClient,
achievementClient: config.AchievementClient,

View File

@ -106,12 +106,14 @@ func (h *Handler) listRooms(writer http.ResponseWriter, request *http.Request) {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
allVisibleRegions := h.roomRegionWhitelistAllows(request, viewerUserID)
resp, err := h.roomQueryClient.ListRooms(request.Context(), &roomv1.ListRoomsRequest{
Meta: httpkit.RoomMeta(request, "", ""),
ViewerUserId: viewerUserID,
VisibleRegionId: userResp.GetUser().GetRegionId(),
ViewerCountryCode: userResp.GetUser().GetCountry(),
AllVisibleRegions: allVisibleRegions,
Tab: tab,
Cursor: request.URL.Query().Get("cursor"),
Limit: limit,
@ -183,6 +185,18 @@ func (h *Handler) listRoomFeeds(writer http.ResponseWriter, request *http.Reques
httpkit.WriteOK(writer, request, roomListDataFromProto(resp))
}
func (h *Handler) roomRegionWhitelistAllows(request *http.Request, viewerUserID int64) bool {
if h.appConfigReader == nil || viewerUserID <= 0 {
return false
}
allowed, err := h.appConfigReader.RoomRegionWhitelistAllows(request.Context(), appcode.FromContext(request.Context()), viewerUserID)
if err != nil {
// 白名单读取失败时必须 fail-closed避免后台配置或缓存异常放大成跨区域房间泄露。
return false
}
return allowed
}
func (h *Handler) roomFeedRelatedUsers(request *http.Request, tab string, query string, rawCursor string) ([]*roomv1.RoomFeedRelatedUser, bool, error) {
if tab == "visited" || tab == "followed" {
return nil, true, nil

View File

@ -31,6 +31,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler {
UserRegionClient: h.userRegionClient,
UserSocialClient: h.userSocialClient,
UserHostClient: h.userHostClient,
AppConfigReader: h.appConfigReader,
WalletClient: h.walletClient,
GrowthLevelClient: h.growthLevelClient,
AchievementClient: h.achievementClient,

View File

@ -10,9 +10,9 @@ mysql_auto_migrate: false
tencent_im:
enabled: true
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: 24h
endpoint: "adminapisgp.im.qcloud.com"
request_timeout: 5s

View File

@ -10,9 +10,9 @@ mysql_auto_migrate: false
tencent_im:
enabled: true
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: 24h
endpoint: "adminapisgp.im.qcloud.com"
request_timeout: 5s

View File

@ -20,6 +20,7 @@ const (
channelTencentIMC2C = "tencent_im_c2c"
eventWalletBalance = "WalletBalanceChanged"
eventVIPActivated = "VipActivated"
robotCoinAssetType = "ROBOT_COIN"
deliveryStatusDelivering = "delivering"
deliveryStatusDelivered = "delivered"
deliveryStatusRetryable = "retryable"
@ -122,10 +123,11 @@ func (r *MySQLRepository) listWalletBalanceCandidates(ctx context.Context, limit
LEFT JOIN notice_delivery_events nde
ON nde.source_name = ? AND nde.app_code = wo.app_code AND nde.source_event_id = wo.event_id AND nde.channel = ?
WHERE wo.app_code = ? AND wo.event_type IN (%s)
AND wo.asset_type <> ?
AND nde.source_event_id IS NULL
ORDER BY wo.created_at_ms ASC, wo.event_id ASC
LIMIT ?`, r.walletOutboxTable, sqlPlaceholders(len(eventTypes))),
args: append([]any{sourceWalletOutbox, channelTencentIMC2C, appCode}, stringSliceToAny(eventTypes)...),
args: append(append([]any{sourceWalletOutbox, channelTencentIMC2C, appCode}, stringSliceToAny(eventTypes)...), robotCoinAssetType),
},
{
query: fmt.Sprintf(`
@ -134,10 +136,11 @@ func (r *MySQLRepository) listWalletBalanceCandidates(ctx context.Context, limit
JOIN notice_delivery_events nde
ON nde.source_name = ? AND nde.app_code = wo.app_code AND nde.source_event_id = wo.event_id AND nde.channel = ?
WHERE wo.app_code = ? AND wo.event_type IN (%s)
AND wo.asset_type <> ?
AND nde.status = ? AND nde.next_retry_at_ms <= ?
ORDER BY wo.created_at_ms ASC, wo.event_id ASC
LIMIT ?`, r.walletOutboxTable, sqlPlaceholders(len(eventTypes))),
args: append(append([]any{sourceWalletOutbox, channelTencentIMC2C, appCode}, stringSliceToAny(eventTypes)...), deliveryStatusRetryable, nowMs),
args: append(append(append([]any{sourceWalletOutbox, channelTencentIMC2C, appCode}, stringSliceToAny(eventTypes)...), robotCoinAssetType), deliveryStatusRetryable, nowMs),
},
{
query: fmt.Sprintf(`
@ -146,10 +149,11 @@ func (r *MySQLRepository) listWalletBalanceCandidates(ctx context.Context, limit
JOIN notice_delivery_events nde
ON nde.source_name = ? AND nde.app_code = wo.app_code AND nde.source_event_id = wo.event_id AND nde.channel = ?
WHERE wo.app_code = ? AND wo.event_type IN (%s)
AND wo.asset_type <> ?
AND nde.status = ? AND nde.lock_until_ms <= ?
ORDER BY wo.created_at_ms ASC, wo.event_id ASC
LIMIT ?`, r.walletOutboxTable, sqlPlaceholders(len(eventTypes))),
args: append(append([]any{sourceWalletOutbox, channelTencentIMC2C, appCode}, stringSliceToAny(eventTypes)...), deliveryStatusDelivering, nowMs),
args: append(append(append([]any{sourceWalletOutbox, channelTencentIMC2C, appCode}, stringSliceToAny(eventTypes)...), robotCoinAssetType), deliveryStatusDelivering, nowMs),
},
}
for _, branch := range branches {

View File

@ -73,6 +73,10 @@ func (s *Service) ProcessWalletOutboxMessage(ctx context.Context, message wallet
if !isWalletPrivateNoticeEvent(message.EventType) {
return false, nil
}
if isRobotCoinWalletNotice(message.AssetType) {
// ROBOT_COIN 只服务机器人房间展示扣费,机器人账号不需要也不能接收用户 C2C 余额通知。
return true, nil
}
options = normalizeWalletNoticeWorkerOptions(options, s.cfg.NodeID)
if s.repository == nil {
return true, fmt.Errorf("notice repository is not configured")
@ -162,6 +166,10 @@ func isWalletPrivateNoticeEvent(eventType string) bool {
return false
}
func isRobotCoinWalletNotice(assetType string) bool {
return assetType == robotCoinAssetType
}
func walletBalanceNoticePayload(event WalletBalanceEvent) (json.RawMessage, error) {
var payload map[string]any
if err := json.Unmarshal([]byte(event.PayloadJSON), &payload); err != nil {

View File

@ -115,6 +115,31 @@ func TestProcessWalletOutboxMessagePublishesPrivateIM(t *testing.T) {
}
}
func TestProcessWalletOutboxMessageSkipsRobotCoinPrivateIM(t *testing.T) {
repo := &fakeRepository{}
publisher := &fakePublisher{}
service := New(Config{NodeID: "node-a"}, repo, publisher)
handled, err := service.ProcessWalletOutboxMessage(context.Background(), walletmq.WalletOutboxMessage{
AppCode: "lalu",
EventID: "robot-wallet-1",
EventType: "WalletBalanceChanged",
TransactionID: "robot-tx-1",
CommandID: "robot-cmd-1",
UserID: 100001,
AssetType: robotCoinAssetType,
AvailableDelta: -1,
PayloadJSON: `{"available_after":999}`,
OccurredAtMS: 1710000000000,
}, WalletNoticeWorkerOptions{MaxRetryCount: 3})
if err != nil {
t.Fatalf("ProcessWalletOutboxMessage failed: %v", err)
}
if !handled || len(repo.claimedMessages) != 0 || len(repo.delivered) != 0 || len(publisher.messages) != 0 {
t.Fatalf("robot coin notice must be acked without c2c delivery: handled=%v claimed=%d delivered=%d messages=%d", handled, len(repo.claimedMessages), len(repo.delivered), len(publisher.messages))
}
}
func TestProcessWalletBalanceNoticesMarksRetryable(t *testing.T) {
repo := &fakeRepository{
events: []WalletBalanceEvent{{

View File

@ -19,12 +19,14 @@ rank_limit: 20
snapshot_every_n: 10
wallet_service_addr: "wallet-service:13004"
activity_service_addr: "activity-service:13006"
robot_service_addr: "robot-service:13011"
user_service_addr: "user-service:13005"
tencent_im:
# Docker 本地联调腾讯云 IM REST 桥接;必须与 gateway-service 使用同一组应用配置。
enabled: true
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: "24h"
endpoint: "adminapisgp.im.qcloud.com"
group_type: "ChatRoom"
@ -67,6 +69,13 @@ rocketmq:
tencent_im_consumer_enabled: true
tencent_im_consumer_group: "hyapp-room-im-bridge"
consumer_max_reconsume_times: 16
robot_room_outbox:
enabled: true
topic: "hyapp_robot_room_outbox"
producer_group: "hyapp-room-robot-outbox-producer"
tencent_im_consumer_enabled: true
tencent_im_consumer_group: "hyapp-test-room-robot-im-bridge"
consumer_max_reconsume_times: 16
rocket_launch:
enabled: true
topic: "hyapp_room_rocket_launch"
@ -89,3 +98,14 @@ outbox_worker:
max_retry_count: 10
initial_backoff: "5s"
max_backoff: "5m"
robot_outbox_worker:
# Docker 本地单独投递机器人展示事件,避免压住主 room_outbox fanout。
enabled: true
publish_mode: "mq"
poll_interval: "1s"
batch_size: 30
publish_timeout: "3s"
retry_strategy: "exponential_backoff"
max_retry_count: 10
initial_backoff: "5s"
max_backoff: "5m"

View File

@ -18,6 +18,8 @@ rank_limit: 20
snapshot_every_n: 10
wallet_service_addr: "wallet-service.internal:13004"
activity_service_addr: "activity-service.internal:13006"
robot_service_addr: "robot-service.internal:13011"
user_service_addr: "user-service.internal:13005"
tencent_im:
# 线上开启后,腾讯云 IM 建群和房间系统消息都由 room_outbox worker 异步投递。
enabled: true
@ -77,6 +79,13 @@ rocketmq:
tencent_im_consumer_enabled: true
tencent_im_consumer_group: "hyapp-room-im-bridge"
consumer_max_reconsume_times: 16
robot_room_outbox:
enabled: true
topic: "hyapp_robot_room_outbox"
producer_group: "hyapp-room-robot-outbox-producer"
tencent_im_consumer_enabled: true
tencent_im_consumer_group: "hyapp-room-robot-im-bridge"
consumer_max_reconsume_times: 16
rocket_launch:
enabled: true
topic: "hyapp_room_rocket_launch"
@ -99,3 +108,14 @@ outbox_worker:
max_retry_count: 10
initial_backoff: "5s"
max_backoff: "5m"
robot_outbox_worker:
# 机器人房间展示事件独立投递,只服务 IM 展示,不投 activity/statistics 主业务消费者。
enabled: true
publish_mode: "mq"
poll_interval: "1s"
batch_size: 30
publish_timeout: "3s"
retry_strategy: "exponential_backoff"
max_retry_count: 10
initial_backoff: "5s"
max_backoff: "5m"

View File

@ -19,12 +19,14 @@ node_registry_heartbeat_interval: "10s"
owner_forward_timeout: "2s"
wallet_service_addr: "127.0.0.1:13004"
activity_service_addr: "127.0.0.1:13006"
robot_service_addr: "127.0.0.1:13011"
user_service_addr: "127.0.0.1:13005"
tencent_im:
# 本地联调腾讯云 IM REST 桥接SDKAppID、密钥和管理员账号必须来自同一个应用。
enabled: true
sdk_app_id: 20036101
secret_key: "dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c"
admin_identifier: "900100100"
sdk_app_id: 20040101
secret_key: "2f6a5ec58cccf79647557a96c15e6efe89ba5a44c474096bde2589a633fcd45e"
admin_identifier: "administrator"
admin_user_sig_ttl: "24h"
# REST API 区域域名必须匹配腾讯云 IM 应用的数据存储区域。
endpoint: "adminapisgp.im.qcloud.com"
@ -70,6 +72,13 @@ rocketmq:
tencent_im_consumer_enabled: true
tencent_im_consumer_group: "hyapp-room-im-bridge"
consumer_max_reconsume_times: 16
robot_room_outbox:
enabled: true
topic: "hyapp_robot_room_outbox"
producer_group: "hyapp-room-robot-outbox-producer"
tencent_im_consumer_enabled: true
tencent_im_consumer_group: "hyapp-test-room-robot-im-bridge"
consumer_max_reconsume_times: 16
rocket_launch:
enabled: true
topic: "hyapp_room_rocket_launch"
@ -92,3 +101,14 @@ outbox_worker:
max_retry_count: 10
initial_backoff: "5s"
max_backoff: "5m"
robot_outbox_worker:
# 机器人展示事件走独立 outbox/topic只投房间 IM不占用真人 room_outbox 主流程。
enabled: true
publish_mode: "mq"
poll_interval: "1s"
batch_size: 30
publish_timeout: "3s"
retry_strategy: "exponential_backoff"
max_retry_count: 10
initial_backoff: "5s"
max_backoff: "5m"

View File

@ -156,6 +156,27 @@ CREATE TABLE IF NOT EXISTS room_outbox (
KEY idx_room_outbox_retention (app_code, status, updated_at_ms, event_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='房间事件 outbox 表';
CREATE TABLE IF NOT EXISTS room_robot_outbox (
app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离',
event_id VARCHAR(128) NOT NULL COMMENT '事件幂等 ID',
event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
room_id VARCHAR(64) NOT NULL COMMENT '机器人房间 ID',
status VARCHAR(32) NOT NULL COMMENT '业务状态',
worker_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'worker ID',
lock_until_ms BIGINT NULL COMMENT '锁定过期时间UTC epoch ms',
envelope LONGBLOB NOT NULL COMMENT '事件信封',
created_at_ms BIGINT NOT NULL COMMENT '创建时间UTC epoch ms',
retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数',
next_retry_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '下一次重试时间UTC epoch ms',
last_error TEXT NULL COMMENT '最后一次失败原因',
updated_at_ms BIGINT NOT NULL COMMENT '更新时间UTC epoch ms',
PRIMARY KEY (app_code, event_id),
KEY idx_room_robot_outbox_pending (app_code, status, next_retry_at_ms, created_at_ms, event_id),
KEY idx_room_robot_outbox_claim (app_code, status, lock_until_ms, created_at_ms, event_id),
KEY idx_room_robot_outbox_event_created (app_code, event_type, created_at_ms, event_id),
KEY idx_room_robot_outbox_retention (app_code, status, updated_at_ms, event_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='机器人房间展示事件 outbox 表';
CREATE TABLE IF NOT EXISTS room_user_feed_entries (
app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离',
user_id BIGINT NOT NULL COMMENT '用户 ID',
@ -238,6 +259,8 @@ CREATE TABLE IF NOT EXISTS room_robot_rooms (
status VARCHAR(32) NOT NULL COMMENT '运行状态active/stopped',
owner_robot_user_id BIGINT NOT NULL COMMENT '房主机器人用户 ID',
robot_user_ids_json JSON NOT NULL COMMENT '本房间占用的机器人用户 ID 集合',
active_robot_count INT NOT NULL DEFAULT 0 COMMENT '房间内同时保持的活跃机器人数量0 表示兼容旧配置全量在线',
seat_count INT NOT NULL DEFAULT 10 COMMENT '机器人房间麦位数10/15/20',
gift_ids_json JSON NOT NULL COMMENT '普通礼物 ID 集合',
lucky_gift_ids_json JSON NOT NULL COMMENT '幸运礼物 ID 集合',
normal_gift_interval_ms BIGINT NOT NULL COMMENT '普通礼物间隔毫秒',
@ -245,6 +268,11 @@ CREATE TABLE IF NOT EXISTS room_robot_rooms (
lucky_combo_max BIGINT NOT NULL COMMENT '幸运礼物最大连击次数',
lucky_pause_min_ms BIGINT NOT NULL COMMENT '幸运礼物连击后最小暂停毫秒',
lucky_pause_max_ms BIGINT NOT NULL COMMENT '幸运礼物连击后最大暂停毫秒',
robot_stay_min_ms BIGINT NOT NULL DEFAULT 180000 COMMENT '机器人单次最短停留毫秒',
robot_stay_max_ms BIGINT NOT NULL DEFAULT 600000 COMMENT '机器人单次最长停留毫秒',
robot_replace_min_ms BIGINT NOT NULL DEFAULT 0 COMMENT '机器人离开后最短补位延迟毫秒',
robot_replace_max_ms BIGINT NOT NULL DEFAULT 60000 COMMENT '机器人离开后最长补位延迟毫秒',
max_gift_senders BIGINT NOT NULL DEFAULT 1 COMMENT '同一时间最多允许送礼的机器人数量',
created_by_admin_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建管理员 ID',
created_at_ms BIGINT NOT NULL COMMENT '创建时间UTC epoch ms',
updated_at_ms BIGINT NOT NULL COMMENT '更新时间UTC epoch ms',
@ -253,6 +281,36 @@ CREATE TABLE IF NOT EXISTS room_robot_rooms (
KEY idx_room_robot_rooms_owner (app_code, owner_robot_user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='机器人房间后台配置表';
CREATE TABLE IF NOT EXISTS room_human_robot_configs (
app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离',
enabled BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否启用真人房间机器人行为',
candidate_room_max_online INT NOT NULL DEFAULT 5 COMMENT '低于该在线人数的同国家真人房可进入机器人',
room_full_stop_online INT NOT NULL DEFAULT 10 COMMENT '房间达到该在线人数后停止补机器人',
room_target_min_online INT NOT NULL DEFAULT 8 COMMENT '房间随机目标总人数下限',
room_target_max_online INT NOT NULL DEFAULT 10 COMMENT '房间随机目标总人数上限',
robot_stay_min_ms BIGINT NOT NULL DEFAULT 60000 COMMENT '机器人单次最短停留毫秒',
robot_stay_max_ms BIGINT NOT NULL DEFAULT 600000 COMMENT '机器人单次最长停留毫秒',
robot_replace_min_ms BIGINT NOT NULL DEFAULT 60000 COMMENT '机器人离开后最短补位延迟毫秒',
robot_replace_max_ms BIGINT NOT NULL DEFAULT 180000 COMMENT '机器人离开后最长补位延迟毫秒',
normal_gift_interval_ms BIGINT NOT NULL DEFAULT 10000 COMMENT '普通礼物间隔毫秒',
normal_gift_interval_min_ms BIGINT NOT NULL DEFAULT 1000 COMMENT '普通礼物最短随机间隔毫秒',
normal_gift_interval_max_ms BIGINT NOT NULL DEFAULT 20000 COMMENT '普通礼物最长随机间隔毫秒',
gift_ids_json JSON NOT NULL COMMENT '普通礼物 ID 集合',
lucky_gift_ids_json JSON NOT NULL COMMENT '幸运礼物 ID 集合',
super_lucky_gift_ids_json JSON NOT NULL COMMENT '超级幸运礼物 ID 集合',
lucky_combo_min BIGINT NOT NULL DEFAULT 1 COMMENT '幸运礼物最小连击次数',
lucky_combo_max BIGINT NOT NULL DEFAULT 3 COMMENT '幸运礼物最大连击次数',
lucky_pause_min_ms BIGINT NOT NULL DEFAULT 5000 COMMENT '幸运礼物连击后最小暂停毫秒',
lucky_pause_max_ms BIGINT NOT NULL DEFAULT 20000 COMMENT '幸运礼物连击后最大暂停毫秒',
max_gift_senders BIGINT NOT NULL DEFAULT 1 COMMENT '同一时间最多送礼机器人数量',
country_pools_json JSON NOT NULL COMMENT '国家机器人池配置',
updated_by_admin_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '最后更新管理员 ID',
created_at_ms BIGINT NOT NULL COMMENT '创建时间UTC epoch ms',
updated_at_ms BIGINT NOT NULL COMMENT '更新时间UTC epoch ms',
PRIMARY KEY (app_code),
KEY idx_room_human_robot_enabled (app_code, enabled)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='真人房间机器人行为配置表';
INSERT IGNORE INTO room_seat_configs (
app_code,
allowed_seat_counts,

View File

@ -47,6 +47,10 @@ type App struct {
walletConn *grpc.ClientConn
// activityConn 是 room outbox 事实投递到 activity-service 的 best-effort 通道。
activityConn *grpc.ClientConn
// robotConn 是真人房间机器人运行时读取全站机器人池的依赖。
robotConn *grpc.ClientConn
// userConn 是真人房间机器人运行时读取机器人国家资料的依赖。
userConn *grpc.ClientConn
// repository 是 MySQL 持久化实现,保存 meta、command log、snapshot 和 outbox。
repository *mysqlstorage.Repository
// redisClose 关闭 Redis clientRedis directory 本身不拥有额外生命周期。
@ -92,6 +96,26 @@ func New(cfg config.Config) (*App, error) {
return nil, err
}
}
robotConn, err := grpc.Dial(cfg.RobotServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
closeClientConn(activityConn)
_ = walletConn.Close()
return nil, err
}
userConn, err := grpc.Dial(cfg.UserServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
closeClientConn(robotConn)
closeClientConn(activityConn)
_ = walletConn.Close()
return nil, err
}
closeRobotDepsOnError := true
defer func() {
if closeRobotDepsOnError {
closeClientConn(userConn)
closeClientConn(robotConn)
}
}()
startupCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
@ -153,9 +177,10 @@ func New(cfg config.Config) (*App, error) {
rtcUserRemover = rtcClient
}
mqProducers := make([]*rocketmqx.Producer, 0, 2)
mqConsumers := make([]*rocketmqx.Consumer, 0, 3)
mqProducers := make([]*rocketmqx.Producer, 0, 3)
mqConsumers := make([]*rocketmqx.Consumer, 0, 4)
var rocketLaunchScheduler integration.RoomRocketLaunchScheduler
robotOutboxPublishers := make([]integration.OutboxPublisher, 0, 1)
if cfg.OutboxWorker.PublishMode == config.OutboxPublishModeDirect || cfg.OutboxWorker.PublishMode == config.OutboxPublishModeDual {
if activityConn != nil {
activityPublisher := integration.NewActivityOutboxPublisher(activityv1.NewRoomEventConsumerServiceClient(activityConn), time.Second)
@ -165,6 +190,12 @@ func New(cfg config.Config) (*App, error) {
outboxPublishers = append(outboxPublishers, tencentPublisher)
}
}
if cfg.RobotOutboxWorker.PublishMode == config.OutboxPublishModeDirect || cfg.RobotOutboxWorker.PublishMode == config.OutboxPublishModeDual {
if tencentPublisher != nil {
// 机器人展示事件只需要 IM 房间消息;不投 activity/statistics避免污染真人房间主业务链路。
robotOutboxPublishers = append(robotOutboxPublishers, tencentPublisher)
}
}
if cfg.OutboxWorker.PublishMode == config.OutboxPublishModeMQ || cfg.OutboxWorker.PublishMode == config.OutboxPublishModeDual {
outboxProducer, err := rocketmqx.NewProducer(rocketMQProducerConfig(cfg.RocketMQ, cfg.RocketMQ.RoomOutbox.ProducerGroup))
if err != nil {
@ -177,6 +208,18 @@ func New(cfg config.Config) (*App, error) {
mqProducers = append(mqProducers, outboxProducer)
outboxPublishers = append(outboxPublishers, integration.NewRocketMQOutboxPublisher(outboxProducer, cfg.RocketMQ.RoomOutbox.Topic))
}
if cfg.RobotOutboxWorker.PublishMode == config.OutboxPublishModeMQ || cfg.RobotOutboxWorker.PublishMode == config.OutboxPublishModeDual {
robotOutboxProducer, err := rocketmqx.NewProducer(rocketMQProducerConfig(cfg.RocketMQ, cfg.RocketMQ.RobotRoomOutbox.ProducerGroup))
if err != nil {
_ = repository.Close()
closeClientConn(activityConn)
_ = walletConn.Close()
_ = redisClient.Close()
return nil, err
}
mqProducers = append(mqProducers, robotOutboxProducer)
robotOutboxPublishers = append(robotOutboxPublishers, integration.NewRocketMQOutboxPublisher(robotOutboxProducer, cfg.RocketMQ.RobotRoomOutbox.Topic))
}
if cfg.RocketMQ.RocketLaunch.Enabled {
rocketProducer, err := rocketmqx.NewProducer(rocketMQProducerConfig(cfg.RocketMQ, cfg.RocketMQ.RocketLaunch.ProducerGroup))
if err != nil {
@ -190,6 +233,7 @@ func New(cfg config.Config) (*App, error) {
rocketLaunchScheduler = integration.NewRocketMQRocketLaunchScheduler(rocketProducer, cfg.RocketMQ.RocketLaunch.Topic)
}
outboxPublisher := integration.NewCompositeOutboxPublisher(outboxPublishers...)
robotOutboxPublisher := integration.NewCompositeOutboxPublisher(robotOutboxPublishers...)
var luckyGiftClient integration.LuckyGiftClient
if activityConn != nil {
luckyGiftClient = integration.NewGRPCLuckyGiftClient(activityConn)
@ -205,6 +249,8 @@ func New(cfg config.Config) (*App, error) {
MicPublishTimeout: cfg.MicPublishTimeout,
RTCUserRemover: rtcUserRemover,
RoomRocketLaunchScheduler: rocketLaunchScheduler,
RobotOutboxPublisher: robotOutboxPublisher,
HumanRobotPoolProvider: integration.NewGRPCHumanRoomRobotPoolProvider(robotConn, userConn),
RoomGiftLeaderboard: roomservice.NewRedisRoomGiftLeaderboardStore(redisClient),
LuckyGiftSendLocker: roomservice.NewRedisLuckyGiftSendLocker(redisClient),
LuckyGiftSendLockTTL: cfg.LuckyGiftSendLockTTL,
@ -264,6 +310,37 @@ func New(cfg config.Config) (*App, error) {
}
mqConsumers = append(mqConsumers, imConsumer)
}
if cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerEnabled && tencentPublisher == nil {
_ = repository.Close()
closeClientConn(activityConn)
_ = walletConn.Close()
_ = redisClient.Close()
return nil, errors.New("rocketmq robot_room_outbox tencent_im consumer requires tencent_im.enabled")
}
if cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerEnabled && tencentPublisher != nil {
robotIMConsumer, err := rocketmqx.NewConsumer(rocketMQConsumerConfig(cfg.RocketMQ, cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerGroup, cfg.RocketMQ.RobotRoomOutbox.ConsumerMaxReconsumeTimes))
if err != nil {
_ = repository.Close()
closeClientConn(activityConn)
_ = walletConn.Close()
_ = redisClient.Close()
return nil, err
}
if err := robotIMConsumer.Subscribe(cfg.RocketMQ.RobotRoomOutbox.Topic, roommq.TagRoomOutboxEvent, func(ctx context.Context, message rocketmqx.ConsumedMessage) error {
envelope, _, err := roommq.DecodeRoomOutboxMessage(message.Body)
if err != nil {
return err
}
return tencentPublisher.PublishOutboxEvent(appcode.WithContext(ctx, envelope.GetAppCode()), envelope)
}); err != nil {
_ = repository.Close()
closeClientConn(activityConn)
_ = walletConn.Close()
_ = redisClient.Close()
return nil, err
}
mqConsumers = append(mqConsumers, robotIMConsumer)
}
if cfg.RocketMQ.UserOutbox.Enabled {
userConsumer, err := rocketmqx.NewConsumer(rocketMQConsumerConfig(cfg.RocketMQ, cfg.RocketMQ.UserOutbox.ConsumerGroup, cfg.RocketMQ.UserOutbox.ConsumerMaxReconsumeTimes))
if err != nil {
@ -317,6 +394,7 @@ func New(cfg config.Config) (*App, error) {
return nil, err
}
workerCtx, workerCancel := context.WithCancel(context.Background())
closeRobotDepsOnError = false
return &App{
cfg: cfg,
@ -325,6 +403,8 @@ func New(cfg config.Config) (*App, error) {
listener: listener,
walletConn: walletConn,
activityConn: activityConn,
robotConn: robotConn,
userConn: userConn,
repository: repository,
redisClose: redisClient.Close,
nodeRegistry: directory,
@ -391,9 +471,25 @@ func (a *App) Run() error {
})
})
}
if a.cfg.RobotOutboxWorker.Enabled {
a.workerWG.Go(func() {
a.service.RunRobotOutboxWorker(a.workerCtx, roomservice.OutboxWorkerOptions{
PollInterval: a.cfg.RobotOutboxWorker.PollInterval,
BatchSize: a.cfg.RobotOutboxWorker.BatchSize,
PublishTimeout: a.cfg.RobotOutboxWorker.PublishTimeout,
RetryStrategy: a.cfg.RobotOutboxWorker.RetryStrategy,
MaxRetryCount: a.cfg.RobotOutboxWorker.MaxRetryCount,
InitialBackoff: a.cfg.RobotOutboxWorker.InitialBackoff,
MaxBackoff: a.cfg.RobotOutboxWorker.MaxBackoff,
})
})
}
a.workerWG.Go(func() {
a.service.RunRobotRoomRuntimeManager(a.workerCtx, 10*time.Second)
})
a.workerWG.Go(func() {
a.service.RunHumanRoomRobotRuntimeManager(a.workerCtx, 15*time.Second)
})
err := a.grpcServer.Serve(a.listener)
a.health.MarkGRPCStopped()
@ -435,6 +531,12 @@ func (a *App) Close() {
if a.activityConn != nil {
_ = a.activityConn.Close()
}
if a.robotConn != nil {
_ = a.robotConn.Close()
}
if a.userConn != nil {
_ = a.userConn.Close()
}
if a.repository != nil {
// MySQL 连接池最后释放,保证 GracefulStop 期间仍可完成持久化。
_ = a.repository.Close()

View File

@ -52,6 +52,10 @@ type Config struct {
WalletServiceAddr string `yaml:"wallet_service_addr"`
// ActivityServiceAddr 是房间事实事件投给 activity-service 的内部 gRPC 地址。
ActivityServiceAddr string `yaml:"activity_service_addr"`
// RobotServiceAddr 是真人房间机器人运行时读取全站机器人池的内部 gRPC 地址。
RobotServiceAddr string `yaml:"robot_service_addr"`
// UserServiceAddr 是真人房间机器人运行时按用户资料分国家的内部 gRPC 地址。
UserServiceAddr string `yaml:"user_service_addr"`
// TencentIM 是腾讯云 IM 群组和房间系统消息的外部集成配置。
TencentIM TencentIMConfig `yaml:"tencent_im"`
// TencentRTC 是平台级封禁后移出实时音频房的外部集成配置。
@ -84,6 +88,8 @@ type Config struct {
RocketMQ RocketMQConfig `yaml:"rocketmq"`
// OutboxWorker 控制 room_outbox 到腾讯云 IM 补偿投递 worker。
OutboxWorker OutboxWorkerConfig `yaml:"outbox_worker"`
// RobotOutboxWorker 控制机器人房间展示 outbox避免机器人流量抢占主 room_outbox。
RobotOutboxWorker OutboxWorkerConfig `yaml:"robot_outbox_worker"`
// Log 控制 stdout 结构化日志格式、等级和 access body 策略。
Log logx.Config `yaml:"log"`
}
@ -123,6 +129,7 @@ type RocketMQConfig struct {
SendTimeout time.Duration `yaml:"send_timeout"`
Retry int `yaml:"retry"`
RoomOutbox RoomOutboxMQConfig `yaml:"room_outbox"`
RobotRoomOutbox RoomOutboxMQConfig `yaml:"robot_room_outbox"`
RocketLaunch RocketLaunchMQConfig `yaml:"rocket_launch"`
UserOutbox UserOutboxMQConfig `yaml:"user_outbox"`
}
@ -245,6 +252,8 @@ func Default() Config {
SnapshotEveryN: 10,
WalletServiceAddr: "127.0.0.1:13004",
ActivityServiceAddr: "127.0.0.1:13006",
RobotServiceAddr: "127.0.0.1:13011",
UserServiceAddr: "127.0.0.1:13005",
TencentIM: TencentIMConfig{
Enabled: false,
AdminIdentifier: "administrator",
@ -272,6 +281,7 @@ func Default() Config {
RoomRocketLaunchScanInterval: time.Second,
RocketMQ: defaultRocketMQConfig(),
OutboxWorker: defaultOutboxWorkerConfig(),
RobotOutboxWorker: defaultOutboxWorkerConfig(),
Log: logx.Config{
Level: "info",
Format: "json",
@ -308,6 +318,14 @@ func defaultRocketMQConfig() RocketMQConfig {
TencentIMConsumerGroup: "hyapp-room-im-bridge",
ConsumerMaxReconsumeTimes: 16,
},
RobotRoomOutbox: RoomOutboxMQConfig{
Enabled: false,
Topic: "hyapp_robot_room_outbox",
ProducerGroup: "hyapp-room-robot-outbox-producer",
TencentIMConsumerEnabled: false,
TencentIMConsumerGroup: "hyapp-room-robot-im-bridge",
ConsumerMaxReconsumeTimes: 16,
},
RocketLaunch: RocketLaunchMQConfig{
Enabled: false,
Topic: "hyapp_room_rocket_launch",
@ -377,6 +395,14 @@ func Normalize(cfg Config) (Config, error) {
if cfg.ActivityServiceAddr == "" {
cfg.ActivityServiceAddr = "127.0.0.1:13006"
}
cfg.RobotServiceAddr = strings.TrimSpace(cfg.RobotServiceAddr)
if cfg.RobotServiceAddr == "" {
cfg.RobotServiceAddr = "127.0.0.1:13011"
}
cfg.UserServiceAddr = strings.TrimSpace(cfg.UserServiceAddr)
if cfg.UserServiceAddr == "" {
cfg.UserServiceAddr = "127.0.0.1:13005"
}
cfg.TencentRTC.SecretID = strings.TrimSpace(cfg.TencentRTC.SecretID)
cfg.TencentRTC.SecretKey = strings.TrimSpace(cfg.TencentRTC.SecretKey)
cfg.TencentRTC.Region = strings.TrimSpace(cfg.TencentRTC.Region)
@ -395,7 +421,12 @@ func Normalize(cfg Config) (Config, error) {
return Config{}, err
}
cfg.OutboxWorker = outboxWorker
rocketMQ, err := normalizeRocketMQConfig(cfg.RocketMQ, cfg.OutboxWorker.PublishMode)
robotOutboxWorker, err := normalizeOutboxWorkerConfig(cfg.RobotOutboxWorker)
if err != nil {
return Config{}, err
}
cfg.RobotOutboxWorker = robotOutboxWorker
rocketMQ, err := normalizeRocketMQConfig(cfg.RocketMQ, cfg.OutboxWorker.PublishMode, cfg.RobotOutboxWorker.PublishMode)
if err != nil {
return Config{}, err
}
@ -462,7 +493,7 @@ func normalizeOutboxWorkerConfig(cfg OutboxWorkerConfig) (OutboxWorkerConfig, er
return cfg, nil
}
func normalizeRocketMQConfig(cfg RocketMQConfig, publishMode string) (RocketMQConfig, error) {
func normalizeRocketMQConfig(cfg RocketMQConfig, publishMode string, robotPublishMode string) (RocketMQConfig, error) {
defaults := defaultRocketMQConfig()
cfg.NameServers = normalizeStringSlice(cfg.NameServers)
cfg.NameServerDomain = strings.TrimSpace(cfg.NameServerDomain)
@ -488,6 +519,18 @@ func normalizeRocketMQConfig(cfg RocketMQConfig, publishMode string) (RocketMQCo
if cfg.RoomOutbox.ConsumerMaxReconsumeTimes <= 0 {
cfg.RoomOutbox.ConsumerMaxReconsumeTimes = defaults.RoomOutbox.ConsumerMaxReconsumeTimes
}
if cfg.RobotRoomOutbox.Topic = strings.TrimSpace(cfg.RobotRoomOutbox.Topic); cfg.RobotRoomOutbox.Topic == "" {
cfg.RobotRoomOutbox.Topic = defaults.RobotRoomOutbox.Topic
}
if cfg.RobotRoomOutbox.ProducerGroup = strings.TrimSpace(cfg.RobotRoomOutbox.ProducerGroup); cfg.RobotRoomOutbox.ProducerGroup == "" {
cfg.RobotRoomOutbox.ProducerGroup = defaults.RobotRoomOutbox.ProducerGroup
}
if cfg.RobotRoomOutbox.TencentIMConsumerGroup = strings.TrimSpace(cfg.RobotRoomOutbox.TencentIMConsumerGroup); cfg.RobotRoomOutbox.TencentIMConsumerGroup == "" {
cfg.RobotRoomOutbox.TencentIMConsumerGroup = defaults.RobotRoomOutbox.TencentIMConsumerGroup
}
if cfg.RobotRoomOutbox.ConsumerMaxReconsumeTimes <= 0 {
cfg.RobotRoomOutbox.ConsumerMaxReconsumeTimes = defaults.RobotRoomOutbox.ConsumerMaxReconsumeTimes
}
if cfg.RocketLaunch.Topic = strings.TrimSpace(cfg.RocketLaunch.Topic); cfg.RocketLaunch.Topic == "" {
cfg.RocketLaunch.Topic = defaults.RocketLaunch.Topic
}
@ -509,7 +552,7 @@ func normalizeRocketMQConfig(cfg RocketMQConfig, publishMode string) (RocketMQCo
if cfg.UserOutbox.ConsumerMaxReconsumeTimes <= 0 {
cfg.UserOutbox.ConsumerMaxReconsumeTimes = defaults.UserOutbox.ConsumerMaxReconsumeTimes
}
if cfg.RoomOutbox.Enabled || cfg.RocketLaunch.Enabled || cfg.UserOutbox.Enabled || cfg.RoomOutbox.TencentIMConsumerEnabled {
if cfg.RoomOutbox.Enabled || cfg.RobotRoomOutbox.Enabled || cfg.RocketLaunch.Enabled || cfg.UserOutbox.Enabled || cfg.RoomOutbox.TencentIMConsumerEnabled || cfg.RobotRoomOutbox.TencentIMConsumerEnabled {
cfg.Enabled = true
}
if publishMode == OutboxPublishModeMQ || publishMode == OutboxPublishModeDual {
@ -517,6 +560,11 @@ func normalizeRocketMQConfig(cfg RocketMQConfig, publishMode string) (RocketMQCo
return RocketMQConfig{}, fmt.Errorf("outbox_worker publish_mode %q requires rocketmq.room_outbox.enabled", publishMode)
}
}
if robotPublishMode == OutboxPublishModeMQ || robotPublishMode == OutboxPublishModeDual {
if !cfg.RobotRoomOutbox.Enabled {
return RocketMQConfig{}, fmt.Errorf("robot_outbox_worker publish_mode %q requires rocketmq.robot_room_outbox.enabled", robotPublishMode)
}
}
if cfg.Enabled {
if len(cfg.NameServers) == 0 && cfg.NameServerDomain == "" {
return RocketMQConfig{}, fmt.Errorf("rocketmq name_servers or name_server_domain is required")

View File

@ -34,13 +34,22 @@ func TestLoad(t *testing.T) {
if cfg.WalletServiceAddr != "127.0.0.1:13004" {
t.Fatalf("unexpected wallet addr: %s", cfg.WalletServiceAddr)
}
if cfg.TencentIM.SDKAppID != 20040101 || cfg.TencentIM.SecretKey == "" || cfg.TencentIM.AdminIdentifier != "administrator" {
t.Fatalf("local room-service must use test Tencent IM account: %+v", cfg.TencentIM)
}
if !cfg.OutboxWorker.Enabled || cfg.OutboxWorker.PublishMode != OutboxPublishModeMQ || cfg.OutboxWorker.PollInterval != time.Second || cfg.OutboxWorker.BatchSize != 100 || cfg.OutboxWorker.PublishTimeout != 3*time.Second || cfg.OutboxWorker.RetryStrategy != "exponential_backoff" || cfg.OutboxWorker.MaxRetryCount != 10 || cfg.OutboxWorker.InitialBackoff != 5*time.Second || cfg.OutboxWorker.MaxBackoff != 5*time.Minute {
t.Fatalf("unexpected outbox worker config: %+v", cfg.OutboxWorker)
}
if !cfg.RobotOutboxWorker.Enabled || cfg.RobotOutboxWorker.PublishMode != OutboxPublishModeMQ || cfg.RobotOutboxWorker.PollInterval != time.Second || cfg.RobotOutboxWorker.BatchSize != 30 || cfg.RobotOutboxWorker.PublishTimeout != 3*time.Second || cfg.RobotOutboxWorker.RetryStrategy != "exponential_backoff" || cfg.RobotOutboxWorker.MaxRetryCount != 10 || cfg.RobotOutboxWorker.InitialBackoff != 5*time.Second || cfg.RobotOutboxWorker.MaxBackoff != 5*time.Minute {
t.Fatalf("unexpected robot outbox worker config: %+v", cfg.RobotOutboxWorker)
}
// 本地默认也走 room_outbox MQ、IM bridge 和火箭延迟唤醒,避免本地直投和线上 MQ 语义分叉。
if !cfg.RocketMQ.Enabled || !cfg.RocketMQ.RoomOutbox.Enabled || !cfg.RocketMQ.RoomOutbox.TencentIMConsumerEnabled || !cfg.RocketMQ.RocketLaunch.Enabled || !cfg.RocketMQ.UserOutbox.Enabled {
if !cfg.RocketMQ.Enabled || !cfg.RocketMQ.RoomOutbox.Enabled || !cfg.RocketMQ.RoomOutbox.TencentIMConsumerEnabled || !cfg.RocketMQ.RobotRoomOutbox.Enabled || !cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerEnabled || !cfg.RocketMQ.RocketLaunch.Enabled || !cfg.RocketMQ.UserOutbox.Enabled {
t.Fatalf("local config must enable room MQ fanout and IM bridge: %+v", cfg.RocketMQ)
}
if cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerGroup != "hyapp-test-room-robot-im-bridge" {
t.Fatalf("local robot IM bridge group mismatch: %s", cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerGroup)
}
}
// TestLoadTencentExample 验证线上腾讯云 IM 模板能覆盖本地默认配置。
@ -71,9 +80,15 @@ func TestLoadTencentExample(t *testing.T) {
if !cfg.OutboxWorker.Enabled || cfg.OutboxWorker.RetryStrategy != "exponential_backoff" || cfg.OutboxWorker.MaxRetryCount != 10 {
t.Fatalf("tencent example must configure outbox worker: %+v", cfg.OutboxWorker)
}
if cfg.OutboxWorker.PublishMode != OutboxPublishModeMQ || !cfg.RocketMQ.RoomOutbox.Enabled || !cfg.RocketMQ.RocketLaunch.Enabled {
if !cfg.RobotOutboxWorker.Enabled || cfg.RobotOutboxWorker.PublishMode != OutboxPublishModeMQ || cfg.RobotOutboxWorker.BatchSize != 30 {
t.Fatalf("tencent example must configure robot outbox worker: %+v", cfg.RobotOutboxWorker)
}
if cfg.OutboxWorker.PublishMode != OutboxPublishModeMQ || !cfg.RocketMQ.RoomOutbox.Enabled || !cfg.RocketMQ.RobotRoomOutbox.Enabled || !cfg.RocketMQ.RocketLaunch.Enabled {
t.Fatalf("tencent example must route room outbox and rocket launch through RocketMQ: mode=%s mq=%+v", cfg.OutboxWorker.PublishMode, cfg.RocketMQ)
}
if cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerGroup != "hyapp-room-robot-im-bridge" {
t.Fatalf("prod robot IM bridge group mismatch: %s", cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerGroup)
}
}
func TestLoadDockerConfigStartsRoomIMBridgeWhenOutboxUsesMQ(t *testing.T) {
@ -91,6 +106,12 @@ func TestLoadDockerConfigStartsRoomIMBridgeWhenOutboxUsesMQ(t *testing.T) {
if !cfg.RocketMQ.RoomOutbox.TencentIMConsumerEnabled {
t.Fatalf("docker mq room outbox must start Tencent IM bridge consumer")
}
if cfg.RobotOutboxWorker.PublishMode != OutboxPublishModeMQ || !cfg.RocketMQ.RobotRoomOutbox.Enabled || !cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerEnabled {
t.Fatalf("docker config must start robot outbox MQ and IM bridge: worker=%+v mq=%+v", cfg.RobotOutboxWorker, cfg.RocketMQ.RobotRoomOutbox)
}
if cfg.TencentIM.SDKAppID != 20040101 || cfg.TencentIM.AdminIdentifier != "administrator" || cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerGroup != "hyapp-test-room-robot-im-bridge" {
t.Fatalf("docker config must use test IM account and robot group: im=%+v group=%s", cfg.TencentIM, cfg.RocketMQ.RobotRoomOutbox.TencentIMConsumerGroup)
}
if !cfg.TencentIM.Enabled {
t.Fatalf("Tencent IM bridge consumer requires tencent_im.enabled")
}

View File

@ -0,0 +1,141 @@
package integration
import (
"context"
"fmt"
"sort"
"strings"
"time"
"google.golang.org/grpc"
robotv1 "hyapp.local/api/proto/robot/v1"
userv1 "hyapp.local/api/proto/user/v1"
"hyapp/pkg/appcode"
)
const humanRobotPoolPageSize = int32(200)
// HumanRoomRobotPool 是真人房间机器人运行时按国家分组后的账号池。
type HumanRoomRobotPool struct {
CountryCode string
RobotUserIDs []int64
}
// HumanRoomRobotPoolProvider 屏蔽 robot-service 和 user-service 的组合查询细节。
type HumanRoomRobotPoolProvider interface {
ListHumanRoomRobotPools(ctx context.Context, appCode string) ([]HumanRoomRobotPool, error)
}
type GRPCHumanRoomRobotPoolProvider struct {
robots robotv1.GameRobotServiceClient
users userv1.UserServiceClient
}
func NewGRPCHumanRoomRobotPoolProvider(robotConn grpc.ClientConnInterface, userConn grpc.ClientConnInterface) *GRPCHumanRoomRobotPoolProvider {
return &GRPCHumanRoomRobotPoolProvider{
robots: robotv1.NewGameRobotServiceClient(robotConn),
users: userv1.NewUserServiceClient(userConn),
}
}
func (p *GRPCHumanRoomRobotPoolProvider) ListHumanRoomRobotPools(ctx context.Context, appCode string) ([]HumanRoomRobotPool, error) {
if p == nil || p.robots == nil || p.users == nil {
return nil, fmt.Errorf("human room robot pool provider is not configured")
}
app := appcode.Normalize(appCode)
userIDs, err := p.listActiveRobotUserIDs(ctx, app)
if err != nil {
return nil, err
}
if len(userIDs) == 0 {
return nil, nil
}
groups := make(map[string][]int64)
for start := 0; start < len(userIDs); start += int(humanRobotPoolPageSize) {
end := start + int(humanRobotPoolPageSize)
if end > len(userIDs) {
end = len(userIDs)
}
resp, err := p.users.BatchGetUsers(ctx, &userv1.BatchGetUsersRequest{
Meta: userRequestMeta(app, "room-human-robot-users"),
UserIds: userIDs[start:end],
})
if err != nil {
return nil, err
}
for _, userID := range userIDs[start:end] {
user := resp.GetUsers()[userID]
countryCode := normalizePoolCountryCode(user.GetCountry())
if countryCode == "" {
continue
}
groups[countryCode] = append(groups[countryCode], userID)
}
}
pools := make([]HumanRoomRobotPool, 0, len(groups))
for countryCode, ids := range groups {
pools = append(pools, HumanRoomRobotPool{CountryCode: countryCode, RobotUserIDs: ids})
}
sort.Slice(pools, func(i, j int) bool { return pools[i].CountryCode < pools[j].CountryCode })
return pools, nil
}
func (p *GRPCHumanRoomRobotPoolProvider) listActiveRobotUserIDs(ctx context.Context, app string) ([]int64, error) {
userIDs := make([]int64, 0, humanRobotPoolPageSize)
cursor := ""
for {
resp, err := p.robots.ListGameRobots(ctx, &robotv1.ListGameRobotsRequest{
Meta: robotRequestMeta(app, "room-human-robot-pool"),
Status: "active",
PageSize: humanRobotPoolPageSize,
Cursor: cursor,
})
if err != nil {
return nil, err
}
for _, robot := range resp.GetRobots() {
if robot.GetUserId() > 0 {
userIDs = append(userIDs, robot.GetUserId())
}
}
cursor = strings.TrimSpace(resp.GetNextCursor())
if cursor == "" {
return uniquePositiveInt64(userIDs), nil
}
}
}
func robotRequestMeta(appCode string, requestID string) *robotv1.RequestMeta {
return &robotv1.RequestMeta{
RequestId: requestID,
Caller: "room-service",
AppCode: appcode.Normalize(appCode),
SentAtMs: time.Now().UTC().UnixMilli(),
}
}
func userRequestMeta(appCode string, requestID string) *userv1.RequestMeta {
return &userv1.RequestMeta{
RequestId: requestID,
Caller: "room-service",
AppCode: appcode.Normalize(appCode),
SentAtMs: time.Now().UTC().UnixMilli(),
}
}
func normalizePoolCountryCode(value string) string {
return strings.ToUpper(strings.TrimSpace(value))
}
func uniquePositiveInt64(values []int64) []int64 {
seen := make(map[int64]bool, len(values))
out := make([]int64, 0, len(values))
for _, value := range values {
if value <= 0 || seen[value] {
continue
}
seen[value] = true
out = append(out, value)
}
return out
}

View File

@ -315,6 +315,33 @@ func roomEventFromEnvelope(envelope *roomeventsv1.EventEnvelope) (tencentim.Room
"gift_effect_types": string(effectTypesJSON),
}
return base, true, nil
case "RoomHeatChanged":
// 机器人通道也会投递热度展示事件,客户端可独立刷新房间热度,不依赖主 outbox。
var body roomeventsv1.RoomHeatChanged
if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil {
return tencentim.RoomEvent{}, false, err
}
base.RoomHeat = body.GetCurrentHeat()
base.Attributes = map[string]string{
"delta": fmt.Sprintf("%d", body.GetDelta()),
"room_heat": fmt.Sprintf("%d", body.GetCurrentHeat()),
}
return base, true, nil
case "RoomRankChanged":
// 麦位收礼热度属于房间内展示数据;机器人事件只在 robot outbox 内广播。
var body roomeventsv1.RoomRankChanged
if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil {
return tencentim.RoomEvent{}, false, err
}
base.ActorUserID = body.GetUserId()
base.TargetUserID = body.GetUserId()
base.GiftValue = body.GetGiftValue()
base.Attributes = map[string]string{
"user_id": fmt.Sprintf("%d", body.GetUserId()),
"score": fmt.Sprintf("%d", body.GetScore()),
"gift_value": fmt.Sprintf("%d", body.GetGiftValue()),
}
return base, true, nil
case "RoomRobotLuckyGiftDrawn":
// 机器人幸运礼物只发房间展示协议,不进入 activity-service 真实抽奖和奖池链路。
var body roomeventsv1.RoomRobotLuckyGiftDrawn
@ -471,6 +498,10 @@ func eventTypeForClient(eventType string) string {
return "room_user_unbanned"
case "RoomGiftSent":
return "room_gift_sent"
case "RoomHeatChanged":
return "room_heat_changed"
case "RoomRankChanged":
return "room_rank_changed"
case "RoomRobotLuckyGiftDrawn":
return "lucky_gift_drawn"
case "RoomRocketFuelChanged":

View File

@ -113,6 +113,76 @@ func TestRoomGiftSentCarriesTargetGiftValueInIMAttributes(t *testing.T) {
}
}
func TestRoomHeatAndRankChangedPublishDisplayIMEvents(t *testing.T) {
heatRecord, err := outbox.Build("room-robot-heat", "RoomHeatChanged", 9, time.Now(), &roomeventsv1.RoomHeatChanged{
Delta: 120,
CurrentHeat: 880,
})
if err != nil {
t.Fatalf("Build RoomHeatChanged envelope failed: %v", err)
}
heatEvent, publish, err := roomEventFromEnvelope(heatRecord.Envelope)
if err != nil {
t.Fatalf("RoomHeatChanged should decode: %v", err)
}
if !publish || heatEvent.EventType != "room_heat_changed" || heatEvent.RoomHeat != 880 || heatEvent.Attributes["delta"] != "120" {
t.Fatalf("heat IM event mismatch: publish=%t event=%+v", publish, heatEvent)
}
rankRecord, err := outbox.Build("room-robot-rank", "RoomRankChanged", 10, time.Now(), &roomeventsv1.RoomRankChanged{
UserId: 1002,
Score: 360,
GiftValue: 360,
})
if err != nil {
t.Fatalf("Build RoomRankChanged envelope failed: %v", err)
}
rankEvent, publish, err := roomEventFromEnvelope(rankRecord.Envelope)
if err != nil {
t.Fatalf("RoomRankChanged should decode: %v", err)
}
if !publish || rankEvent.EventType != "room_rank_changed" || rankEvent.TargetUserID != 1002 || rankEvent.GiftValue != 360 || rankEvent.Attributes["score"] != "360" {
t.Fatalf("rank IM event mismatch: publish=%t event=%+v", publish, rankEvent)
}
}
func TestRoomRobotLuckyGiftDrawnPublishesLuckyGiftIMEvent(t *testing.T) {
record, err := outbox.Build("room-robot-lucky", "RoomRobotLuckyGiftDrawn", 11, time.Now(), &roomeventsv1.RoomRobotLuckyGiftDrawn{
DrawId: "robot_lucky_draw_1",
CommandId: "cmd_robot_lucky_1",
SenderUserId: 1001,
TargetUserId: 1002,
GiftId: "gift_lucky_1",
GiftCount: 1,
PoolId: "robot_lucky_display",
MultiplierPpm: 5000000,
BaseRewardCoins: 500,
EffectiveRewardCoins: 500,
CreatedAtMs: 1778000000000,
VisibleRegionId: 86,
IsRobot: true,
Synthetic: true,
})
if err != nil {
t.Fatalf("Build RoomRobotLuckyGiftDrawn envelope failed: %v", err)
}
event, publish, err := roomEventFromEnvelope(record.Envelope)
if err != nil {
t.Fatalf("RoomRobotLuckyGiftDrawn should decode: %v", err)
}
if !publish || event.EventType != "lucky_gift_drawn" || event.ActorUserID != 1001 || event.TargetUserID != 1002 {
t.Fatalf("robot lucky gift IM event mismatch: publish=%t event=%+v", publish, event)
}
if event.Attributes["draw_id"] != "robot_lucky_draw_1" ||
event.Attributes["gift_id"] != "gift_lucky_1" ||
event.Attributes["pool_id"] != "robot_lucky_display" ||
event.Attributes["effective_reward_coins"] != "500" ||
event.Attributes["reward_status"] != "granted" {
t.Fatalf("robot lucky gift IM attributes mismatch: %+v", event.Attributes)
}
}
func TestRoomMicChangedCarriesTargetGiftValueInIMAttributes(t *testing.T) {
record, err := outbox.Build("room-mic-value", "RoomMicChanged", 9, time.Now(), &roomeventsv1.RoomMicChanged{
ActorUserId: 1001,

View File

@ -476,6 +476,8 @@ type SendGift struct {
RocketCurrentContributions []RocketContribution `json:"rocket_current_contributions,omitempty"`
// RobotGift 表示本次礼物只服务机器人房间展示;不写真实统计、任务、周星和房间贡献榜。
RobotGift bool `json:"robot_gift,omitempty"`
// RobotWalletGift 表示本次礼物由机器人钱包结算;真人房间机器人可以用它贡献真实房间热度。
RobotWalletGift bool `json:"robot_wallet_gift,omitempty"`
// SyntheticLuckyGift 表示幸运礼物只生成展示事件,不调用真实 activity 抽奖和奖池。
SyntheticLuckyGift bool `json:"synthetic_lucky_gift,omitempty"`
// SyntheticLuckyRewardCoins 是机器人幸运礼物展示用爆奖金币值,不代表真实钱包返奖。

View File

@ -7,6 +7,7 @@ import (
"math/rand"
"slices"
"strings"
"sync"
"time"
roomv1 "hyapp.local/api/proto/room/v1"
@ -21,6 +22,16 @@ const (
robotRoomStatusStopped = "stopped"
robotRoomMode = "voice"
robotRoomLuckyPoolID = "robot_lucky_display"
maxRobotLuckyComboPerCycle = int64(3)
defaultRobotStayMinMS = int64(3 * 60 * 1000)
defaultRobotStayMaxMS = int64(10 * 60 * 1000)
defaultRobotReplaceMinMS = int64(0)
defaultRobotReplaceMaxMS = int64(60 * 1000)
defaultMaxGiftSenders = int64(1)
defaultRobotRoomSeatCount = int32(10)
)
func (s *Service) AdminListRobotRooms(ctx context.Context, req *roomv1.AdminListRobotRoomsRequest) (*roomv1.AdminListRobotRoomsResponse, error) {
@ -152,11 +163,15 @@ func (s *Service) buildRobotRoomConfig(ctx context.Context, req *roomv1.AdminCre
if selectedCount > len(available) {
selectedCount = len(available)
}
selected := selectRobotUsers(rng, ownerID, available, selectedCount)
robotPool := selectRobotUsers(rng, ownerID, available, len(available))
rule, err := normalizeRobotRoomGiftRule(req.GetGiftRule())
if err != nil {
return RobotRoomConfig{}, err
}
seatCount := normalizeRobotRoomSeatCount(req.GetSeatCount())
if seatCount <= 0 {
return RobotRoomConfig{}, xerr.New(xerr.InvalidArgument, "robot room seat_count is invalid")
}
roomID := fmt.Sprintf("robot_%d_%d", now.UnixMilli(), rng.Intn(900000)+100000)
if !roomid.ValidStringID(roomID) {
return RobotRoomConfig{}, xerr.New(xerr.Internal, "generated robot room id is invalid")
@ -176,9 +191,12 @@ func (s *Service) buildRobotRoomConfig(ctx context.Context, req *roomv1.AdminCre
Title: title,
CoverURL: coverURL,
VisibleRegionID: normalizeVisibleRegionID(req.GetVisibleRegionId()),
OwnerCountryCode: normalizeRoomCountryCode(req.GetOwnerCountryCode()),
Status: robotRoomStatusActive,
OwnerRobotUserID: ownerID,
RobotUserIDs: selected,
RobotUserIDs: robotPool,
ActiveRobotCount: int32(selectedCount),
SeatCount: seatCount,
GiftRule: rule,
CreatedByAdminID: req.GetAdminId(),
CreatedAtMS: now.UnixMilli(),
@ -187,6 +205,7 @@ func (s *Service) buildRobotRoomConfig(ctx context.Context, req *roomv1.AdminCre
}
func (s *Service) bootstrapRobotRoom(ctx context.Context, config RobotRoomConfig) error {
activeIDs := robotRoomInitialActiveIDs(config)
_, err := s.CreateRoom(ctx, &roomv1.CreateRoomRequest{
Meta: &roomv1.RequestMeta{
RequestId: fmt.Sprintf("admin-robot-room-create-%s", config.RoomID),
@ -196,19 +215,20 @@ func (s *Service) bootstrapRobotRoom(ctx context.Context, config RobotRoomConfig
AppCode: config.AppCode,
SentAtMs: s.clock.Now().UnixMilli(),
},
SeatCount: int32(max(10, len(config.RobotUserIDs))),
Mode: robotRoomMode,
VisibleRegionId: config.VisibleRegionID,
RoomName: config.Title,
RoomAvatar: config.CoverURL,
RoomShortId: config.RoomShortID,
RobotRoom: true,
RobotUserIds: config.RobotUserIDs,
SeatCount: config.SeatCount,
Mode: robotRoomMode,
VisibleRegionId: config.VisibleRegionID,
OwnerCountryCode: config.OwnerCountryCode,
RoomName: config.Title,
RoomAvatar: config.CoverURL,
RoomShortId: config.RoomShortID,
RobotRoom: true,
RobotUserIds: config.RobotUserIDs,
})
if err != nil {
return err
}
for _, userID := range config.RobotUserIDs {
for _, userID := range activeIDs {
if userID == config.OwnerRobotUserID {
continue
}
@ -219,7 +239,7 @@ func (s *Service) bootstrapRobotRoom(ctx context.Context, config RobotRoomConfig
return err
}
}
for index, userID := range config.RobotUserIDs {
for index, userID := range activeIDs {
if _, err := s.RobotVirtualMicUp(ctx, RobotMicUpInput{
Meta: robotRoomCommandMeta(config, config.OwnerRobotUserID, fmt.Sprintf("mic:%d", userID)),
TargetUserID: userID,
@ -236,6 +256,7 @@ func (s *Service) RunRobotRoomRuntimeManager(ctx context.Context, interval time.
if interval <= 0 {
interval = 10 * time.Second
}
logx.Info(ctx, "robot_room_runtime_manager_started", slog.Int64("interval_ms", interval.Milliseconds()))
ticker := time.NewTicker(interval)
defer ticker.Stop()
s.startActiveRobotRooms(ctx)
@ -256,6 +277,7 @@ func (s *Service) startActiveRobotRooms(ctx context.Context) {
logx.Warn(ctx, "robot_room_runtime_scan_failed", slog.String("error", err.Error()))
return
}
logx.Info(ctx, "robot_room_runtime_scan_completed", slog.Int("active_room_count", len(configs)))
for _, config := range configs {
s.startRobotRoomRuntime(ctx, config)
}
@ -263,37 +285,79 @@ func (s *Service) startActiveRobotRooms(ctx context.Context) {
func (s *Service) startRobotRoomRuntime(parent context.Context, config RobotRoomConfig) {
if config.Status != robotRoomStatusActive || len(config.RobotUserIDs) < 2 {
logx.Info(parent, "robot_room_runtime_start_skipped",
slog.String("room_id", config.RoomID),
slog.String("status", config.Status),
slog.Int("robot_count", len(config.RobotUserIDs)),
)
return
}
if err := parent.Err(); err != nil {
// 管理端创建/启停请求的 ctx 会随 HTTP/gRPC 请求结束而取消;已取消的 ctx 不能写入
// runtime map否则后台恢复扫描会误以为该房间仍在运行。
logx.Warn(parent, "robot_room_runtime_parent_cancelled", slog.String("room_id", config.RoomID), slog.String("error", err.Error()))
return
}
s.robotRuntimeMu.Lock()
if s.robotRuntimes == nil {
s.robotRuntimes = make(map[string]context.CancelFunc)
s.robotRuntimes = make(map[string]robotRoomRuntime)
}
if _, exists := s.robotRuntimes[config.RoomID]; exists {
s.robotRuntimeMu.Unlock()
logx.Info(parent, "robot_room_runtime_start_skipped",
slog.String("room_id", config.RoomID),
slog.String("status", config.Status),
slog.Int("robot_count", len(config.RobotUserIDs)),
slog.String("reason", "already_running"),
)
return
}
s.robotRuntimeMu.Unlock()
if err := s.ensureRobotRoomParticipants(parent, config); err != nil {
logx.Warn(parent, "robot_room_runtime_prepare_failed", slog.String("room_id", config.RoomID), slog.String("error", err.Error()))
return
}
s.robotRuntimeMu.Lock()
if _, exists := s.robotRuntimes[config.RoomID]; exists {
s.robotRuntimeMu.Unlock()
return
}
ctx, cancel := context.WithCancel(appcode.WithContext(parent, config.AppCode))
s.robotRuntimes[config.RoomID] = cancel
token := fmt.Sprintf("%s:%d", config.RoomID, time.Now().UTC().UnixNano())
s.robotRuntimes[config.RoomID] = robotRoomRuntime{cancel: cancel, token: token}
s.robotRuntimeMu.Unlock()
go s.runRobotRoomRuntime(ctx, config)
logx.Info(ctx, "robot_room_runtime_started",
slog.String("room_id", config.RoomID),
slog.Int64("owner_robot_user_id", config.OwnerRobotUserID),
slog.Int("robot_count", len(config.RobotUserIDs)),
slog.Int("normal_gift_count", len(config.GiftRule.GiftIDs)),
slog.Int("lucky_gift_count", len(config.GiftRule.LuckyGiftIDs)),
)
go func() {
defer s.clearRobotRoomRuntime(config.RoomID, token)
s.runRobotRoomRuntime(ctx, config)
}()
}
func (s *Service) stopRobotRoomRuntime(roomID string) {
s.robotRuntimeMu.Lock()
cancel := s.robotRuntimes[roomID]
runtime := s.robotRuntimes[roomID]
delete(s.robotRuntimes, roomID)
s.robotRuntimeMu.Unlock()
if cancel != nil {
cancel()
if runtime.cancel != nil {
runtime.cancel()
}
}
func (s *Service) stopAllRobotRoomRuntimes() {
s.robotRuntimeMu.Lock()
cancels := make([]context.CancelFunc, 0, len(s.robotRuntimes))
for roomID, cancel := range s.robotRuntimes {
cancels = append(cancels, cancel)
for roomID, runtime := range s.robotRuntimes {
if runtime.cancel != nil {
cancels = append(cancels, runtime.cancel)
}
delete(s.robotRuntimes, roomID)
}
s.robotRuntimeMu.Unlock()
@ -302,16 +366,158 @@ func (s *Service) stopAllRobotRoomRuntimes() {
}
}
func (s *Service) clearRobotRoomRuntime(roomID string, token string) {
s.robotRuntimeMu.Lock()
defer s.robotRuntimeMu.Unlock()
runtime, exists := s.robotRuntimes[roomID]
if !exists || runtime.token != token {
return
}
delete(s.robotRuntimes, roomID)
}
func (s *Service) ensureRobotRoomParticipants(ctx context.Context, config RobotRoomConfig) error {
roomCtx := appcode.WithContext(ctx, config.AppCode)
snapshot, err := s.currentSnapshot(roomCtx, config.RoomID)
if err != nil {
return err
}
online := make(map[int64]bool, len(snapshot.GetOnlineUsers()))
for _, user := range snapshot.GetOnlineUsers() {
online[user.GetUserId()] = true
}
activeTarget := robotRoomActiveTarget(config)
activeRobots := onlineRobotIDs(config.RobotUserIDs, online)
missing := activeTarget - len(activeRobots)
if missing > 0 {
for _, userID := range robotRoomFillCandidates(config, online, missing) {
// active 机器人房从持久化配置恢复时,旧进程可能已经把机器人 stale 成 left
// 这里只补齐后台配置的活跃人数,不再把整个候选池一次性塞回房间。
if err := s.joinRobotRoomUser(roomCtx, config, userID, 0, fmt.Sprintf("runtime-join:%d:%d", userID, time.Now().UTC().UnixNano())); err != nil {
return err
}
online[userID] = true
activeRobots = append(activeRobots, userID)
}
}
snapshot, err = s.currentSnapshot(roomCtx, config.RoomID)
if err != nil {
return err
}
seated := make(map[int64]bool, len(config.RobotUserIDs))
occupiedSeats := make(map[int32]bool, len(snapshot.GetMicSeats()))
for _, seat := range snapshot.GetMicSeats() {
userID := seat.GetUserId()
if userID > 0 {
seated[userID] = true
occupiedSeats[seat.GetSeatNo()] = true
}
}
for _, userID := range activeRobots {
if userID <= 0 || seated[userID] {
continue
}
seatNo := preferredRobotSeatNo(config, userID)
if occupiedSeats[seatNo] {
seatNo = firstFreeRobotSeatNo(snapshot.GetMicSeats(), activeTarget)
if seatNo <= 0 {
logx.Warn(roomCtx, "robot_room_runtime_mic_restore_skipped", slog.String("room_id", config.RoomID), slog.Int64("robot_user_id", userID), slog.String("reason", "no_free_seat"))
continue
}
}
// 虚拟麦位只服务机器人房展示若并发恢复导致机器人已上麦Conflict 可视为达成目标。
if _, err := s.RobotVirtualMicUp(roomCtx, RobotMicUpInput{
Meta: robotRoomCommandMeta(config, config.OwnerRobotUserID, fmt.Sprintf("runtime-mic:%d:%d", userID, time.Now().UTC().UnixNano())),
TargetUserID: userID,
SeatNo: seatNo,
}); err != nil {
if xerr.CodeOf(err) == xerr.Conflict && strings.Contains(xerr.MessageOf(err), "already on seat") {
continue
}
return err
}
occupiedSeats[seatNo] = true
}
return nil
}
func (s *Service) runRobotRoomRuntime(ctx context.Context, config RobotRoomConfig) {
activity := newRobotRoomActivity(config.RobotUserIDs)
if snapshot, err := s.currentSnapshot(appcode.WithContext(ctx, config.AppCode), config.RoomID); err == nil {
for _, user := range snapshot.GetOnlineUsers() {
if robotRoomHasUser(config.RobotUserIDs, user.GetUserId()) {
activity.markActive(user.GetUserId())
}
}
}
giftSlots := make(chan struct{}, robotRoomMaxGiftSenders(config))
for _, senderID := range config.RobotUserIDs {
senderID := senderID
go s.runRobotNormalGiftLoop(ctx, config, senderID)
go s.runRobotLuckyGiftLoop(ctx, config, senderID)
go s.runRobotPresenceLoop(ctx, config, activity, senderID)
go s.runRobotNormalGiftLoop(ctx, config, activity, giftSlots, senderID)
go s.runRobotLuckyGiftLoop(ctx, config, activity, giftSlots, senderID)
}
<-ctx.Done()
}
func (s *Service) runRobotNormalGiftLoop(ctx context.Context, config RobotRoomConfig, senderID int64) {
func (s *Service) runRobotPresenceLoop(ctx context.Context, config RobotRoomConfig, activity *robotRoomActivity, userID int64) {
if userID <= 0 {
return
}
rng := rand.New(rand.NewSource(time.Now().UnixNano() + userID*31))
for {
if !activity.isActive(userID) {
if !waitRobotRuntimeDelay(ctx, time.Duration(200+rng.Intn(600))*time.Millisecond) {
return
}
continue
}
stay := time.Duration(randomInt64Range(rng, config.GiftRule.RobotStayMinMS, config.GiftRule.RobotStayMaxMS)) * time.Millisecond
if stay <= 0 {
stay = time.Duration(defaultRobotStayMinMS) * time.Millisecond
}
if !waitRobotRuntimeDelay(ctx, stay) {
return
}
if !activity.markInactive(userID) {
continue
}
seatNo := s.robotRoomSeatNo(ctx, config, userID)
if err := s.leaveRobotRoomUser(ctx, config, userID); err != nil {
logx.Warn(ctx, "robot_room_leave_failed", slog.String("room_id", config.RoomID), slog.Int64("robot_user_id", userID), slog.String("error", err.Error()))
activity.markActive(userID)
continue
}
delay := time.Duration(randomInt64Range(rng, config.GiftRule.RobotReplaceMinMS, config.GiftRule.RobotReplaceMaxMS)) * time.Millisecond
if !waitRobotRuntimeDelay(ctx, delay) {
return
}
replacementID := activity.pickReplacement(rng, userID)
if replacementID <= 0 {
replacementID = userID
}
if err := s.joinRobotRoomUser(ctx, config, replacementID, seatNo, fmt.Sprintf("replace:%d:%d", replacementID, time.Now().UTC().UnixNano())); err != nil {
logx.Warn(ctx, "robot_room_replace_join_failed", slog.String("room_id", config.RoomID), slog.Int64("leaving_user_id", userID), slog.Int64("replacement_user_id", replacementID), slog.String("error", err.Error()))
if restoreErr := s.joinRobotRoomUser(ctx, config, userID, seatNo, fmt.Sprintf("restore:%d:%d", userID, time.Now().UTC().UnixNano())); restoreErr != nil {
logx.Warn(ctx, "robot_room_replace_restore_failed", slog.String("room_id", config.RoomID), slog.Int64("robot_user_id", userID), slog.String("error", restoreErr.Error()))
continue
}
activity.markActive(userID)
continue
}
activity.markActive(replacementID)
logx.Info(ctx, "robot_room_replaced_user",
slog.String("room_id", config.RoomID),
slog.Int64("left_robot_user_id", userID),
slog.Int64("joined_robot_user_id", replacementID),
slog.Int64("stay_ms", stay.Milliseconds()),
slog.Int64("replace_delay_ms", delay.Milliseconds()),
)
}
}
func (s *Service) runRobotNormalGiftLoop(ctx context.Context, config RobotRoomConfig, activity *robotRoomActivity, giftSlots chan struct{}, senderID int64) {
interval := time.Duration(config.GiftRule.NormalGiftIntervalMS) * time.Millisecond
if interval <= 0 || len(config.GiftRule.GiftIDs) == 0 {
return
@ -324,33 +530,46 @@ func (s *Service) runRobotNormalGiftLoop(ctx context.Context, config RobotRoomCo
case <-ctx.Done():
return
case <-timer.C:
targetID := randomRobotTarget(rng, config.RobotUserIDs, senderID)
if !activity.isActive(senderID) {
timer.Reset(interval)
continue
}
targetID := randomRobotTarget(rng, activity.activeIDs(), senderID)
giftID := randomString(rng, config.GiftRule.GiftIDs)
if targetID > 0 && giftID != "" {
s.sendRobotGiftBestEffort(ctx, config, senderID, targetID, giftID, "", "normal")
s.sendRobotGiftBestEffort(ctx, config, activity, giftSlots, senderID, targetID, giftID, "", "normal")
}
timer.Reset(interval)
}
}
}
func (s *Service) runRobotLuckyGiftLoop(ctx context.Context, config RobotRoomConfig, senderID int64) {
func (s *Service) runRobotLuckyGiftLoop(ctx context.Context, config RobotRoomConfig, activity *robotRoomActivity, giftSlots chan struct{}, senderID int64) {
if len(config.GiftRule.LuckyGiftIDs) == 0 || config.GiftRule.LuckyComboMax <= 0 {
return
}
comboMin := clampRobotLuckyCombo(config.GiftRule.LuckyComboMin)
comboMax := clampRobotLuckyCombo(config.GiftRule.LuckyComboMax)
if comboMin <= 0 || comboMax < comboMin {
return
}
rng := rand.New(rand.NewSource(time.Now().UnixNano() + senderID*17))
for {
combo := randomInt64Range(rng, config.GiftRule.LuckyComboMin, config.GiftRule.LuckyComboMax)
if !activity.isActive(senderID) {
if !waitRobotRuntimeDelay(ctx, time.Duration(300+rng.Intn(700))*time.Millisecond) {
return
}
continue
}
combo := randomInt64Range(rng, comboMin, comboMax)
for i := int64(0); i < combo; i++ {
giftID := randomString(rng, config.GiftRule.LuckyGiftIDs)
for _, targetID := range config.RobotUserIDs {
if targetID == senderID {
continue
}
if err := ctx.Err(); err != nil {
return
}
s.sendRobotGiftBestEffort(ctx, config, senderID, targetID, giftID, robotRoomLuckyPoolID, "lucky")
targetID := randomRobotTarget(rng, activity.activeIDs(), senderID)
if targetID > 0 && giftID != "" {
s.sendRobotGiftBestEffort(ctx, config, activity, giftSlots, senderID, targetID, giftID, robotRoomLuckyPoolID, "lucky")
}
if !waitRobotGiftPace(ctx, rng) {
return
}
}
pause := time.Duration(randomInt64Range(rng, config.GiftRule.LuckyPauseMinMS, config.GiftRule.LuckyPauseMaxMS)) * time.Millisecond
@ -367,7 +586,16 @@ func (s *Service) runRobotLuckyGiftLoop(ctx context.Context, config RobotRoomCon
}
}
func (s *Service) sendRobotGiftBestEffort(ctx context.Context, config RobotRoomConfig, senderID int64, targetID int64, giftID string, poolID string, kind string) {
func (s *Service) sendRobotGiftBestEffort(ctx context.Context, config RobotRoomConfig, activity *robotRoomActivity, giftSlots chan struct{}, senderID int64, targetID int64, giftID string, poolID string, kind string) {
if !activity.isActive(senderID) || !activity.isActive(targetID) {
return
}
select {
case giftSlots <- struct{}{}:
defer func() { <-giftSlots }()
default:
return
}
_, err := s.RobotSendGift(ctx, RobotSendGiftInput{
Meta: robotRoomCommandMeta(config, senderID, fmt.Sprintf("gift:%s:%d:%d", kind, targetID, time.Now().UTC().UnixNano())),
TargetUserID: targetID,
@ -383,6 +611,56 @@ func (s *Service) sendRobotGiftBestEffort(ctx context.Context, config RobotRoomC
}
}
func (s *Service) leaveRobotRoomUser(ctx context.Context, config RobotRoomConfig, userID int64) error {
_, err := s.LeaveRoom(ctx, &roomv1.LeaveRoomRequest{
Meta: robotRoomCommandMeta(config, userID, fmt.Sprintf("leave:%d:%d", userID, time.Now().UTC().UnixNano())),
})
return err
}
func (s *Service) joinRobotRoomUser(ctx context.Context, config RobotRoomConfig, userID int64, seatNo int32, suffix string) error {
role := "audience"
if userID == config.OwnerRobotUserID {
role = "owner"
}
if _, err := s.JoinRoom(ctx, &roomv1.JoinRoomRequest{
Meta: robotRoomCommandMeta(config, userID, suffix),
Role: role,
}); err != nil {
return err
}
if seatNo <= 0 {
seatNo = preferredRobotSeatNo(config, userID)
}
if seatNo <= 0 {
seatNo = 1
}
if _, err := s.RobotVirtualMicUp(ctx, RobotMicUpInput{
Meta: robotRoomCommandMeta(config, config.OwnerRobotUserID, fmt.Sprintf("mic:%d:%d", userID, time.Now().UTC().UnixNano())),
TargetUserID: userID,
SeatNo: seatNo,
}); err != nil {
if xerr.CodeOf(err) == xerr.Conflict && strings.Contains(xerr.MessageOf(err), "already on seat") {
return nil
}
return err
}
return nil
}
func (s *Service) robotRoomSeatNo(ctx context.Context, config RobotRoomConfig, userID int64) int32 {
snapshot, err := s.currentSnapshot(appcode.WithContext(ctx, config.AppCode), config.RoomID)
if err != nil {
return preferredRobotSeatNo(config, userID)
}
for _, seat := range snapshot.GetMicSeats() {
if seat.GetUserId() == userID {
return seat.GetSeatNo()
}
}
return firstFreeRobotSeatNo(snapshot.GetMicSeats(), robotRoomActiveTarget(config))
}
func robotRoomCommandMeta(config RobotRoomConfig, actorUserID int64, suffix string) *roomv1.RequestMeta {
commandID := fmt.Sprintf("robot-room:%s:%s", config.RoomID, strings.TrimSpace(suffix))
if len(commandID) > 128 {
@ -406,11 +684,17 @@ func normalizeRobotRoomGiftRule(input *roomv1.AdminRobotRoomGiftRule) (RobotRoom
GiftIDs: normalizeStringSet(input.GetGiftIds()),
LuckyGiftIDs: normalizeStringSet(input.GetLuckyGiftIds()),
NormalGiftIntervalMS: input.GetNormalGiftIntervalMs(),
LuckyComboMin: input.GetLuckyComboMin(),
LuckyComboMax: input.GetLuckyComboMax(),
LuckyComboMin: clampRobotLuckyCombo(input.GetLuckyComboMin()),
LuckyComboMax: clampRobotLuckyCombo(input.GetLuckyComboMax()),
LuckyPauseMinMS: input.GetLuckyPauseMinMs(),
LuckyPauseMaxMS: input.GetLuckyPauseMaxMs(),
RobotStayMinMS: input.GetRobotStayMinMs(),
RobotStayMaxMS: input.GetRobotStayMaxMs(),
RobotReplaceMinMS: input.GetRobotReplaceMinMs(),
RobotReplaceMaxMS: input.GetRobotReplaceMaxMs(),
MaxGiftSenders: input.GetMaxGiftSenders(),
}
rule = withRobotRoomGiftRuleDefaults(rule)
if len(rule.GiftIDs) == 0 {
return RobotRoomGiftRule{}, xerr.New(xerr.InvalidArgument, "gift_ids is required")
}
@ -426,9 +710,49 @@ func normalizeRobotRoomGiftRule(input *roomv1.AdminRobotRoomGiftRule) (RobotRoom
if rule.LuckyPauseMinMS <= 0 || rule.LuckyPauseMaxMS < rule.LuckyPauseMinMS {
return RobotRoomGiftRule{}, xerr.New(xerr.InvalidArgument, "lucky pause range is invalid")
}
if rule.RobotStayMinMS <= 0 || rule.RobotStayMaxMS < rule.RobotStayMinMS {
return RobotRoomGiftRule{}, xerr.New(xerr.InvalidArgument, "robot stay range is invalid")
}
if rule.RobotReplaceMinMS < 0 || rule.RobotReplaceMaxMS < rule.RobotReplaceMinMS {
return RobotRoomGiftRule{}, xerr.New(xerr.InvalidArgument, "robot replace range is invalid")
}
if rule.MaxGiftSenders <= 0 {
return RobotRoomGiftRule{}, xerr.New(xerr.InvalidArgument, "max_gift_senders is required")
}
return rule, nil
}
func withRobotRoomGiftRuleDefaults(rule RobotRoomGiftRule) RobotRoomGiftRule {
if rule.RobotStayMinMS <= 0 && rule.RobotStayMaxMS <= 0 {
rule.RobotStayMinMS = defaultRobotStayMinMS
rule.RobotStayMaxMS = defaultRobotStayMaxMS
}
if rule.RobotReplaceMinMS == 0 && rule.RobotReplaceMaxMS == 0 {
rule.RobotReplaceMinMS = defaultRobotReplaceMinMS
rule.RobotReplaceMaxMS = defaultRobotReplaceMaxMS
}
if rule.MaxGiftSenders <= 0 {
rule.MaxGiftSenders = defaultMaxGiftSenders
}
return rule
}
// WithRobotRoomGiftRuleStorageDefaults 让 repository 恢复历史行时复用运行时默认值;
// 默认值只补空字段,不放宽 normalizeRobotRoomGiftRule 对显式非法范围的校验。
func WithRobotRoomGiftRuleStorageDefaults(rule RobotRoomGiftRule) RobotRoomGiftRule {
return withRobotRoomGiftRuleDefaults(rule)
}
func clampRobotLuckyCombo(value int64) int64 {
if value <= 0 {
return value
}
if value > maxRobotLuckyComboPerCycle {
return maxRobotLuckyComboPerCycle
}
return value
}
func robotRoomConfigToProto(config RobotRoomConfig) *roomv1.AdminRobotRoom {
return &roomv1.AdminRobotRoom{
AppCode: config.AppCode,
@ -440,6 +764,8 @@ func robotRoomConfigToProto(config RobotRoomConfig) *roomv1.AdminRobotRoom {
Status: config.Status,
OwnerRobotUserId: config.OwnerRobotUserID,
RobotUserIds: append([]int64(nil), config.RobotUserIDs...),
ActiveRobotCount: config.ActiveRobotCount,
SeatCount: config.SeatCount,
GiftRule: &roomv1.AdminRobotRoomGiftRule{
GiftIds: append([]string(nil), config.GiftRule.GiftIDs...),
LuckyGiftIds: append([]string(nil), config.GiftRule.LuckyGiftIDs...),
@ -448,6 +774,11 @@ func robotRoomConfigToProto(config RobotRoomConfig) *roomv1.AdminRobotRoom {
LuckyComboMax: config.GiftRule.LuckyComboMax,
LuckyPauseMinMs: config.GiftRule.LuckyPauseMinMS,
LuckyPauseMaxMs: config.GiftRule.LuckyPauseMaxMS,
RobotStayMinMs: config.GiftRule.RobotStayMinMS,
RobotStayMaxMs: config.GiftRule.RobotStayMaxMS,
RobotReplaceMinMs: config.GiftRule.RobotReplaceMinMS,
RobotReplaceMaxMs: config.GiftRule.RobotReplaceMaxMS,
MaxGiftSenders: config.GiftRule.MaxGiftSenders,
},
CreatedByAdminId: config.CreatedByAdminID,
CreatedAtMs: config.CreatedAtMS,
@ -470,6 +801,17 @@ func normalizeRobotCountRange(minCount int32, maxCount int32) (int, int) {
return minValue, maxValue
}
func normalizeRobotRoomSeatCount(seatCount int32) int32 {
switch seatCount {
case 0:
return defaultRobotRoomSeatCount
case 10, 15, 20:
return seatCount
default:
return 0
}
}
func selectRobotUsers(rng *rand.Rand, ownerID int64, available []int64, count int) []int64 {
others := make([]int64, 0, len(available))
for _, userID := range available {
@ -489,6 +831,258 @@ func selectRobotUsers(rng *rand.Rand, ownerID int64, available []int64, count in
return selected
}
func robotRoomInitialActiveIDs(config RobotRoomConfig) []int64 {
target := robotRoomActiveTarget(config)
if target <= 0 {
return nil
}
if target > len(config.RobotUserIDs) {
target = len(config.RobotUserIDs)
}
active := make([]int64, 0, target)
if config.OwnerRobotUserID > 0 && robotRoomHasUser(config.RobotUserIDs, config.OwnerRobotUserID) {
active = append(active, config.OwnerRobotUserID)
}
for _, userID := range config.RobotUserIDs {
if len(active) >= target {
break
}
if userID <= 0 || userID == config.OwnerRobotUserID {
continue
}
active = append(active, userID)
}
return active
}
func robotRoomActiveTarget(config RobotRoomConfig) int {
target := int(config.ActiveRobotCount)
if target <= 0 {
target = len(config.RobotUserIDs)
}
if target > len(config.RobotUserIDs) {
target = len(config.RobotUserIDs)
}
if target < 0 {
return 0
}
return target
}
func robotRoomMaxGiftSenders(config RobotRoomConfig) int {
maxSenders := int(config.GiftRule.MaxGiftSenders)
if maxSenders <= 0 {
maxSenders = int(defaultMaxGiftSenders)
}
if maxSenders > len(config.RobotUserIDs) {
maxSenders = len(config.RobotUserIDs)
}
if maxSenders <= 0 {
maxSenders = 1
}
return maxSenders
}
func robotRoomHasUser(robots []int64, userID int64) bool {
for _, robotID := range robots {
if robotID == userID {
return true
}
}
return false
}
func onlineRobotIDs(robots []int64, online map[int64]bool) []int64 {
out := make([]int64, 0, len(robots))
for _, userID := range robots {
if online[userID] {
out = append(out, userID)
}
}
return out
}
func robotRoomFillCandidates(config RobotRoomConfig, online map[int64]bool, limit int) []int64 {
if limit <= 0 {
return nil
}
out := make([]int64, 0, limit)
if config.OwnerRobotUserID > 0 && !online[config.OwnerRobotUserID] && robotRoomHasUser(config.RobotUserIDs, config.OwnerRobotUserID) {
out = append(out, config.OwnerRobotUserID)
}
for _, userID := range config.RobotUserIDs {
if len(out) >= limit {
break
}
if userID <= 0 || userID == config.OwnerRobotUserID || online[userID] {
continue
}
out = append(out, userID)
}
return out
}
func preferredRobotSeatNo(config RobotRoomConfig, userID int64) int32 {
for index, robotID := range config.RobotUserIDs {
if robotID == userID {
return int32(index + 1)
}
}
return 0
}
func firstFreeRobotSeatNo(seats []*roomv1.SeatState, activeTarget int) int32 {
occupied := make(map[int32]bool, len(seats))
maxSeatNo := int32(0)
for _, seat := range seats {
if seat.GetSeatNo() > maxSeatNo {
maxSeatNo = seat.GetSeatNo()
}
if seat.GetUserId() > 0 {
occupied[seat.GetSeatNo()] = true
}
}
if maxSeatNo <= 0 {
maxSeatNo = int32(max(10, activeTarget))
}
for seatNo := int32(1); seatNo <= maxSeatNo; seatNo++ {
if !occupied[seatNo] {
return seatNo
}
}
return 0
}
func waitRobotRuntimeDelay(ctx context.Context, delay time.Duration) bool {
if delay <= 0 {
select {
case <-ctx.Done():
return false
default:
return true
}
}
timer := time.NewTimer(delay)
defer timer.Stop()
select {
case <-ctx.Done():
return false
case <-timer.C:
return true
}
}
type robotRoomActivity struct {
mu sync.Mutex
active map[int64]bool
giftSenders map[int64]bool
pool []int64
}
func newRobotRoomActivity(pool []int64) *robotRoomActivity {
return &robotRoomActivity{
active: make(map[int64]bool, len(pool)),
giftSenders: make(map[int64]bool),
pool: append([]int64(nil), pool...),
}
}
func (a *robotRoomActivity) isActive(userID int64) bool {
a.mu.Lock()
defer a.mu.Unlock()
return a.active[userID]
}
func (a *robotRoomActivity) markActive(userID int64) {
if userID <= 0 {
return
}
a.mu.Lock()
a.active[userID] = true
a.mu.Unlock()
}
func (a *robotRoomActivity) markInactive(userID int64) bool {
a.mu.Lock()
defer a.mu.Unlock()
if !a.active[userID] {
return false
}
delete(a.active, userID)
delete(a.giftSenders, userID)
return true
}
func (a *robotRoomActivity) isGiftSender(userID int64) bool {
a.mu.Lock()
defer a.mu.Unlock()
return a.giftSenders[userID]
}
func (a *robotRoomActivity) markGiftSender(userID int64) {
if userID <= 0 {
return
}
a.mu.Lock()
if a.active[userID] {
a.giftSenders[userID] = true
}
a.mu.Unlock()
}
func (a *robotRoomActivity) markGiftSenderWithinLimit(userID int64, maxSenders int) bool {
if userID <= 0 || maxSenders <= 0 {
return false
}
a.mu.Lock()
defer a.mu.Unlock()
if !a.active[userID] || len(a.giftSenders) >= maxSenders {
return false
}
a.giftSenders[userID] = true
return true
}
func (a *robotRoomActivity) giftSenderCount() int {
a.mu.Lock()
defer a.mu.Unlock()
return len(a.giftSenders)
}
func (a *robotRoomActivity) activeIDs() []int64 {
a.mu.Lock()
defer a.mu.Unlock()
out := make([]int64, 0, len(a.active))
for userID := range a.active {
out = append(out, userID)
}
return out
}
func (a *robotRoomActivity) pickReplacement(rng *rand.Rand, departingUserID int64) int64 {
a.mu.Lock()
defer a.mu.Unlock()
candidates := make([]int64, 0, len(a.pool))
fallback := make([]int64, 0, 1)
for _, userID := range a.pool {
if a.active[userID] {
continue
}
if userID == departingUserID {
fallback = append(fallback, userID)
continue
}
candidates = append(candidates, userID)
}
if len(candidates) == 0 {
candidates = fallback
}
if len(candidates) == 0 {
return 0
}
return candidates[rng.Intn(len(candidates))]
}
func normalizeRobotRoomStatus(status string) string {
switch strings.TrimSpace(status) {
case robotRoomStatusActive:
@ -564,3 +1158,15 @@ func randomJitter(interval time.Duration, rng *rand.Rand) time.Duration {
}
return time.Duration(rng.Int63n(int64(interval))) + time.Second
}
func waitRobotGiftPace(ctx context.Context, rng *rand.Rand) bool {
delay := time.Duration(300+rng.Intn(500)) * time.Millisecond
timer := time.NewTimer(delay)
defer timer.Stop()
select {
case <-ctx.Done():
return false
case <-timer.C:
return true
}
}

View File

@ -0,0 +1,108 @@
package service_test
import (
"context"
"testing"
"time"
roomv1 "hyapp.local/api/proto/room/v1"
"hyapp/pkg/appcode"
"hyapp/services/room-service/internal/integration"
roomservice "hyapp/services/room-service/internal/room/service"
"hyapp/services/room-service/internal/router"
"hyapp/services/room-service/internal/testutil/mysqltest"
)
func TestRobotRoomRuntimeStartRestoresLeftRobots(t *testing.T) {
ctx := appcode.WithContext(context.Background(), appcode.Default)
repository := mysqltest.NewRepository(t)
svc := roomservice.New(roomservice.Config{
NodeID: "node-robot-runtime-restore-test",
LeaseTTL: 10 * time.Second,
RankLimit: 20,
SnapshotEveryN: 1,
}, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher())
created, err := svc.AdminCreateRobotRoom(ctx, &roomv1.AdminCreateRobotRoomRequest{
Meta: roomservice.NewRequestMeta("", 9001),
OwnerRobotUserId: 1001,
CandidateRobotUserIds: []int64{1001, 1002},
MinRobotCount: 2,
MaxRobotCount: 2,
RoomName: "Robot Runtime Restore",
RoomAvatar: testRoomCoverURL,
VisibleRegionId: 686,
GiftRule: &roomv1.AdminRobotRoomGiftRule{
GiftIds: []string{"normal_gift"},
LuckyGiftIds: []string{"lucky_gift"},
NormalGiftIntervalMs: 10000,
LuckyComboMin: 1,
LuckyComboMax: 1,
LuckyPauseMinMs: 5000,
LuckyPauseMaxMs: 5000,
},
AdminId: 9001,
})
if err != nil {
t.Fatalf("create robot room failed: %v", err)
}
roomID := created.GetRoom().GetRoomId()
robotUserIDs := created.GetRoom().GetRobotUserIds()
for _, userID := range robotUserIDs {
if _, err := svc.LeaveRoom(ctx, &roomv1.LeaveRoomRequest{
Meta: roomservice.NewRequestMeta(roomID, userID),
}); err != nil {
t.Fatalf("leave robot %d failed: %v", userID, err)
}
}
if _, err := svc.AdminSetRobotRoomStatus(ctx, &roomv1.AdminSetRobotRoomStatusRequest{
Meta: roomservice.NewRequestMeta(roomID, 9001),
Status: "stopped",
AdminId: 9001,
}); err != nil {
t.Fatalf("stop robot room failed: %v", err)
}
if _, err := svc.AdminSetRobotRoomStatus(ctx, &roomv1.AdminSetRobotRoomStatusRequest{
Meta: roomservice.NewRequestMeta(roomID, 9001),
Status: "active",
AdminId: 9001,
}); err != nil {
t.Fatalf("restart robot room failed: %v", err)
}
snapshot, err := svc.GetRoomSnapshot(ctx, &roomv1.GetRoomSnapshotRequest{
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
RoomId: roomID,
ViewerUserId: robotUserIDs[0],
})
if err != nil {
t.Fatalf("snapshot after runtime restore failed: %v", err)
}
for _, userID := range robotUserIDs {
if !snapshotContainsUser(snapshot.GetRoom(), userID) {
t.Fatalf("robot %d should be online after runtime restart", userID)
}
if !snapshotContainsSeatUser(snapshot.GetRoom(), userID) {
t.Fatalf("robot %d should be on virtual mic after runtime restart", userID)
}
}
}
func snapshotContainsUser(snapshot *roomv1.RoomSnapshot, userID int64) bool {
for _, user := range snapshot.GetOnlineUsers() {
if user.GetUserId() == userID {
return true
}
}
return false
}
func snapshotContainsSeatUser(snapshot *roomv1.RoomSnapshot, userID int64) bool {
for _, seat := range snapshot.GetMicSeats() {
if seat.GetUserId() == userID {
return true
}
}
return false
}

View File

@ -0,0 +1,133 @@
package service
import (
"math/rand"
"testing"
roomv1 "hyapp.local/api/proto/room/v1"
"hyapp/services/room-service/internal/room/command"
"hyapp/services/room-service/internal/room/state"
)
func TestRobotRoomRuntimeClearUsesToken(t *testing.T) {
cancelled := false
svc := &Service{
robotRuntimes: map[string]robotRoomRuntime{
"robot-runtime-token-test": {
cancel: func() { cancelled = true },
token: "new-token",
},
},
}
svc.clearRobotRoomRuntime("robot-runtime-token-test", "old-token")
if len(svc.robotRuntimes) != 1 {
t.Fatalf("old runtime token must not clear newer runtime")
}
svc.clearRobotRoomRuntime("robot-runtime-token-test", "new-token")
if len(svc.robotRuntimes) != 0 {
t.Fatalf("matching runtime token should clear runtime, got %d", len(svc.robotRuntimes))
}
if cancelled {
t.Fatalf("clearRobotRoomRuntime must only remove map entry, not invoke cancel")
}
}
func TestRobotRoomStalePresenceKeepsConfiguredRobots(t *testing.T) {
current := &state.RoomState{
RoomExt: map[string]string{
roomExtRobotRoomKey: "true",
roomExtRobotUserIDsKey: "1001,1002",
},
OnlineUsers: map[int64]*state.RoomUserState{
1001: {UserID: 1001, LastSeenAtMS: 10},
1002: {UserID: 1002, LastSeenAtMS: 10},
2001: {UserID: 2001, LastSeenAtMS: 10},
2002: {UserID: 2002, LastSeenAtMS: 200},
},
}
stale := stalePresenceUserIDs(current, 100)
if len(stale) != 1 || stale[0] != 2001 {
t.Fatalf("stale sweep should keep robot users and evict only stale real users, got %+v", stale)
}
}
func TestReplayRoomHeartbeatAfterLeaveIsIgnored(t *testing.T) {
current := &state.RoomState{
OnlineUsers: map[int64]*state.RoomUserState{},
}
err := replay(current, &command.RoomHeartbeat{
Base: command.Base{
ActorID: 123456,
Room: "robot-stale-heartbeat",
SentAtMS: 1781675912713,
},
}, 1781675913212)
if err != nil {
t.Fatalf("stale heartbeat after leave must not break recovery: %v", err)
}
if len(current.OnlineUsers) != 0 {
t.Fatalf("stale heartbeat must not recreate presence: %+v", current.OnlineUsers)
}
if current.Version != 0 {
t.Fatalf("ignored heartbeat must not advance room version, got %d", current.Version)
}
}
func TestNormalizeRobotRoomGiftRuleClampsLuckyCombo(t *testing.T) {
rule, err := normalizeRobotRoomGiftRule(&roomv1.AdminRobotRoomGiftRule{
GiftIds: []string{"normal-gift"},
LuckyGiftIds: []string{"lucky-gift"},
NormalGiftIntervalMs: 10000,
LuckyComboMin: 100,
LuckyComboMax: 10000,
LuckyPauseMinMs: 5000,
LuckyPauseMaxMs: 20000,
})
if err != nil {
t.Fatalf("normalize robot room gift rule failed: %v", err)
}
if rule.LuckyComboMin != maxRobotLuckyComboPerCycle || rule.LuckyComboMax != maxRobotLuckyComboPerCycle {
t.Fatalf("lucky combo should be clamped to %d, got %d-%d", maxRobotLuckyComboPerCycle, rule.LuckyComboMin, rule.LuckyComboMax)
}
}
func TestNormalizeRobotRoomGiftRuleAppliesBehaviorDefaults(t *testing.T) {
rule, err := normalizeRobotRoomGiftRule(&roomv1.AdminRobotRoomGiftRule{
GiftIds: []string{"normal-gift"},
LuckyGiftIds: []string{"lucky-gift"},
NormalGiftIntervalMs: 10000,
LuckyComboMin: 1,
LuckyComboMax: 1,
LuckyPauseMinMs: 5000,
LuckyPauseMaxMs: 20000,
})
if err != nil {
t.Fatalf("normalize robot room gift rule failed: %v", err)
}
if rule.RobotStayMinMS != defaultRobotStayMinMS || rule.RobotStayMaxMS != defaultRobotStayMaxMS {
t.Fatalf("robot stay defaults mismatch: %d-%d", rule.RobotStayMinMS, rule.RobotStayMaxMS)
}
if rule.RobotReplaceMinMS != defaultRobotReplaceMinMS || rule.RobotReplaceMaxMS != defaultRobotReplaceMaxMS {
t.Fatalf("robot replace defaults mismatch: %d-%d", rule.RobotReplaceMinMS, rule.RobotReplaceMaxMS)
}
if rule.MaxGiftSenders != defaultMaxGiftSenders {
t.Fatalf("max gift senders default mismatch: %d", rule.MaxGiftSenders)
}
}
func TestRobotRoomActivityPrefersOtherReplacement(t *testing.T) {
activity := newRobotRoomActivity([]int64{1001, 1002, 1003})
activity.markActive(1001)
activity.markActive(1002)
if !activity.markInactive(1002) {
t.Fatalf("expected active robot to become inactive")
}
rng := rand.New(rand.NewSource(1))
if got := activity.pickReplacement(rng, 1002); got != 1003 {
t.Fatalf("replacement should prefer another offline robot, got %d", got)
}
}

View File

@ -0,0 +1,135 @@
package service_test
import (
"context"
"testing"
"time"
roomv1 "hyapp.local/api/proto/room/v1"
"hyapp/pkg/appcode"
"hyapp/services/room-service/internal/integration"
roomservice "hyapp/services/room-service/internal/room/service"
"hyapp/services/room-service/internal/router"
"hyapp/services/room-service/internal/testutil/mysqltest"
)
func TestAdminCreateRobotRoomProjectsOwnerRegionAndCountry(t *testing.T) {
ctx := appcode.WithContext(context.Background(), appcode.Default)
repository := mysqltest.NewRepository(t)
svc := roomservice.New(roomservice.Config{
NodeID: "node-admin-robot-room-owner-region-country-test",
LeaseTTL: 10 * time.Second,
RankLimit: 20,
SnapshotEveryN: 1,
}, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher())
resp, err := svc.AdminCreateRobotRoom(ctx, &roomv1.AdminCreateRobotRoomRequest{
Meta: roomservice.NewRequestMeta("", 9001),
OwnerRobotUserId: 325379237278126080,
CandidateRobotUserIds: []int64{325379237278126080},
MinRobotCount: 1,
MaxRobotCount: 1,
RoomName: "Robot Owner",
RoomAvatar: testRoomCoverURL,
VisibleRegionId: 686,
OwnerCountryCode: "ae",
GiftRule: &roomv1.AdminRobotRoomGiftRule{
GiftIds: []string{"84"},
LuckyGiftIds: []string{"28"},
NormalGiftIntervalMs: 10000,
LuckyComboMin: 100,
LuckyComboMax: 10000,
LuckyPauseMinMs: 5000,
LuckyPauseMaxMs: 20000,
},
AdminId: 9001,
})
if err != nil {
t.Fatalf("AdminCreateRobotRoom failed: %v", err)
}
roomID := resp.GetRoom().GetRoomId()
if roomID == "" {
t.Fatalf("created robot room id is empty")
}
entries, err := repository.ListRoomListEntries(ctx, roomservice.RoomListQuery{VisibleRegionID: 686, CountryCode: "AE", Tab: "new", Limit: 10})
if err != nil {
t.Fatalf("list robot room entries failed: %v", err)
}
if len(entries) != 1 || entries[0].RoomID != roomID || entries[0].VisibleRegionID != 686 || entries[0].OwnerCountryCode != "AE" {
t.Fatalf("robot room owner region/country projection mismatch: %+v", entries)
}
}
func TestAdminCreateRobotRoomUsesCandidatePoolAndActiveCount(t *testing.T) {
ctx := appcode.WithContext(context.Background(), appcode.Default)
repository := mysqltest.NewRepository(t)
svc := roomservice.New(roomservice.Config{
NodeID: "node-admin-robot-room-pool-test",
LeaseTTL: 10 * time.Second,
RankLimit: 20,
SnapshotEveryN: 1,
}, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher())
resp, err := svc.AdminCreateRobotRoom(ctx, &roomv1.AdminCreateRobotRoomRequest{
Meta: roomservice.NewRequestMeta("", 9001),
OwnerRobotUserId: 1001,
CandidateRobotUserIds: []int64{1001, 1002, 1003, 1004},
MinRobotCount: 2,
MaxRobotCount: 2,
RoomName: "Robot Pool",
RoomAvatar: testRoomCoverURL,
VisibleRegionId: 686,
OwnerCountryCode: "ae",
GiftRule: &roomv1.AdminRobotRoomGiftRule{
GiftIds: []string{"84"},
LuckyGiftIds: []string{"28"},
NormalGiftIntervalMs: 10000,
LuckyComboMin: 1,
LuckyComboMax: 1,
LuckyPauseMinMs: 5000,
LuckyPauseMaxMs: 20000,
RobotStayMinMs: 180000,
RobotStayMaxMs: 600000,
RobotReplaceMinMs: 0,
RobotReplaceMaxMs: 60000,
MaxGiftSenders: 2,
},
AdminId: 9001,
})
if err != nil {
t.Fatalf("AdminCreateRobotRoom failed: %v", err)
}
roomID := resp.GetRoom().GetRoomId()
if got := len(resp.GetRoom().GetRobotUserIds()); got != 4 {
t.Fatalf("robot room should persist full candidate pool for replacement, got %d", got)
}
if resp.GetRoom().GetGiftRule().GetMaxGiftSenders() != 2 {
t.Fatalf("max gift senders should round-trip through room config")
}
snapshot, err := svc.GetRoomSnapshot(ctx, &roomv1.GetRoomSnapshotRequest{
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
RoomId: roomID,
ViewerUserId: 1001,
})
if err != nil {
t.Fatalf("snapshot failed: %v", err)
}
if got := len(snapshot.GetRoom().GetOnlineUsers()); got != 2 {
t.Fatalf("robot room should only bootstrap active robot count online, got %d", got)
}
if got := occupiedSeatUserCount(snapshot.GetRoom()); got != 2 {
t.Fatalf("robot room should only put active robots on virtual mic, got %d", got)
}
}
func occupiedSeatUserCount(snapshot *roomv1.RoomSnapshot) int {
count := 0
for _, seat := range snapshot.GetMicSeats() {
if seat.GetUserId() > 0 {
count++
}
}
return count
}

View File

@ -35,6 +35,7 @@ type RobotSendGiftInput struct {
RobotUserIDs []int64
SyntheticRewardCoins int64
SyntheticMultiplierPPM int64
RealRoomHeat bool
}
type robotGiftOptions struct {
@ -42,6 +43,7 @@ type robotGiftOptions struct {
RobotUserIDs []int64
SyntheticRewardCoins int64
SyntheticMultiplierPPM int64
RealRoomHeat bool
}
func (s *Service) RobotSendGift(ctx context.Context, input RobotSendGiftInput) (*roomv1.SendGiftResponse, error) {
@ -59,6 +61,7 @@ func (s *Service) RobotSendGift(ctx context.Context, input RobotSendGiftInput) (
RobotUserIDs: input.RobotUserIDs,
SyntheticRewardCoins: input.SyntheticRewardCoins,
SyntheticMultiplierPPM: input.SyntheticMultiplierPPM,
RealRoomHeat: input.RealRoomHeat,
})
}
@ -78,7 +81,8 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
// 工资区域由 gateway 从 user-service host profile 注入;房间 visible_region_id 只用于房间/礼物可见性。
TargetHostRegionID: req.GetTargetHostRegionId(),
TargetAgencyOwnerUserID: req.GetTargetAgencyOwnerUserId(),
RobotGift: robotOptions.Enabled,
RobotGift: robotOptions.Enabled && !robotOptions.RealRoomHeat,
RobotWalletGift: robotOptions.Enabled,
SyntheticLuckyGift: robotOptions.Enabled && strings.TrimSpace(req.GetPoolId()) != "",
SyntheticLuckyRewardCoins: firstPositiveInt64(robotOptions.SyntheticRewardCoins, 0),
SyntheticLuckyMultiplierPPM: firstPositiveInt64(robotOptions.SyntheticMultiplierPPM, 1000000),
@ -109,8 +113,8 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
return mutationResult{}, nil, xerr.New(xerr.NotFound, "target not in room")
}
}
if cmd.RobotGift {
if err := requireRobotGiftParticipants(current, cmd.ActorUserID(), cmd.TargetUserIDs, robotOptions.RobotUserIDs); err != nil {
if robotOptions.Enabled {
if err := requireRobotGiftParticipants(current, cmd.ActorUserID(), cmd.TargetUserIDs, robotOptions.RobotUserIDs, !robotOptions.RealRoomHeat); err != nil {
return mutationResult{}, nil, err
}
}
@ -261,8 +265,9 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
TargetGiftValue: targetCurrentGiftValues[targetBilling.TargetUserID],
// effect_types 来自后台礼物配置,房间事件必须原样带出,后续 activity-service 才能识别全服广播标识。
GiftEffectTypes: targetBilling.Billing.GetGiftEffectTypes(),
IsRobotGift: cmd.RobotGift,
IsRobotGift: cmd.RobotWalletGift,
SyntheticLuckyGift: cmd.SyntheticLuckyGift,
RealRoomRobotGift: cmd.RobotWalletGift && !cmd.RobotGift,
})
if err != nil {
return mutationResult{}, nil, err
@ -270,6 +275,14 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
giftEvents = append(giftEvents, giftEvent)
}
records := make([]outbox.Record, 0, len(giftEvents)+4)
robotRecords := make([]outbox.Record, 0, len(giftEvents)+3)
if cmd.RobotGift {
// 机器人送礼只保留客户端展示所需事实,并写入 robot outbox由独立 worker/topic 补偿投递。
robotRecords = append(robotRecords, giftEvents...)
} else {
records = append(records, giftEvents...)
}
heatEvent, err := outbox.Build(current.RoomID, "RoomHeatChanged", current.Version, now, &roomeventsv1.RoomHeatChanged{
Delta: heatValue,
CurrentHeat: current.Heat,
@ -287,23 +300,28 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
if err != nil {
return mutationResult{}, nil, err
}
records := make([]outbox.Record, 0, len(giftEvents)+4)
records = append(records, giftEvents...)
records = append(records, heatEvent, rankEvent)
if rocketApply.progressEvent != nil {
progressEvent, err := outbox.Build(current.RoomID, "RoomRocketFuelChanged", current.Version, now, rocketApply.progressEvent)
if err != nil {
return mutationResult{}, nil, err
}
records = append(records, progressEvent)
if cmd.RobotGift {
// 房间热度和麦位收礼热度仍要给客户端展示,但走机器人 outbox不能占用真人房间主流程。
robotRecords = append(robotRecords, heatEvent, rankEvent)
} else {
records = append(records, heatEvent, rankEvent)
}
if rocketApply.ignited != nil {
ignitedEvent, err := outbox.Build(current.RoomID, "RoomRocketIgnited", current.Version, now, rocketApply.ignited)
if err != nil {
return mutationResult{}, nil, err
if !cmd.RobotGift && !cmd.RobotWalletGift {
// 火箭只属于真人礼物主业务链路,机器人展示礼物不能触发火箭燃料 outbox。
if rocketApply.progressEvent != nil {
progressEvent, err := outbox.Build(current.RoomID, "RoomRocketFuelChanged", current.Version, now, rocketApply.progressEvent)
if err != nil {
return mutationResult{}, nil, err
}
records = append(records, progressEvent)
}
if rocketApply.ignited != nil {
ignitedEvent, err := outbox.Build(current.RoomID, "RoomRocketIgnited", current.Version, now, rocketApply.ignited)
if err != nil {
return mutationResult{}, nil, err
}
records = append(records, ignitedEvent)
}
records = append(records, ignitedEvent)
}
if cmd.SyntheticLuckyGift && luckyGift != nil {
drawEvent, err := outbox.Build(current.RoomID, "RoomRobotLuckyGiftDrawn", current.Version, now, &roomeventsv1.RoomRobotLuckyGiftDrawn{
@ -327,18 +345,23 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
if err != nil {
return mutationResult{}, nil, err
}
records = append(records, drawEvent)
if cmd.RobotGift {
robotRecords = append(robotRecords, drawEvent)
} else {
records = append(records, drawEvent)
}
}
result := mutationResult{
snapshot: current.ToProto(),
billingReceiptID: billing.GetBillingReceiptId(),
roomHeat: current.Heat,
giftRank: cloneProtoRank(current.GiftRank),
luckyGift: luckyGift,
luckyGifts: luckyGifts,
commandPayload: commandPayload,
walletDebitMS: walletDebitMS,
snapshot: current.ToProto(),
billingReceiptID: billing.GetBillingReceiptId(),
roomHeat: current.Heat,
giftRank: cloneProtoRank(current.GiftRank),
luckyGift: luckyGift,
luckyGifts: luckyGifts,
commandPayload: commandPayload,
walletDebitMS: walletDebitMS,
robotOutboxRecords: robotRecords,
roomGiftLeaderboard: &RoomGiftLeaderboardIncrement{
AppCode: appcode.FromContext(ctx),
RoomID: current.RoomID,
@ -387,7 +410,7 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
"gift_icon_url": billing.GetGiftIconUrl(),
"gift_animation_url": billing.GetGiftAnimationUrl(),
"target_gift_value": fmt.Sprintf("%d", targetCurrentGiftValues[cmd.TargetUserID]),
"is_robot_gift": fmt.Sprintf("%t", cmd.RobotGift),
"is_robot_gift": fmt.Sprintf("%t", cmd.RobotWalletGift),
"synthetic_lucky_gift": fmt.Sprintf("%t", cmd.SyntheticLuckyGift),
},
},
@ -423,7 +446,7 @@ type giftTargetBilling struct {
}
func (s *Service) debitGiftTargets(ctx context.Context, cmd command.SendGift, roomMeta RoomMeta) (*walletv1.DebitGiftResponse, []giftTargetBilling, error) {
if cmd.RobotGift {
if cmd.RobotWalletGift {
if len(cmd.TargetUserIDs) != 1 {
return nil, nil, xerr.New(xerr.InvalidArgument, "robot gift only supports one target")
}
@ -773,8 +796,11 @@ func findRankItem(items []state.RankItem, userID int64) state.RankItem {
return state.RankItem{UserID: userID}
}
func requireRobotGiftParticipants(current *state.RoomState, senderUserID int64, targetUserIDs []int64, runtimeRobotUserIDs []int64) error {
if current == nil || current.RoomExt[roomExtRobotRoomKey] != "true" {
func requireRobotGiftParticipants(current *state.RoomState, senderUserID int64, targetUserIDs []int64, runtimeRobotUserIDs []int64, requireRobotRoom bool) error {
if current == nil {
return xerr.New(xerr.PermissionDenied, "robot gift requires room state")
}
if requireRobotRoom && (current == nil || current.RoomExt[roomExtRobotRoomKey] != "true") {
return xerr.New(xerr.PermissionDenied, "robot gift requires robot room")
}
allowed := parseInt64CSV(current.RoomExt[roomExtRobotUserIDsKey])

View File

@ -0,0 +1,839 @@
package service
import (
"context"
"fmt"
"log/slog"
"math/rand"
"strings"
"time"
roomv1 "hyapp.local/api/proto/room/v1"
"hyapp/pkg/appcode"
"hyapp/pkg/logx"
"hyapp/pkg/xerr"
)
const (
humanRobotLuckyPoolID = "human_robot_lucky_display"
humanRobotSuperLuckyPoolID = "human_robot_super_lucky_display"
defaultHumanRobotCandidateRoomMaxOnline = int32(5)
defaultHumanRobotRoomFullStopOnline = int32(10)
defaultHumanRobotRoomTargetMinOnline = int32(8)
defaultHumanRobotRoomTargetMaxOnline = int32(10)
defaultHumanRobotStayMinMS = int64(60 * 1000)
defaultHumanRobotStayMaxMS = int64(10 * 60 * 1000)
defaultHumanRobotReplaceMinMS = int64(60 * 1000)
defaultHumanRobotReplaceMaxMS = int64(3 * 60 * 1000)
defaultHumanRobotNormalGiftIntervalMS = int64(10 * 1000)
defaultHumanRobotNormalGiftIntervalMinMS = int64(1 * 1000)
defaultHumanRobotNormalGiftIntervalMaxMS = int64(20 * 1000)
defaultHumanRobotLuckyPauseMinMS = int64(5 * 1000)
defaultHumanRobotLuckyPauseMaxMS = int64(20 * 1000)
defaultHumanRobotLuckyComboMin = int64(1)
defaultHumanRobotLuckyComboMax = int64(3)
defaultHumanRobotMaxGiftSenders = int64(1)
)
func (s *Service) AdminGetHumanRoomRobotConfig(ctx context.Context, req *roomv1.AdminGetHumanRoomRobotConfigRequest) (*roomv1.AdminGetHumanRoomRobotConfigResponse, error) {
ctx = contextFromMeta(ctx, req.GetMeta())
config, exists, err := s.repository.GetHumanRoomRobotConfig(ctx)
if err != nil {
return nil, err
}
if !exists {
config = defaultHumanRoomRobotConfig(appcode.FromContext(ctx), s.clock.Now().UnixMilli())
}
return &roomv1.AdminGetHumanRoomRobotConfigResponse{Config: humanRoomRobotConfigToProto(config), ServerTimeMs: s.clock.Now().UnixMilli()}, nil
}
func (s *Service) AdminUpdateHumanRoomRobotConfig(ctx context.Context, req *roomv1.AdminUpdateHumanRoomRobotConfigRequest) (*roomv1.AdminUpdateHumanRoomRobotConfigResponse, error) {
ctx = contextFromMeta(ctx, req.GetMeta())
config, err := normalizeHumanRoomRobotConfig(appcode.FromContext(ctx), req.GetConfig(), req.GetAdminId(), s.clock.Now().UnixMilli())
if err != nil {
return nil, err
}
saved, err := s.repository.UpsertHumanRoomRobotConfig(ctx, config)
if err != nil {
return nil, err
}
if !saved.Enabled {
s.stopAllHumanRoomRobotRuntimes()
}
return &roomv1.AdminUpdateHumanRoomRobotConfigResponse{Config: humanRoomRobotConfigToProto(saved), ServerTimeMs: s.clock.Now().UnixMilli()}, nil
}
// RunHumanRoomRobotRuntimeManager 定期把各国家空闲机器人补进低人数真人房间。
func (s *Service) RunHumanRoomRobotRuntimeManager(ctx context.Context, interval time.Duration) {
if interval <= 0 {
interval = 15 * time.Second
}
logx.Info(ctx, "human_room_robot_runtime_manager_started", slog.Int64("interval_ms", interval.Milliseconds()))
ticker := time.NewTicker(interval)
defer ticker.Stop()
s.scanHumanRoomRobotRuntimes(ctx)
for {
select {
case <-ctx.Done():
s.stopAllHumanRoomRobotRuntimes()
return
case <-ticker.C:
s.scanHumanRoomRobotRuntimes(ctx)
}
}
}
func (s *Service) scanHumanRoomRobotRuntimes(ctx context.Context) {
config, exists, err := s.repository.GetHumanRoomRobotConfig(ctx)
if err != nil {
logx.Warn(ctx, "human_room_robot_config_load_failed", slog.String("error", err.Error()))
return
}
if !exists {
return
}
config = withHumanRoomRobotDefaults(config)
if !config.Enabled {
s.stopAllHumanRoomRobotRuntimes()
return
}
pools, err := s.loadHumanRoomRobotPools(ctx, config.AppCode)
if err != nil {
logx.Warn(ctx, "human_room_robot_pool_load_failed", slog.String("error", err.Error()))
return
}
config.CountryPools = pools
for _, pool := range config.CountryPools {
countryCode := normalizeRoomCountryCode(pool.CountryCode)
if countryCode == "" || len(pool.RobotUserIDs) == 0 {
continue
}
rooms, err := s.repository.ListHumanRobotCandidateRooms(ctx, config.AppCode, countryCode, config.CandidateRoomMaxOnline, config.RoomTargetMaxOnline, 50)
if err != nil {
logx.Warn(ctx, "human_room_robot_candidate_rooms_failed", slog.String("country_code", countryCode), slog.String("error", err.Error()))
continue
}
for _, room := range rooms {
if s.humanRoomRobotRuntimeConfigChanged(room.RoomID, config.UpdatedAtMS) {
s.stopHumanRoomRobotRuntime(room.RoomID)
}
if s.humanRoomRobotRuntimeExists(room.RoomID) {
continue
}
s.startHumanRoomRobotRuntime(ctx, config, countryCode, room.RoomID, pool.RobotUserIDs)
}
}
}
func (s *Service) loadHumanRoomRobotPools(ctx context.Context, appCode string) ([]HumanRoomRobotCountryPool, error) {
if s.humanRobotPoolProvider == nil {
return nil, xerr.New(xerr.Unavailable, "human room robot pool provider is not configured")
}
items, err := s.humanRobotPoolProvider.ListHumanRoomRobotPools(ctx, appCode)
if err != nil {
return nil, err
}
pools := make([]HumanRoomRobotCountryPool, 0, len(items))
for _, item := range items {
countryCode := normalizeRoomCountryCode(item.CountryCode)
ids := normalizeRobotUserIDs(item.RobotUserIDs)
if countryCode == "" || len(ids) == 0 {
continue
}
pools = append(pools, HumanRoomRobotCountryPool{CountryCode: countryCode, RobotUserIDs: ids})
}
return pools, nil
}
func (s *Service) startHumanRoomRobotRuntime(parent context.Context, config HumanRoomRobotConfig, countryCode string, roomID string, pool []int64) {
if parent.Err() != nil || roomID == "" || len(pool) == 0 {
return
}
s.humanRobotRuntimeMu.Lock()
if s.humanRobotRuntimes == nil {
s.humanRobotRuntimes = make(map[string]robotRoomRuntime)
}
if _, exists := s.humanRobotRuntimes[roomID]; exists {
s.humanRobotRuntimeMu.Unlock()
return
}
s.humanRobotRuntimeMu.Unlock()
roomCtx := appcode.WithContext(parent, config.AppCode)
targetOnline := randomHumanRoomTargetOnline(config)
selected, err := s.prepareHumanRoomRobots(roomCtx, config, roomID, pool, targetOnline)
if err != nil {
logx.Warn(roomCtx, "human_room_robot_prepare_failed", slog.String("room_id", roomID), slog.String("country_code", countryCode), slog.String("error", err.Error()))
return
}
if len(selected) == 0 {
return
}
s.humanRobotRuntimeMu.Lock()
if _, exists := s.humanRobotRuntimes[roomID]; exists {
s.humanRobotRuntimeMu.Unlock()
return
}
ctx, cancel := context.WithCancel(roomCtx)
token := fmt.Sprintf("%s:%d", roomID, time.Now().UTC().UnixNano())
s.humanRobotRuntimes[roomID] = robotRoomRuntime{cancel: cancel, token: token, configUpdatedAtMS: config.UpdatedAtMS}
s.humanRobotRuntimeMu.Unlock()
logx.Info(ctx, "human_room_robot_runtime_started",
slog.String("room_id", roomID),
slog.String("country_code", countryCode),
slog.Int("target_online", targetOnline),
slog.Int("active_robot_count", len(selected)),
)
go func() {
defer s.clearHumanRoomRobotRuntime(roomID, token)
s.runHumanRoomRobotRuntime(ctx, config, roomID, pool, selected, targetOnline)
}()
}
func (s *Service) prepareHumanRoomRobots(ctx context.Context, config HumanRoomRobotConfig, roomID string, pool []int64, targetOnline int) ([]int64, error) {
snapshot, err := s.currentSnapshot(ctx, roomID)
if err != nil {
return nil, err
}
if snapshot.GetStatus() != "active" {
return nil, nil
}
online := make(map[int64]bool, len(snapshot.GetOnlineUsers()))
for _, user := range snapshot.GetOnlineUsers() {
online[user.GetUserId()] = true
}
humanOnline := humanRoomRealOnlineCount(snapshot.GetOnlineUsers(), allHumanRoomRobotIDs(config))
if humanOnline >= int(config.CandidateRoomMaxOnline) || len(online) >= targetOnline {
return nil, nil
}
limit := targetOnline - len(online)
if limit <= 0 {
return nil, nil
}
freeSeats := freeSeatNumbers(snapshot.GetMicSeats())
if len(freeSeats) < limit {
limit = len(freeSeats)
}
if limit <= 0 {
return nil, nil
}
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
candidates := append([]int64(nil), pool...)
rng.Shuffle(len(candidates), func(i, j int) { candidates[i], candidates[j] = candidates[j], candidates[i] })
selected := make([]int64, 0, limit)
for _, userID := range candidates {
if len(selected) >= limit {
break
}
if userID <= 0 || online[userID] || s.robotHasActiveRoomPresence(ctx, userID, roomID) {
continue
}
seatNo := freeSeats[len(selected)]
if err := s.joinHumanRoomRobot(ctx, roomID, userID, seatNo, fmt.Sprintf("initial:%d:%d", userID, time.Now().UTC().UnixNano())); err != nil {
logx.Warn(ctx, "human_room_robot_initial_join_failed", slog.String("room_id", roomID), slog.Int64("robot_user_id", userID), slog.String("error", err.Error()))
continue
}
selected = append(selected, userID)
}
return selected, nil
}
func (s *Service) runHumanRoomRobotRuntime(ctx context.Context, config HumanRoomRobotConfig, roomID string, pool []int64, initialActive []int64, targetOnline int) {
activity := newRobotRoomActivity(pool)
for _, userID := range initialActive {
activity.markActive(userID)
}
markInitialHumanRoomGiftSenders(activity, initialActive, int(config.MaxGiftSenders))
giftSlots := make(chan struct{}, int(max(1, int(config.MaxGiftSenders))))
for _, userID := range pool {
userID := userID
go s.runHumanRobotPresenceLoop(ctx, config, roomID, pool, activity, userID, targetOnline)
go s.runHumanRobotNormalGiftLoop(ctx, config, roomID, activity, giftSlots, userID)
go s.runHumanRobotLuckyGiftLoop(ctx, config, roomID, activity, giftSlots, userID, config.LuckyGiftIDs, humanRobotLuckyPoolID, "lucky", 5_000_000)
go s.runHumanRobotLuckyGiftLoop(ctx, config, roomID, activity, giftSlots, userID, config.SuperLuckyGiftIDs, humanRobotSuperLuckyPoolID, "super_lucky", 20_000_000)
}
go s.runHumanRobotFillLoop(ctx, config, roomID, pool, activity, targetOnline)
<-ctx.Done()
}
func (s *Service) runHumanRobotFillLoop(ctx context.Context, config HumanRoomRobotConfig, roomID string, pool []int64, activity *robotRoomActivity, targetOnline int) {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
timer := time.NewTimer(time.Duration(1+rng.Intn(3)) * time.Second)
defer timer.Stop()
for {
select {
case <-ctx.Done():
return
case <-timer.C:
s.fillHumanRoomRobotsOnce(ctx, config, roomID, pool, activity, rng, targetOnline)
timer.Reset(time.Duration(5+rng.Intn(5)) * time.Second)
}
}
}
func (s *Service) fillHumanRoomRobotsOnce(ctx context.Context, config HumanRoomRobotConfig, roomID string, pool []int64, activity *robotRoomActivity, rng *rand.Rand, targetOnline int) {
snapshot, err := s.currentSnapshot(ctx, roomID)
if err != nil || snapshot.GetStatus() != "active" {
return
}
humanOnline := humanRoomRealOnlineCount(snapshot.GetOnlineUsers(), allHumanRoomRobotIDs(config))
if humanOnline >= int(config.CandidateRoomMaxOnline) || len(snapshot.GetOnlineUsers()) >= targetOnline {
return
}
limit := targetOnline - len(snapshot.GetOnlineUsers())
freeSeats := freeSeatNumbers(snapshot.GetMicSeats())
if len(freeSeats) < limit {
limit = len(freeSeats)
}
if limit <= 0 {
return
}
online := make(map[int64]bool, len(snapshot.GetOnlineUsers()))
for _, user := range snapshot.GetOnlineUsers() {
online[user.GetUserId()] = true
}
candidates := append([]int64(nil), pool...)
rng.Shuffle(len(candidates), func(i, j int) { candidates[i], candidates[j] = candidates[j], candidates[i] })
joined := 0
for _, userID := range candidates {
if joined >= limit {
return
}
if userID <= 0 || online[userID] || activity.isActive(userID) || s.robotHasActiveRoomPresence(ctx, userID, roomID) {
continue
}
seatNo := freeSeats[joined]
if err := s.joinHumanRoomRobot(ctx, roomID, userID, seatNo, fmt.Sprintf("fill:%d:%d", userID, time.Now().UTC().UnixNano())); err != nil {
logx.Warn(ctx, "human_room_robot_fill_join_failed", slog.String("room_id", roomID), slog.Int64("robot_user_id", userID), slog.String("error", err.Error()))
continue
}
activity.markActive(userID)
activity.markGiftSenderWithinLimit(userID, int(config.MaxGiftSenders))
online[userID] = true
joined++
}
}
func (s *Service) runHumanRobotPresenceLoop(ctx context.Context, config HumanRoomRobotConfig, roomID string, pool []int64, activity *robotRoomActivity, userID int64, targetOnline int) {
if userID <= 0 {
return
}
rng := rand.New(rand.NewSource(time.Now().UnixNano() + userID*43))
for {
if !activity.isActive(userID) {
if !waitRobotRuntimeDelay(ctx, time.Duration(300+rng.Intn(700))*time.Millisecond) {
return
}
continue
}
stay := time.Duration(randomInt64Range(rng, config.RobotStayMinMS, config.RobotStayMaxMS)) * time.Millisecond
if !waitRobotRuntimeDelay(ctx, stay) {
return
}
// 送礼名额绑定在房间内的少数机器人身上;送礼机器人离开时,补位机器人接替这个名额,保证房间内送礼者数量稳定且不会扩散到所有机器人。
wasGiftSender := activity.isGiftSender(userID)
if !activity.markInactive(userID) {
continue
}
seatNo := s.humanRoomRobotSeatNo(ctx, roomID, userID)
if err := s.leaveHumanRoomRobot(ctx, roomID, userID); err != nil {
logx.Warn(ctx, "human_room_robot_leave_failed", slog.String("room_id", roomID), slog.Int64("robot_user_id", userID), slog.String("error", err.Error()))
activity.markActive(userID)
if wasGiftSender {
activity.markGiftSender(userID)
}
continue
}
delay := time.Duration(randomInt64Range(rng, config.RobotReplaceMinMS, config.RobotReplaceMaxMS)) * time.Millisecond
if !waitRobotRuntimeDelay(ctx, delay) {
return
}
replacementID := s.pickHumanRoomReplacement(ctx, config, roomID, pool, activity, userID)
if replacementID <= 0 {
continue
}
if seatNo <= 0 {
seatNo = s.firstHumanRoomFreeSeatNo(ctx, roomID)
}
if seatNo <= 0 || !s.humanRoomNeedsRobot(ctx, config, roomID, targetOnline) {
continue
}
if err := s.joinHumanRoomRobot(ctx, roomID, replacementID, seatNo, fmt.Sprintf("replace:%d:%d", replacementID, time.Now().UTC().UnixNano())); err != nil {
logx.Warn(ctx, "human_room_robot_replace_join_failed", slog.String("room_id", roomID), slog.Int64("replacement_user_id", replacementID), slog.String("error", err.Error()))
continue
}
activity.markActive(replacementID)
if wasGiftSender || activity.giftSenderCount() < int(config.MaxGiftSenders) {
activity.markGiftSenderWithinLimit(replacementID, int(config.MaxGiftSenders))
}
}
}
func (s *Service) runHumanRobotNormalGiftLoop(ctx context.Context, config HumanRoomRobotConfig, roomID string, activity *robotRoomActivity, giftSlots chan struct{}, senderID int64) {
if config.NormalGiftIntervalMinMS <= 0 || config.NormalGiftIntervalMaxMS <= 0 || len(config.GiftIDs) == 0 {
return
}
rng := rand.New(rand.NewSource(time.Now().UnixNano() + senderID*59))
timer := time.NewTimer(humanRoomRobotNormalGiftDelay(config, rng))
defer timer.Stop()
for {
select {
case <-ctx.Done():
return
case <-timer.C:
if activity.isActive(senderID) && activity.isGiftSender(senderID) {
targetID := randomRobotTarget(rng, activity.activeIDs(), senderID)
giftID := randomString(rng, config.GiftIDs)
s.sendHumanRoomRobotGiftBestEffort(ctx, config, roomID, activity, giftSlots, senderID, targetID, giftID, "", "normal", 0)
}
timer.Reset(humanRoomRobotNormalGiftDelay(config, rng))
}
}
}
func (s *Service) runHumanRobotLuckyGiftLoop(ctx context.Context, config HumanRoomRobotConfig, roomID string, activity *robotRoomActivity, giftSlots chan struct{}, senderID int64, giftIDs []string, poolID string, kind string, multiplierPPM int64) {
if len(giftIDs) == 0 || config.LuckyComboMax <= 0 {
return
}
rng := rand.New(rand.NewSource(time.Now().UnixNano() + senderID*71))
for {
if !activity.isActive(senderID) || !activity.isGiftSender(senderID) {
if !waitRobotRuntimeDelay(ctx, time.Duration(300+rng.Intn(700))*time.Millisecond) {
return
}
continue
}
combo := randomInt64Range(rng, config.LuckyComboMin, config.LuckyComboMax)
for i := int64(0); i < combo; i++ {
if !activity.isActive(senderID) || !activity.isGiftSender(senderID) {
break
}
targetID := randomRobotTarget(rng, activity.activeIDs(), senderID)
giftID := randomString(rng, giftIDs)
s.sendHumanRoomRobotGiftBestEffort(ctx, config, roomID, activity, giftSlots, senderID, targetID, giftID, poolID, kind, multiplierPPM)
if !waitRobotGiftPace(ctx, rng) {
return
}
}
pause := time.Duration(randomInt64Range(rng, config.LuckyPauseMinMS, config.LuckyPauseMaxMS)) * time.Millisecond
if !waitRobotRuntimeDelay(ctx, pause) {
return
}
}
}
func (s *Service) sendHumanRoomRobotGiftBestEffort(ctx context.Context, config HumanRoomRobotConfig, roomID string, activity *robotRoomActivity, giftSlots chan struct{}, senderID int64, targetID int64, giftID string, poolID string, kind string, multiplierPPM int64) {
if !activity.isActive(senderID) || !activity.isGiftSender(senderID) || !activity.isActive(targetID) || giftID == "" {
return
}
select {
case giftSlots <- struct{}{}:
defer func() { <-giftSlots }()
default:
return
}
_, err := s.RobotSendGift(ctx, RobotSendGiftInput{
Meta: humanRoomRobotCommandMeta(config, roomID, senderID, fmt.Sprintf("gift:%s:%d:%d", kind, targetID, time.Now().UTC().UnixNano())),
TargetUserID: targetID,
GiftID: giftID,
GiftCount: 1,
PoolID: poolID,
RobotUserIDs: activity.pool,
SyntheticMultiplierPPM: multiplierPPM,
RealRoomHeat: true,
})
if err != nil {
logx.Warn(ctx, "human_room_robot_send_gift_failed", slog.String("room_id", roomID), slog.String("kind", kind), slog.Int64("sender_user_id", senderID), slog.Int64("target_user_id", targetID), slog.String("gift_id", giftID), slog.String("error", err.Error()))
}
}
func markInitialHumanRoomGiftSenders(activity *robotRoomActivity, initialActive []int64, maxSenders int) {
if activity == nil || maxSenders <= 0 || len(initialActive) == 0 {
return
}
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
candidates := append([]int64(nil), initialActive...)
rng.Shuffle(len(candidates), func(i int, j int) {
candidates[i], candidates[j] = candidates[j], candidates[i]
})
for _, userID := range candidates {
if activity.giftSenderCount() >= maxSenders {
return
}
activity.markGiftSenderWithinLimit(userID, maxSenders)
}
}
func humanRoomRobotNormalGiftDelay(config HumanRoomRobotConfig, rng *rand.Rand) time.Duration {
minMS := config.NormalGiftIntervalMinMS
maxMS := config.NormalGiftIntervalMaxMS
if minMS <= 0 && maxMS <= 0 && config.NormalGiftIntervalMS > 0 {
minMS = config.NormalGiftIntervalMS
maxMS = config.NormalGiftIntervalMS
}
if minMS <= 0 {
minMS = defaultHumanRobotNormalGiftIntervalMinMS
}
if maxMS < minMS {
maxMS = minMS
}
return time.Duration(randomInt64Range(rng, minMS, maxMS)) * time.Millisecond
}
func randomHumanRoomTargetOnline(config HumanRoomRobotConfig) int {
minOnline := config.RoomTargetMinOnline
maxOnline := config.RoomTargetMaxOnline
if minOnline <= 0 && maxOnline <= 0 && config.RoomFullStopOnline > 0 {
minOnline = config.RoomFullStopOnline
maxOnline = config.RoomFullStopOnline
}
if minOnline <= 0 {
minOnline = defaultHumanRobotRoomTargetMinOnline
}
if maxOnline < minOnline {
maxOnline = minOnline
}
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
return int(randomInt64Range(rng, int64(minOnline), int64(maxOnline)))
}
func (s *Service) joinHumanRoomRobot(ctx context.Context, roomID string, userID int64, seatNo int32, suffix string) error {
if _, err := s.JoinRoom(ctx, &roomv1.JoinRoomRequest{
Meta: humanRoomRobotCommandMeta(HumanRoomRobotConfig{AppCode: appcode.FromContext(ctx)}, roomID, userID, "join:"+suffix),
Role: "audience",
}); err != nil {
return err
}
if _, err := s.RobotVirtualMicUp(ctx, RobotMicUpInput{
Meta: humanRoomRobotCommandMeta(HumanRoomRobotConfig{AppCode: appcode.FromContext(ctx)}, roomID, userID, "mic:"+suffix),
TargetUserID: userID,
SeatNo: seatNo,
}); err != nil {
if xerr.CodeOf(err) == xerr.Conflict && strings.Contains(xerr.MessageOf(err), "already on seat") {
return nil
}
return err
}
return nil
}
func (s *Service) leaveHumanRoomRobot(ctx context.Context, roomID string, userID int64) error {
_, err := s.LeaveRoom(ctx, &roomv1.LeaveRoomRequest{
Meta: humanRoomRobotCommandMeta(HumanRoomRobotConfig{AppCode: appcode.FromContext(ctx)}, roomID, userID, fmt.Sprintf("leave:%d:%d", userID, time.Now().UTC().UnixNano())),
})
return err
}
func (s *Service) pickHumanRoomReplacement(ctx context.Context, config HumanRoomRobotConfig, roomID string, pool []int64, activity *robotRoomActivity, departingUserID int64) int64 {
active := make(map[int64]bool, len(activity.activeIDs()))
for _, id := range activity.activeIDs() {
active[id] = true
}
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
candidates := append([]int64(nil), pool...)
rng.Shuffle(len(candidates), func(i, j int) { candidates[i], candidates[j] = candidates[j], candidates[i] })
for _, userID := range candidates {
if userID <= 0 || active[userID] || userID == departingUserID || s.robotHasActiveRoomPresence(ctx, userID, roomID) {
continue
}
return userID
}
if !s.robotHasActiveRoomPresence(ctx, departingUserID, roomID) {
return departingUserID
}
return 0
}
func (s *Service) humanRoomNeedsRobot(ctx context.Context, config HumanRoomRobotConfig, roomID string, targetOnline int) bool {
snapshot, err := s.currentSnapshot(ctx, roomID)
if err != nil || snapshot.GetStatus() != "active" {
return false
}
humanOnline := humanRoomRealOnlineCount(snapshot.GetOnlineUsers(), allHumanRoomRobotIDs(config))
return humanOnline < int(config.CandidateRoomMaxOnline) && len(snapshot.GetOnlineUsers()) < targetOnline
}
func (s *Service) robotHasActiveRoomPresence(ctx context.Context, userID int64, allowedRoomID string) bool {
presence, exists, err := s.repository.GetCurrentRoomPresence(ctx, userID)
if err != nil || !exists {
return false
}
return presence.RoomID != "" && presence.RoomID != allowedRoomID
}
func (s *Service) humanRoomRobotSeatNo(ctx context.Context, roomID string, userID int64) int32 {
snapshot, err := s.currentSnapshot(ctx, roomID)
if err != nil {
return 0
}
for _, seat := range snapshot.GetMicSeats() {
if seat.GetUserId() == userID {
return seat.GetSeatNo()
}
}
return 0
}
func (s *Service) firstHumanRoomFreeSeatNo(ctx context.Context, roomID string) int32 {
snapshot, err := s.currentSnapshot(ctx, roomID)
if err != nil {
return 0
}
seats := freeSeatNumbers(snapshot.GetMicSeats())
if len(seats) == 0 {
return 0
}
return seats[0]
}
func (s *Service) humanRoomRobotRuntimeExists(roomID string) bool {
s.humanRobotRuntimeMu.Lock()
defer s.humanRobotRuntimeMu.Unlock()
_, exists := s.humanRobotRuntimes[roomID]
return exists
}
func (s *Service) humanRoomRobotRuntimeConfigChanged(roomID string, updatedAtMS int64) bool {
if updatedAtMS <= 0 {
return false
}
s.humanRobotRuntimeMu.Lock()
defer s.humanRobotRuntimeMu.Unlock()
runtime, exists := s.humanRobotRuntimes[roomID]
return exists && runtime.configUpdatedAtMS > 0 && runtime.configUpdatedAtMS != updatedAtMS
}
func (s *Service) stopHumanRoomRobotRuntime(roomID string) {
s.humanRobotRuntimeMu.Lock()
runtime := s.humanRobotRuntimes[roomID]
delete(s.humanRobotRuntimes, roomID)
s.humanRobotRuntimeMu.Unlock()
if runtime.cancel != nil {
runtime.cancel()
}
}
func (s *Service) clearHumanRoomRobotRuntime(roomID string, token string) {
s.humanRobotRuntimeMu.Lock()
defer s.humanRobotRuntimeMu.Unlock()
runtime, exists := s.humanRobotRuntimes[roomID]
if !exists || runtime.token != token {
return
}
delete(s.humanRobotRuntimes, roomID)
}
func (s *Service) stopAllHumanRoomRobotRuntimes() {
s.humanRobotRuntimeMu.Lock()
cancels := make([]context.CancelFunc, 0, len(s.humanRobotRuntimes))
for roomID, runtime := range s.humanRobotRuntimes {
if runtime.cancel != nil {
cancels = append(cancels, runtime.cancel)
}
delete(s.humanRobotRuntimes, roomID)
}
s.humanRobotRuntimeMu.Unlock()
for _, cancel := range cancels {
cancel()
}
}
func normalizeHumanRoomRobotConfig(appCode string, input *roomv1.AdminHumanRoomRobotConfig, adminID uint64, nowMS int64) (HumanRoomRobotConfig, error) {
if input == nil {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "human room robot config is required")
}
config := HumanRoomRobotConfig{
AppCode: appcode.Normalize(appCode),
Enabled: input.GetEnabled(),
CandidateRoomMaxOnline: input.GetCandidateRoomMaxOnline(),
RoomFullStopOnline: input.GetRoomFullStopOnline(),
RoomTargetMinOnline: input.GetRoomTargetMinOnline(),
RoomTargetMaxOnline: input.GetRoomTargetMaxOnline(),
RobotStayMinMS: input.GetRobotStayMinMs(),
RobotStayMaxMS: input.GetRobotStayMaxMs(),
RobotReplaceMinMS: input.GetRobotReplaceMinMs(),
RobotReplaceMaxMS: input.GetRobotReplaceMaxMs(),
NormalGiftIntervalMS: input.GetNormalGiftIntervalMs(),
NormalGiftIntervalMinMS: input.GetNormalGiftIntervalMinMs(),
NormalGiftIntervalMaxMS: input.GetNormalGiftIntervalMaxMs(),
GiftIDs: normalizeStringSet(input.GetGiftIds()),
LuckyGiftIDs: normalizeStringSet(input.GetLuckyGiftIds()),
SuperLuckyGiftIDs: normalizeStringSet(input.GetSuperLuckyGiftIds()),
LuckyComboMin: input.GetLuckyComboMin(),
LuckyComboMax: input.GetLuckyComboMax(),
LuckyPauseMinMS: input.GetLuckyPauseMinMs(),
LuckyPauseMaxMS: input.GetLuckyPauseMaxMs(),
MaxGiftSenders: input.GetMaxGiftSenders(),
UpdatedByAdminID: adminID,
CreatedAtMS: input.GetCreatedAtMs(),
UpdatedAtMS: nowMS,
}
config = withHumanRoomRobotDefaults(config)
if config.CandidateRoomMaxOnline <= 0 || config.RoomTargetMinOnline <= 0 || config.RoomTargetMaxOnline < config.RoomTargetMinOnline {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "room online thresholds are invalid")
}
if config.RobotStayMinMS <= 0 || config.RobotStayMaxMS < config.RobotStayMinMS {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "robot stay range is invalid")
}
if config.RobotReplaceMinMS < 0 || config.RobotReplaceMaxMS < config.RobotReplaceMinMS {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "robot replace range is invalid")
}
if config.NormalGiftIntervalMinMS <= 0 || config.NormalGiftIntervalMaxMS < config.NormalGiftIntervalMinMS {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "normal gift interval range is invalid")
}
if config.Enabled && len(config.GiftIDs) == 0 {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "gift_ids is required")
}
if config.Enabled && len(config.LuckyGiftIDs) == 0 && len(config.SuperLuckyGiftIDs) == 0 {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "lucky gift ids are required")
}
if config.LuckyComboMin <= 0 || config.LuckyComboMax < config.LuckyComboMin {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "lucky combo range is invalid")
}
if config.LuckyPauseMinMS <= 0 || config.LuckyPauseMaxMS < config.LuckyPauseMinMS {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "lucky pause range is invalid")
}
if config.MaxGiftSenders <= 0 {
return HumanRoomRobotConfig{}, xerr.New(xerr.InvalidArgument, "max_gift_senders is required")
}
return config, nil
}
func withHumanRoomRobotDefaults(config HumanRoomRobotConfig) HumanRoomRobotConfig {
if config.AppCode == "" {
config.AppCode = appcode.Default
}
if config.CandidateRoomMaxOnline <= 0 {
config.CandidateRoomMaxOnline = defaultHumanRobotCandidateRoomMaxOnline
}
if config.RoomTargetMinOnline <= 0 && config.RoomTargetMaxOnline <= 0 {
if config.RoomFullStopOnline > 0 {
config.RoomTargetMinOnline = config.RoomFullStopOnline
config.RoomTargetMaxOnline = config.RoomFullStopOnline
} else {
config.RoomTargetMinOnline = defaultHumanRobotRoomTargetMinOnline
config.RoomTargetMaxOnline = defaultHumanRobotRoomTargetMaxOnline
}
}
if config.RoomFullStopOnline <= 0 {
config.RoomFullStopOnline = config.RoomTargetMaxOnline
}
if config.RobotStayMinMS <= 0 && config.RobotStayMaxMS <= 0 {
config.RobotStayMinMS = defaultHumanRobotStayMinMS
config.RobotStayMaxMS = defaultHumanRobotStayMaxMS
}
if config.RobotReplaceMinMS == 0 && config.RobotReplaceMaxMS == 0 {
config.RobotReplaceMinMS = defaultHumanRobotReplaceMinMS
config.RobotReplaceMaxMS = defaultHumanRobotReplaceMaxMS
}
if config.NormalGiftIntervalMinMS <= 0 && config.NormalGiftIntervalMaxMS <= 0 {
if config.NormalGiftIntervalMS > 0 {
config.NormalGiftIntervalMinMS = config.NormalGiftIntervalMS
config.NormalGiftIntervalMaxMS = config.NormalGiftIntervalMS
} else {
config.NormalGiftIntervalMinMS = defaultHumanRobotNormalGiftIntervalMinMS
config.NormalGiftIntervalMaxMS = defaultHumanRobotNormalGiftIntervalMaxMS
}
}
if config.NormalGiftIntervalMS <= 0 {
config.NormalGiftIntervalMS = config.NormalGiftIntervalMaxMS
}
if config.LuckyComboMin <= 0 && config.LuckyComboMax <= 0 {
config.LuckyComboMin = defaultHumanRobotLuckyComboMin
config.LuckyComboMax = defaultHumanRobotLuckyComboMax
}
if config.LuckyPauseMinMS <= 0 && config.LuckyPauseMaxMS <= 0 {
config.LuckyPauseMinMS = defaultHumanRobotLuckyPauseMinMS
config.LuckyPauseMaxMS = defaultHumanRobotLuckyPauseMaxMS
}
if config.MaxGiftSenders <= 0 {
config.MaxGiftSenders = defaultHumanRobotMaxGiftSenders
}
return config
}
func defaultHumanRoomRobotConfig(appCode string, nowMS int64) HumanRoomRobotConfig {
return withHumanRoomRobotDefaults(HumanRoomRobotConfig{AppCode: appcode.Normalize(appCode), CreatedAtMS: nowMS, UpdatedAtMS: nowMS})
}
func humanRoomRobotConfigToProto(config HumanRoomRobotConfig) *roomv1.AdminHumanRoomRobotConfig {
config = withHumanRoomRobotDefaults(config)
out := &roomv1.AdminHumanRoomRobotConfig{
AppCode: config.AppCode,
Enabled: config.Enabled,
CandidateRoomMaxOnline: config.CandidateRoomMaxOnline,
RoomFullStopOnline: config.RoomFullStopOnline,
RoomTargetMinOnline: config.RoomTargetMinOnline,
RoomTargetMaxOnline: config.RoomTargetMaxOnline,
RobotStayMinMs: config.RobotStayMinMS,
RobotStayMaxMs: config.RobotStayMaxMS,
RobotReplaceMinMs: config.RobotReplaceMinMS,
RobotReplaceMaxMs: config.RobotReplaceMaxMS,
NormalGiftIntervalMs: config.NormalGiftIntervalMS,
NormalGiftIntervalMinMs: config.NormalGiftIntervalMinMS,
NormalGiftIntervalMaxMs: config.NormalGiftIntervalMaxMS,
GiftIds: append([]string(nil), config.GiftIDs...),
LuckyGiftIds: append([]string(nil), config.LuckyGiftIDs...),
SuperLuckyGiftIds: append([]string(nil), config.SuperLuckyGiftIDs...),
LuckyComboMin: config.LuckyComboMin,
LuckyComboMax: config.LuckyComboMax,
LuckyPauseMinMs: config.LuckyPauseMinMS,
LuckyPauseMaxMs: config.LuckyPauseMaxMS,
MaxGiftSenders: config.MaxGiftSenders,
UpdatedByAdminId: config.UpdatedByAdminID,
CreatedAtMs: config.CreatedAtMS,
UpdatedAtMs: config.UpdatedAtMS,
}
return out
}
func humanRoomRobotCommandMeta(config HumanRoomRobotConfig, roomID string, actorUserID int64, suffix string) *roomv1.RequestMeta {
commandID := fmt.Sprintf("human-room-robot:%s:%s", roomID, strings.TrimSpace(suffix))
if len(commandID) > 128 {
commandID = commandID[:128]
}
return &roomv1.RequestMeta{
RequestId: commandID,
CommandId: commandID,
ActorUserId: actorUserID,
RoomId: roomID,
AppCode: config.AppCode,
SentAtMs: time.Now().UTC().UnixMilli(),
}
}
func humanRoomRealOnlineCount(users []*roomv1.RoomUser, robotIDs map[int64]bool) int {
count := 0
for _, user := range users {
if user.GetUserId() <= 0 || robotIDs[user.GetUserId()] {
continue
}
count++
}
return count
}
func allHumanRoomRobotIDs(config HumanRoomRobotConfig) map[int64]bool {
out := make(map[int64]bool)
for _, pool := range config.CountryPools {
for _, id := range pool.RobotUserIDs {
if id > 0 {
out[id] = true
}
}
}
return out
}
func freeSeatNumbers(seats []*roomv1.SeatState) []int32 {
out := make([]int32, 0, len(seats))
for _, seat := range seats {
if seat.GetSeatNo() > 0 && seat.GetUserId() == 0 && !seat.GetLocked() {
out = append(out, seat.GetSeatNo())
}
}
return out
}

View File

@ -0,0 +1,52 @@
package service
import (
"math/rand"
"testing"
"time"
)
func TestHumanRoomRobotGiftSenderLimit(t *testing.T) {
activity := newRobotRoomActivity([]int64{101, 102, 103, 104})
for _, userID := range []int64{101, 102, 103, 104} {
activity.markActive(userID)
}
markInitialHumanRoomGiftSenders(activity, []int64{101, 102, 103, 104}, 2)
if got := activity.giftSenderCount(); got != 2 {
t.Fatalf("gift sender count mismatch: got %d want 2", got)
}
if activity.markGiftSenderWithinLimit(104, 2) {
t.Fatalf("gift sender limit allowed one more sender")
}
}
func TestHumanRoomRobotNormalGiftDelayRange(t *testing.T) {
rng := rand.New(rand.NewSource(1))
config := HumanRoomRobotConfig{NormalGiftIntervalMinMS: 1000, NormalGiftIntervalMaxMS: 20000}
for i := 0; i < 100; i++ {
delay := humanRoomRobotNormalGiftDelay(config, rng)
if delay < time.Second || delay > 20*time.Second {
t.Fatalf("gift delay out of range: %s", delay)
}
}
}
func TestRandomHumanRoomTargetOnlineRange(t *testing.T) {
config := HumanRoomRobotConfig{RoomTargetMinOnline: 8, RoomTargetMaxOnline: 10}
for i := 0; i < 100; i++ {
target := randomHumanRoomTargetOnline(config)
if target < 8 || target > 10 {
t.Fatalf("target online out of range: %d", target)
}
}
}
func TestRandomHumanRoomTargetOnlineLegacyFixedValue(t *testing.T) {
config := HumanRoomRobotConfig{RoomFullStopOnline: 10}
for i := 0; i < 20; i++ {
if target := randomHumanRoomTargetOnline(config); target != 10 {
t.Fatalf("legacy target online mismatch: got %d want 10", target)
}
}
}

View File

@ -38,6 +38,7 @@ type roomListCursor struct {
Query string `json:"query,omitempty"`
CountryCode string `json:"country_code,omitempty"`
ViewerCountry string `json:"viewer_country,omitempty"`
AllRegions bool `json:"all_regions,omitempty"`
SortScore int64 `json:"sort_score,omitempty"`
CreatedAtMS int64 `json:"created_at_ms,omitempty"`
UpdatedAtMS int64 `json:"updated_at_ms,omitempty"`
@ -70,7 +71,8 @@ func (s *Service) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (
}
countryCode := normalizeRoomCountryCode(req.GetCountryCode())
viewerCountryCode := normalizeRoomCountryCode(req.GetViewerCountryCode())
cursor, err := decodeRoomListCursor(tab, query, countryCode, viewerCountryCode, req.GetCursor())
allVisibleRegions := req.GetAllVisibleRegions()
cursor, err := decodeRoomListCursor(tab, query, countryCode, viewerCountryCode, allVisibleRegions, req.GetCursor())
if err != nil {
return nil, err
}
@ -78,6 +80,7 @@ func (s *Service) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (
entries, err := s.repository.ListRoomListEntries(ctx, RoomListQuery{
AppCode: appcode.FromContext(ctx),
VisibleRegionID: normalizeVisibleRegionID(req.GetVisibleRegionId()),
AllVisibleRegions: allVisibleRegions,
Tab: tab,
Query: query,
CountryCode: countryCode,
@ -96,7 +99,7 @@ func (s *Service) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (
return nil, err
}
return roomListResponseFromEntries(tab, query, countryCode, viewerCountryCode, entries, limit), nil
return roomListResponseFromEntries(tab, query, countryCode, viewerCountryCode, allVisibleRegions, entries, limit), nil
}
// ListRoomFeeds 查询 Mine 页 visited/friend/following/followed 房间流。
@ -118,7 +121,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, "", "", false, req.GetCursor())
if err != nil {
return nil, err
}
@ -166,7 +169,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, "", "", false, entries, limit), nil
}
// GetMyRoom 查询当前用户自己创建的房间,不依赖 room_list_entries 投影命中。
@ -199,12 +202,12 @@ func (s *Service) GetMyRoom(ctx context.Context, req *roomv1.GetMyRoomRequest) (
}, nil
}
func roomListResponseFromEntries(tab string, query string, countryCode string, viewerCountryCode string, entries []RoomListEntry, limit int) *roomv1.ListRoomsResponse {
func roomListResponseFromEntries(tab string, query string, countryCode string, viewerCountryCode string, allRegions bool, entries []RoomListEntry, limit int) *roomv1.ListRoomsResponse {
nextCursor := ""
if len(entries) > limit {
// 多查一条用于判断是否存在下一页;返回数据只包含请求的 limit 条。
last := entries[limit-1]
nextCursor = encodeRoomListCursor(tab, query, countryCode, viewerCountryCode, last)
nextCursor = encodeRoomListCursor(tab, query, countryCode, viewerCountryCode, allRegions, last)
entries = entries[:limit]
}
@ -409,10 +412,10 @@ func normalizeRoomCountryCode(countryCode string) string {
}
// decodeRoomListCursor 校验不透明 cursor 和当前 tab 一致,禁止客户端跨排序维度复用游标。
func decodeRoomListCursor(tab string, query string, countryCode string, viewerCountryCode string, encoded string) (roomListCursor, error) {
func decodeRoomListCursor(tab string, query string, countryCode string, viewerCountryCode string, allRegions bool, encoded string) (roomListCursor, error) {
encoded = strings.TrimSpace(encoded)
if encoded == "" {
return roomListCursor{Tab: tab, Query: query, CountryCode: countryCode, ViewerCountry: viewerCountryCode}, nil
return roomListCursor{Tab: tab, Query: query, CountryCode: countryCode, ViewerCountry: viewerCountryCode, AllRegions: allRegions}, nil
}
payload, err := base64.RawURLEncoding.DecodeString(encoded)
@ -424,7 +427,7 @@ func decodeRoomListCursor(tab string, query string, countryCode string, viewerCo
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.CountryCode != countryCode || cursor.ViewerCountry != viewerCountryCode || cursor.RoomID == "" {
if cursor.Tab != tab || cursor.Query != query || cursor.CountryCode != countryCode || cursor.ViewerCountry != viewerCountryCode || cursor.AllRegions != allRegions || cursor.RoomID == "" {
return roomListCursor{}, xerr.New(xerr.InvalidArgument, "cursor is invalid")
}
@ -433,12 +436,13 @@ func decodeRoomListCursor(tab string, query string, countryCode string, viewerCo
// encodeRoomListCursor 把最后一条列表记录编码成下一页边界。
// cursor 不暴露契约语义,后续调整排序字段时可以只兼容服务端解析逻辑。
func encodeRoomListCursor(tab string, query string, countryCode string, viewerCountryCode string, entry RoomListEntry) string {
func encodeRoomListCursor(tab string, query string, countryCode string, viewerCountryCode string, allRegions bool, entry RoomListEntry) string {
cursor := roomListCursor{
Tab: tab,
Query: query,
CountryCode: countryCode,
ViewerCountry: viewerCountryCode,
AllRegions: allRegions,
SortScore: entry.SortScore,
CreatedAtMS: entry.CreatedAtMS,
UpdatedAtMS: entry.UpdatedAtMS,

View File

@ -17,6 +17,8 @@ const (
outboxRetryExponentialBackoff = "exponential_backoff"
// outboxWorkerName 固定写入日志,便于后续按 worker 聚合检索。
outboxWorkerName = "room_outbox"
// robotOutboxWorkerName 固定标识机器人展示事件通道,避免和主 room_outbox 监控混淆。
robotOutboxWorkerName = "room_robot_outbox"
)
// OutboxWorkerOptions 控制 room_outbox pending 事件的持续补偿循环。
@ -88,16 +90,25 @@ func normalizeOutboxWorkerOptions(options OutboxWorkerOptions) OutboxWorkerOptio
// RunOutboxWorker 持续扫描 pending outbox它不执行房间命令只投递已持久化事件。
func (s *Service) RunOutboxWorker(ctx context.Context, options OutboxWorkerOptions) {
s.runOutboxWorker(ctx, options, outboxWorkerName, s.ProcessPendingOutbox)
}
// RunRobotOutboxWorker 持续扫描机器人房间展示 outbox它和主 room_outbox 完全分开抢占。
func (s *Service) RunRobotOutboxWorker(ctx context.Context, options OutboxWorkerOptions) {
s.runOutboxWorker(ctx, options, robotOutboxWorkerName, s.ProcessPendingRobotOutbox)
}
func (s *Service) runOutboxWorker(ctx context.Context, options OutboxWorkerOptions, workerName string, process func(context.Context, OutboxWorkerOptions) error) {
options = normalizeOutboxWorkerOptions(options)
if options.RetryStrategy != outboxRetryExponentialBackoff {
// 配置层会拒绝未知策略;这里兜底避免测试或手写构造静默改变语义。
logx.Error(ctx, "worker_stopped", fmt.Errorf("unsupported retry_strategy"), slog.String("worker", outboxWorkerName), slog.String("node_id", s.nodeID))
logx.Error(ctx, "worker_stopped", fmt.Errorf("unsupported retry_strategy"), slog.String("worker", workerName), slog.String("node_id", s.nodeID))
return
}
// 启动后先执行一轮,避免服务刚恢复时还要等一个 poll interval 才补偿历史事件。
if err := s.ProcessPendingOutbox(ctx, options); err != nil && ctx.Err() == nil {
logx.Error(ctx, "worker_batch_failed", err, slog.String("worker", outboxWorkerName), slog.String("node_id", s.nodeID), slog.Int("batch_size", options.BatchSize))
if err := process(ctx, options); err != nil && ctx.Err() == nil {
logx.Error(ctx, "worker_batch_failed", err, slog.String("worker", workerName), slog.String("node_id", s.nodeID), slog.Int("batch_size", options.BatchSize))
}
ticker := time.NewTicker(options.PollInterval)
@ -108,8 +119,8 @@ func (s *Service) RunOutboxWorker(ctx context.Context, options OutboxWorkerOptio
case <-ctx.Done():
return
case <-ticker.C:
if err := s.ProcessPendingOutbox(ctx, options); err != nil && ctx.Err() == nil {
logx.Error(ctx, "worker_batch_failed", err, slog.String("worker", outboxWorkerName), slog.String("node_id", s.nodeID), slog.Int("batch_size", options.BatchSize))
if err := process(ctx, options); err != nil && ctx.Err() == nil {
logx.Error(ctx, "worker_batch_failed", err, slog.String("worker", workerName), slog.String("node_id", s.nodeID), slog.Int("batch_size", options.BatchSize))
}
}
}
@ -117,13 +128,22 @@ func (s *Service) RunOutboxWorker(ctx context.Context, options OutboxWorkerOptio
// ProcessPendingOutbox 把待投递事件补偿性地推送给异步消费者。
func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorkerOptions) error {
return s.processPendingOutbox(ctx, options, outboxWorkerName, false)
}
// ProcessPendingRobotOutbox 把机器人展示事件补偿性地推送给独立机器人异步消费者。
func (s *Service) ProcessPendingRobotOutbox(ctx context.Context, options OutboxWorkerOptions) error {
return s.processPendingOutbox(ctx, options, robotOutboxWorkerName, true)
}
func (s *Service) processPendingOutbox(ctx context.Context, options OutboxWorkerOptions, workerName string, robotLane bool) error {
options = normalizeOutboxWorkerOptions(options)
if options.RetryStrategy != outboxRetryExponentialBackoff {
return fmt.Errorf("unsupported outbox retry_strategy %q", options.RetryStrategy)
}
// 补偿 worker 先抢占 pending/retryable 事件,再投递,避免多机同时处理同一批。
records, err := s.repository.ClaimPendingOutbox(ctx, s.nodeID, options.BatchSize, time.Now().UTC().Add(options.PublishTimeout).UnixMilli())
records, err := s.claimPendingOutbox(ctx, robotLane, options)
if err != nil {
return err
}
@ -138,13 +158,13 @@ func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorker
if record.RetryCount >= options.MaxRetryCount {
// 已达到最大失败次数的历史事件直接转死信,防止每轮 worker 继续打外部系统。
markCtx, markCancel := context.WithTimeout(appcode.WithContext(context.Background(), record.AppCode), options.PublishTimeout)
markErr := s.repository.MarkOutboxDead(markCtx, record.EventID, deadLetterReason(record))
markErr := s.markOutboxDead(markCtx, robotLane, record.EventID, deadLetterReason(record))
markCancel()
if markErr != nil {
return markErr
}
logx.Error(ctx, "outbox_dead_letter", nil,
slog.String("worker", outboxWorkerName),
slog.String("worker", workerName),
slog.String("node_id", s.nodeID),
slog.String("event_id", record.EventID),
slog.String("event_type", record.EventType),
@ -157,20 +177,20 @@ func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorker
publishCtx, cancel := context.WithTimeout(appcode.WithContext(context.Background(), record.AppCode), options.PublishTimeout)
// 发布上下文不继承 worker ctx避免 shutdown 取消导致已开始的单条外部投递无界处于未知状态。
err := s.publishOutboxRecord(publishCtx, record)
err := s.publishOutboxRecord(publishCtx, record, robotLane)
cancel()
if err != nil {
// 投递失败转为 retryable并写入指数退避时间等待下一轮 worker 到期后再抢占。
nextRetryAtMS := time.Now().UTC().Add(outboxBackoff(record.RetryCount+1, options)).UnixMilli()
markCtx, markCancel := context.WithTimeout(appcode.WithContext(context.Background(), record.AppCode), options.PublishTimeout)
markErr := s.repository.MarkOutboxRetryable(markCtx, record.EventID, trimOutboxError(err.Error()), nextRetryAtMS)
markErr := s.markOutboxRetryable(markCtx, robotLane, record.EventID, trimOutboxError(err.Error()), nextRetryAtMS)
markCancel()
if markErr != nil {
return markErr
}
logx.Warn(ctx, "outbox_publish_retryable",
slog.String("worker", outboxWorkerName),
slog.String("worker", workerName),
slog.String("node_id", s.nodeID),
slog.String("event_id", record.EventID),
slog.String("event_type", record.EventType),
@ -184,14 +204,14 @@ func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorker
// 只有外部发布成功后才能标记 delivered。
markCtx, markCancel := context.WithTimeout(appcode.WithContext(context.Background(), record.AppCode), options.PublishTimeout)
markErr := s.repository.MarkOutboxDelivered(markCtx, record.EventID)
markErr := s.markOutboxDelivered(markCtx, robotLane, record.EventID)
markCancel()
if markErr != nil {
return markErr
}
logx.Info(ctx, "outbox_delivered",
slog.String("worker", outboxWorkerName),
slog.String("worker", workerName),
slog.String("node_id", s.nodeID),
slog.String("event_id", record.EventID),
slog.String("event_type", record.EventType),
@ -203,11 +223,46 @@ func (s *Service) ProcessPendingOutbox(ctx context.Context, options OutboxWorker
return nil
}
func (s *Service) publishOutboxRecord(ctx context.Context, record outbox.Record) error {
func (s *Service) claimPendingOutbox(ctx context.Context, robotLane bool, options OutboxWorkerOptions) ([]outbox.Record, error) {
lockUntilMS := time.Now().UTC().Add(options.PublishTimeout).UnixMilli()
if robotLane {
return s.repository.ClaimPendingRobotOutbox(ctx, s.nodeID, options.BatchSize, lockUntilMS)
}
return s.repository.ClaimPendingOutbox(ctx, s.nodeID, options.BatchSize, lockUntilMS)
}
func (s *Service) markOutboxDelivered(ctx context.Context, robotLane bool, eventID string) error {
if robotLane {
return s.repository.MarkRobotOutboxDelivered(ctx, eventID)
}
return s.repository.MarkOutboxDelivered(ctx, eventID)
}
func (s *Service) markOutboxRetryable(ctx context.Context, robotLane bool, eventID string, lastErr string, nextRetryAtMS int64) error {
if robotLane {
return s.repository.MarkRobotOutboxRetryable(ctx, eventID, lastErr, nextRetryAtMS)
}
return s.repository.MarkOutboxRetryable(ctx, eventID, lastErr, nextRetryAtMS)
}
func (s *Service) markOutboxDead(ctx context.Context, robotLane bool, eventID string, lastErr string) error {
if robotLane {
return s.repository.MarkRobotOutboxDead(ctx, eventID, lastErr)
}
return s.repository.MarkOutboxDead(ctx, eventID, lastErr)
}
func (s *Service) publishOutboxRecord(ctx context.Context, record outbox.Record, robotLane bool) error {
// Ignited 先安排延迟发射,再对外广播事件;如果 MQ 延迟调度不可用,本条 outbox 保持 retryable。
if err := s.scheduleRoomRocketLaunchFromEnvelope(ctx, record.Envelope); err != nil {
return err
}
if robotLane {
if s.robotOutboxPublisher == nil {
return nil
}
return s.robotOutboxPublisher.PublishOutboxEvent(ctx, record.Envelope)
}
if s.outboxPublisher == nil {
return nil
}

View File

@ -92,6 +92,7 @@ func (s *Service) mutateRoom(ctx context.Context, cmd command.Command, replayabl
CreatedAtMS: now.UnixMilli(),
},
OutboxRecords: outboxRecords,
RobotOutboxRecords: result.robotOutboxRecords,
RoomStatus: result.roomStatus,
RoomSeatCount: result.roomSeatCount,
RoomPasswordHash: result.roomPasswordHash,

View File

@ -414,8 +414,18 @@ func stalePresenceUserIDs(current *state.RoomState, cutoffMs int64) []int64 {
return nil
}
robotUserIDs := map[int64]bool(nil)
if current.RoomExt[roomExtRobotRoomKey] == "true" {
// 机器人房的内部机器人没有客户端心跳;它们的生命周期由机器人房配置和运行时管理,
// 不能被普通用户 stale worker 清掉,否则送礼循环会因为 sender/target 不在房间而失败。
robotUserIDs = parseInt64CSV(current.RoomExt[roomExtRobotUserIDsKey])
}
userIDs := make([]int64, 0)
for userID, userState := range current.OnlineUsers {
if robotUserIDs[userID] {
continue
}
if userState != nil && userState.LastSeenAtMS <= cutoffMs {
userIDs = append(userIDs, userID)
}

View File

@ -163,7 +163,9 @@ func replay(current *state.RoomState, cmd command.Command, committedAtMS int64)
case *command.RoomHeartbeat:
existing, exists := current.OnlineUsers[typed.ActorUserID()]
if !exists {
return fmt.Errorf("room_heartbeat replay actor is not in room: %d", typed.ActorUserID())
// 心跳和离房可能在同一房间版本附近并发落库;如果离房先被重放,随后到达的旧心跳
// 不能重新创建 presence也不能让整个 Room Cell 恢复失败。
return nil
}
// 心跳只刷新 last_seen不产生用户进房事件。
existing.LastSeenAtMS = typed.SentAtMS

View File

@ -59,6 +59,8 @@ type MutationCommit struct {
Command CommandRecord
// OutboxRecords 是本次命令产生的房间外事件。
OutboxRecords []outbox.Record
// RobotOutboxRecords 是机器人房间必要展示事件,必须和命令日志同事务写入独立 robot outbox。
RobotOutboxRecords []outbox.Record
// RoomStatus 非空时同步更新 rooms 和 room_list_entries 的生命周期状态。
RoomStatus string
// RoomSeatCount 非 nil 时同步更新 rooms 元数据中的麦位总数。
@ -258,6 +260,39 @@ type AdminCreateRoomPinInput struct {
NowMS int64
}
type HumanRoomRobotCountryPool struct {
CountryCode string
RobotUserIDs []int64
}
type HumanRoomRobotConfig struct {
AppCode string
Enabled bool
CandidateRoomMaxOnline int32
RoomFullStopOnline int32
RoomTargetMinOnline int32
RoomTargetMaxOnline int32
RobotStayMinMS int64
RobotStayMaxMS int64
RobotReplaceMinMS int64
RobotReplaceMaxMS int64
NormalGiftIntervalMS int64
NormalGiftIntervalMinMS int64
NormalGiftIntervalMaxMS int64
GiftIDs []string
LuckyGiftIDs []string
SuperLuckyGiftIDs []string
LuckyComboMin int64
LuckyComboMax int64
LuckyPauseMinMS int64
LuckyPauseMaxMS int64
MaxGiftSenders int64
CountryPools []HumanRoomRobotCountryPool
UpdatedByAdminID uint64
CreatedAtMS int64
UpdatedAtMS int64
}
// RoomSeatConfig 是后台房间配置里控制创建/修改房间座位数的低频配置。
type RoomSeatConfig struct {
// AppCode 是配置所属 App。
@ -330,6 +365,11 @@ type RobotRoomGiftRule struct {
LuckyComboMax int64
LuckyPauseMinMS int64
LuckyPauseMaxMS int64
RobotStayMinMS int64
RobotStayMaxMS int64
RobotReplaceMinMS int64
RobotReplaceMaxMS int64
MaxGiftSenders int64
}
// RobotRoomConfig 是 room-service 持久化的机器人房间配置和账号占用事实。
@ -340,9 +380,12 @@ type RobotRoomConfig struct {
Title string
CoverURL string
VisibleRegionID int64
OwnerCountryCode string
Status string
OwnerRobotUserID int64
RobotUserIDs []int64
ActiveRobotCount int32
SeatCount int32
GiftRule RobotRoomGiftRule
CreatedByAdminID uint64
CreatedAtMS int64
@ -415,6 +458,8 @@ type RoomListQuery struct {
AppCode string
// VisibleRegionID 是服务端解析出的用户区域,客户端不能伪造。
VisibleRegionID int64
// AllVisibleRegions 只服务后台白名单用户;为 true 时列表读模型不再按 VisibleRegionID 收敛。
AllVisibleRegions bool
// Tab 只允许 hot/new决定公共发现列表排序字段。
Tab string
// OwnerUserID 保留给内部定向读模型;公开 Mine 顶部卡片走 GetMyRoom。
@ -594,14 +639,24 @@ type Repository interface {
SaveOutbox(ctx context.Context, records []outbox.Record) error
// ListPendingOutbox 扫描待补偿投递事件。
ListPendingOutbox(ctx context.Context, limit int) ([]outbox.Record, error)
// ListPendingRobotOutbox 扫描机器人房间待补偿展示事件。
ListPendingRobotOutbox(ctx context.Context, limit int) ([]outbox.Record, error)
// ClaimPendingOutbox 抢占一批待投递事件,避免多 worker 同时投递同一批。
ClaimPendingOutbox(ctx context.Context, workerID string, limit int, lockUntilMS int64) ([]outbox.Record, error)
// ClaimPendingRobotOutbox 抢占机器人房间展示事件,避免机器人流量占用主 room_outbox worker。
ClaimPendingRobotOutbox(ctx context.Context, workerID string, limit int, lockUntilMS int64) ([]outbox.Record, error)
// MarkOutboxDelivered 标记事件已经投递成功。
MarkOutboxDelivered(ctx context.Context, eventID string) error
// MarkRobotOutboxDelivered 标记机器人展示事件已经投递成功。
MarkRobotOutboxDelivered(ctx context.Context, eventID string) error
// MarkOutboxRetryable 记录一次投递失败,并写入下一次允许抢占的退避时间。
MarkOutboxRetryable(ctx context.Context, eventID string, lastErr string, nextRetryAtMS int64) error
// MarkRobotOutboxRetryable 记录机器人展示事件投递失败,并写入独立重试退避。
MarkRobotOutboxRetryable(ctx context.Context, eventID string, lastErr string, nextRetryAtMS int64) error
// MarkOutboxDead 把超过最大重试次数的事件转入 failed避免固定污染日志和外部依赖。
MarkOutboxDead(ctx context.Context, eventID string, lastErr string) error
// MarkRobotOutboxDead 把超过最大重试次数的机器人展示事件转入 failed。
MarkRobotOutboxDead(ctx context.Context, eventID string, lastErr string) error
// UpsertRoomListEntry 写入或更新房间列表读模型;失败不应破坏 Room Cell 已提交状态。
UpsertRoomListEntry(ctx context.Context, entry RoomListEntry) error
// ListRoomListEntries 按区域和 tab 查询房间列表,不访问 Room Cell 内存。
@ -639,6 +694,9 @@ type Repository interface {
UpdateRobotRoomStatus(ctx context.Context, roomID string, status string, nowMS int64) (RobotRoomConfig, bool, error)
OccupiedRobotUserIDs(ctx context.Context, userIDs []int64) (map[int64]bool, error)
ListActiveRobotRooms(ctx context.Context) ([]RobotRoomConfig, error)
GetHumanRoomRobotConfig(ctx context.Context) (HumanRoomRobotConfig, bool, error)
UpsertHumanRoomRobotConfig(ctx context.Context, config HumanRoomRobotConfig) (HumanRoomRobotConfig, error)
ListHumanRobotCandidateRooms(ctx context.Context, appCode string, countryCode string, maxOnline int32, fullStopOnline int32, limit int) ([]RoomListEntry, error)
}
// RoomPresenceSnapshot 是 repository 投影接口的稳定入参,避免存储层反向依赖 protobuf。

View File

@ -35,6 +35,10 @@ type Config struct {
RTCUserRemover integration.RTCUserRemover
// RoomRocketLaunchScheduler 把倒计时发射唤醒交给外部延迟消息,避免只靠已加载 Cell 扫描。
RoomRocketLaunchScheduler integration.RoomRocketLaunchScheduler
// RobotOutboxPublisher 专门投递机器人房间展示事件,避免机器人流量进入真人房间 room_outbox 通道。
RobotOutboxPublisher integration.OutboxPublisher
// HumanRobotPoolProvider 自动读取全站机器人账号和用户国家,用于真人房间机器人运行时按国家分组。
HumanRobotPoolProvider integration.HumanRoomRobotPoolProvider
// RoomGiftLeaderboard 是跨房间贡献榜读模型SendGift 提交后 best-effort 写入。
RoomGiftLeaderboard RoomGiftLeaderboardStore
// LuckyGiftSendLocker 串行化同一用户的幸运礼物扣费、抽奖和同步返奖链路。
@ -73,6 +77,10 @@ type Service struct {
syncPublisher integration.RoomEventPublisher
// outboxPublisher 是补偿 worker 对外部消费者的异步投递抽象。
outboxPublisher integration.OutboxPublisher
// robotOutboxPublisher 只服务机器人房间必要展示事件,和主 room_outbox 发布器隔离。
robotOutboxPublisher integration.OutboxPublisher
// humanRobotPoolProvider 运行时自动获取全站机器人池,避免后台手工维护国家机器人池。
humanRobotPoolProvider integration.HumanRoomRobotPoolProvider
// roomRocketLaunchScheduler 在 ignited outbox 投递成功后安排 launch_at_ms 唤醒。
roomRocketLaunchScheduler integration.RoomRocketLaunchScheduler
// roomGiftLeaderboard 只保存房间维度贡献值 zset不承载 Room Cell 核心状态。
@ -93,8 +101,21 @@ type Service struct {
// robotRuntimeMu 保护后台机器人房间运行循环;配置变更时要取消旧循环后重建。
robotRuntimeMu sync.Mutex
// robotRuntimes 保存 room_id -> cancel避免同一房间被重复启动多个送礼循环。
robotRuntimes map[string]context.CancelFunc
// robotRuntimes 保存 room_id -> runtime避免同一房间被重复启动多个送礼循环。
robotRuntimes map[string]robotRoomRuntime
// humanRobotRuntimeMu 保护真人房间机器人运行循环,和机器人房间 runtime 分开避免互相取消。
humanRobotRuntimeMu sync.Mutex
// humanRobotRuntimes 保存 room_id -> runtime避免同一真人房间被重复补机器人。
humanRobotRuntimes map[string]robotRoomRuntime
}
type robotRoomRuntime struct {
// cancel 停止当前房间的所有机器人送礼 goroutine。
cancel context.CancelFunc
// token 区分同一房间的前后两次启动,旧 goroutine 退出时不能误删新 runtime。
token string
// configUpdatedAtMS 记录启动 runtime 时采用的配置版本;后台改配置后扫描器据此重启真人房间机器人 runtime。
configUpdatedAtMS int64
}
// mutationResult 是命令在 Room Cell 内执行后的统一结果包。
@ -131,6 +152,8 @@ type mutationResult struct {
syncEvent *tencentim.RoomEvent
// outboxRecords 是本次命令已经持久化的房间事实,提交后可投给 activity 等外部消费者。
outboxRecords []outbox.Record
// robotOutboxRecords 是机器人房间必要展示事实,只进入 robot outbox/worker不占主 room_outbox。
robotOutboxRecords []outbox.Record
// roomStatus 非空时代表命令提交时需要同步更新 rooms 和列表投影生命周期状态。
roomStatus string
// roomSeatCount 非 nil 时代表命令提交时需要同步更新 rooms 元数据座位数。
@ -205,13 +228,16 @@ func New(cfg Config, directory router.Directory, repository Repository, wallet i
luckyGift: luckyGiftClient,
syncPublisher: syncPublisher,
outboxPublisher: outboxPublisher,
robotOutboxPublisher: cfg.RobotOutboxPublisher,
humanRobotPoolProvider: cfg.HumanRobotPoolProvider,
roomRocketLaunchScheduler: cfg.RoomRocketLaunchScheduler,
roomGiftLeaderboard: cfg.RoomGiftLeaderboard,
luckyGiftSendLocker: cfg.LuckyGiftSendLocker,
luckyGiftSendLockTTL: luckyGiftSendLockTTL,
rtcUserRemover: cfg.RTCUserRemover,
cells: make(map[string]*cell.RoomCell),
robotRuntimes: make(map[string]context.CancelFunc),
robotRuntimes: make(map[string]robotRoomRuntime),
humanRobotRuntimes: make(map[string]robotRoomRuntime),
}
}

View File

@ -98,6 +98,61 @@ func TestRoomUserGiftValueFollowsMicChangeAndResetsAfterLeave(t *testing.T) {
}
}
func TestRobotGiftSkipsMainHeatAndRankOutbox(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)
now := &fixedRoomRocketClock{now: time.Date(2026, 6, 8, 11, 0, 0, 0, time.UTC)}
wallet := &rocketTestWallet{debits: []*walletv1.DebitGiftResponse{{
BillingReceiptId: "receipt-robot-display-only",
CoinSpent: 100,
ChargeAmount: 100,
HeatValue: 100,
ChargeAssetType: "ROBOT_COIN",
GiftTypeCode: "robot",
}}}
svc := newUserGiftValueTestService(repository, wallet, now, "node-robot-gift-outbox-boundary")
roomID := "robot-room-outbox-boundary"
senderID := int64(63001)
targetID := int64(63002)
createRocketRoom(t, ctx, svc, roomID, senderID, 9001)
joinRocketRoom(t, ctx, svc, roomID, targetID)
beforeMain := outboxEventCounts(t, ctx, repository)
beforeRobot := robotOutboxEventCounts(t, ctx, repository)
if _, err := svc.RobotSendGift(ctx, roomservice.RobotSendGiftInput{
Meta: rocketMeta(roomID, senderID, "robot-display-only"),
TargetUserID: targetID,
GiftID: "robot-display-gift",
GiftCount: 1,
RobotUserIDs: []int64{senderID, targetID},
}); err != nil {
t.Fatalf("robot send gift failed: %v", err)
}
afterMain := outboxEventCounts(t, ctx, repository)
if delta := afterMain["RoomGiftSent"] - beforeMain["RoomGiftSent"]; delta != 0 {
t.Fatalf("robot gift must not create main gift outbox, delta=%d counts=%+v", delta, afterMain)
}
if delta := afterMain["RoomHeatChanged"] - beforeMain["RoomHeatChanged"]; delta != 0 {
t.Fatalf("robot gift must not create main heat outbox, delta=%d counts=%+v", delta, afterMain)
}
if delta := afterMain["RoomRankChanged"] - beforeMain["RoomRankChanged"]; delta != 0 {
t.Fatalf("robot gift must not create main rank outbox, delta=%d counts=%+v", delta, afterMain)
}
afterRobot := robotOutboxEventCounts(t, ctx, repository)
if delta := afterRobot["RoomGiftSent"] - beforeRobot["RoomGiftSent"]; delta != 1 {
t.Fatalf("robot gift must keep one robot gift display outbox, delta=%d counts=%+v", delta, afterRobot)
}
if delta := afterRobot["RoomHeatChanged"] - beforeRobot["RoomHeatChanged"]; delta != 1 {
t.Fatalf("robot gift must keep robot heat display outbox, delta=%d counts=%+v", delta, afterRobot)
}
if delta := afterRobot["RoomRankChanged"] - beforeRobot["RoomRankChanged"]; delta != 1 {
t.Fatalf("robot gift must keep robot rank display outbox, delta=%d counts=%+v", delta, afterRobot)
}
}
func TestRoomUserGiftValueRecoversFromCommandLog(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)
@ -159,6 +214,32 @@ func TestRoomUserGiftValueRecoversFromCommandLog(t *testing.T) {
}
}
func outboxEventCounts(t *testing.T, ctx context.Context, repository *mysqltest.Repository) map[string]int {
t.Helper()
records, err := repository.ListPendingOutbox(ctx, 200)
if err != nil {
t.Fatalf("list pending outbox failed: %v", err)
}
counts := make(map[string]int, len(records))
for _, record := range records {
counts[record.EventType]++
}
return counts
}
func robotOutboxEventCounts(t *testing.T, ctx context.Context, repository *mysqltest.Repository) map[string]int {
t.Helper()
records, err := repository.ListPendingRobotOutbox(ctx, 200)
if err != nil {
t.Fatalf("list pending robot outbox failed: %v", err)
}
counts := make(map[string]int, len(records))
for _, record := range records {
counts[record.EventType]++
}
return counts
}
func newUserGiftValueTestService(repository *mysqltest.Repository, wallet *rocketTestWallet, clock *fixedRoomRocketClock, nodeID string) *roomservice.Service {
return roomservice.New(roomservice.Config{
NodeID: nodeID,

View File

@ -20,6 +20,11 @@ import (
roomservice "hyapp/services/room-service/internal/room/service"
)
const (
roomOutboxTable = "room_outbox"
roomRobotOutboxTable = "room_robot_outbox"
)
// Repository 把 room-service 的权威状态持久化到 MySQL。
type Repository struct {
// db 是标准库连接池,所有 repository 方法都通过它访问 MySQL。
@ -211,6 +216,26 @@ func (r *Repository) Migrate(ctx context.Context) error {
KEY idx_room_outbox_event_created (app_code, event_type, created_at_ms, event_id),
KEY idx_room_outbox_retention (app_code, status, updated_at_ms, event_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
`CREATE TABLE IF NOT EXISTS room_robot_outbox (
app_code VARCHAR(32) NOT NULL,
event_id VARCHAR(128) NOT NULL,
event_type VARCHAR(64) NOT NULL,
room_id VARCHAR(64) NOT NULL,
status VARCHAR(32) NOT NULL,
worker_id VARCHAR(128) NOT NULL DEFAULT '',
lock_until_ms BIGINT NULL,
envelope LONGBLOB NOT NULL,
created_at_ms BIGINT NOT NULL,
retry_count INT NOT NULL DEFAULT 0,
next_retry_at_ms BIGINT NOT NULL DEFAULT 0,
last_error TEXT NULL,
updated_at_ms BIGINT NOT NULL,
PRIMARY KEY (app_code, event_id),
KEY idx_room_robot_outbox_pending (app_code, status, next_retry_at_ms, created_at_ms, event_id),
KEY idx_room_robot_outbox_claim (app_code, status, lock_until_ms, created_at_ms, event_id),
KEY idx_room_robot_outbox_event_created (app_code, event_type, created_at_ms, event_id),
KEY idx_room_robot_outbox_retention (app_code, status, updated_at_ms, event_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
`CREATE TABLE IF NOT EXISTS room_user_feed_entries (
app_code VARCHAR(32) NOT NULL,
user_id BIGINT NOT NULL,
@ -288,6 +313,8 @@ func (r *Repository) Migrate(ctx context.Context) error {
status VARCHAR(32) NOT NULL,
owner_robot_user_id BIGINT NOT NULL,
robot_user_ids_json JSON NOT NULL,
active_robot_count INT NOT NULL DEFAULT 0,
seat_count INT NOT NULL DEFAULT 10,
gift_ids_json JSON NOT NULL,
lucky_gift_ids_json JSON NOT NULL,
normal_gift_interval_ms BIGINT NOT NULL,
@ -295,6 +322,11 @@ func (r *Repository) Migrate(ctx context.Context) error {
lucky_combo_max BIGINT NOT NULL,
lucky_pause_min_ms BIGINT NOT NULL,
lucky_pause_max_ms BIGINT NOT NULL,
robot_stay_min_ms BIGINT NOT NULL DEFAULT 180000,
robot_stay_max_ms BIGINT NOT NULL DEFAULT 600000,
robot_replace_min_ms BIGINT NOT NULL DEFAULT 0,
robot_replace_max_ms BIGINT NOT NULL DEFAULT 60000,
max_gift_senders BIGINT NOT NULL DEFAULT 1,
created_by_admin_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
created_at_ms BIGINT NOT NULL,
updated_at_ms BIGINT NOT NULL,
@ -302,6 +334,35 @@ func (r *Repository) Migrate(ctx context.Context) error {
KEY idx_room_robot_rooms_status (app_code, status, updated_at_ms, room_id),
KEY idx_room_robot_rooms_owner (app_code, owner_robot_user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
`CREATE TABLE IF NOT EXISTS room_human_robot_configs (
app_code VARCHAR(32) NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT FALSE,
candidate_room_max_online INT NOT NULL DEFAULT 5,
room_full_stop_online INT NOT NULL DEFAULT 10,
room_target_min_online INT NOT NULL DEFAULT 8,
room_target_max_online INT NOT NULL DEFAULT 10,
robot_stay_min_ms BIGINT NOT NULL DEFAULT 60000,
robot_stay_max_ms BIGINT NOT NULL DEFAULT 600000,
robot_replace_min_ms BIGINT NOT NULL DEFAULT 60000,
robot_replace_max_ms BIGINT NOT NULL DEFAULT 180000,
normal_gift_interval_ms BIGINT NOT NULL DEFAULT 10000,
normal_gift_interval_min_ms BIGINT NOT NULL DEFAULT 1000,
normal_gift_interval_max_ms BIGINT NOT NULL DEFAULT 20000,
gift_ids_json JSON NOT NULL,
lucky_gift_ids_json JSON NOT NULL,
super_lucky_gift_ids_json JSON NOT NULL,
lucky_combo_min BIGINT NOT NULL DEFAULT 1,
lucky_combo_max BIGINT NOT NULL DEFAULT 3,
lucky_pause_min_ms BIGINT NOT NULL DEFAULT 5000,
lucky_pause_max_ms BIGINT NOT NULL DEFAULT 20000,
max_gift_senders BIGINT NOT NULL DEFAULT 1,
country_pools_json JSON NOT NULL,
updated_by_admin_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
created_at_ms BIGINT NOT NULL,
updated_at_ms BIGINT NOT NULL,
PRIMARY KEY (app_code),
KEY idx_room_human_robot_enabled (app_code, enabled)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
`INSERT IGNORE INTO room_seat_configs (app_code, allowed_seat_counts, default_seat_count, created_at_ms, updated_at_ms)
VALUES ('lalu', '[10,15,20,25,30]', 15, 0, 0)`,
`INSERT IGNORE INTO room_rocket_configs (
@ -383,10 +444,69 @@ func (r *Repository) Migrate(ctx context.Context) error {
if err := r.ensureRoomPinSchema(ctx); err != nil {
return err
}
if err := r.ensureRobotRoomBehaviorSchema(ctx); err != nil {
return err
}
if err := r.ensureHumanRobotConfigBehaviorSchema(ctx); err != nil {
return err
}
return r.ensureOutboxRetrySchema(ctx)
}
func (r *Repository) ensureHumanRobotConfigBehaviorSchema(ctx context.Context) error {
columns := []struct {
name string
statement string
}{
{name: "normal_gift_interval_min_ms", statement: `ALTER TABLE room_human_robot_configs ADD COLUMN normal_gift_interval_min_ms BIGINT NOT NULL DEFAULT 1000 AFTER normal_gift_interval_ms`},
{name: "normal_gift_interval_max_ms", statement: `ALTER TABLE room_human_robot_configs ADD COLUMN normal_gift_interval_max_ms BIGINT NOT NULL DEFAULT 20000 AFTER normal_gift_interval_min_ms`},
{name: "room_target_min_online", statement: `ALTER TABLE room_human_robot_configs ADD COLUMN room_target_min_online INT NOT NULL DEFAULT 8 AFTER room_full_stop_online`},
{name: "room_target_max_online", statement: `ALTER TABLE room_human_robot_configs ADD COLUMN room_target_max_online INT NOT NULL DEFAULT 10 AFTER room_target_min_online`},
}
for _, column := range columns {
exists, err := r.columnExists(ctx, "room_human_robot_configs", column.name)
if err != nil {
return err
}
if exists {
continue
}
if _, err := r.db.ExecContext(ctx, column.statement); err != nil {
return err
}
}
return nil
}
func (r *Repository) ensureRobotRoomBehaviorSchema(ctx context.Context) error {
columns := []struct {
name string
statement string
}{
{name: "active_robot_count", statement: `ALTER TABLE room_robot_rooms ADD COLUMN active_robot_count INT NOT NULL DEFAULT 0 AFTER robot_user_ids_json`},
{name: "seat_count", statement: `ALTER TABLE room_robot_rooms ADD COLUMN seat_count INT NOT NULL DEFAULT 10 AFTER active_robot_count`},
{name: "robot_stay_min_ms", statement: `ALTER TABLE room_robot_rooms ADD COLUMN robot_stay_min_ms BIGINT NOT NULL DEFAULT 180000 AFTER lucky_pause_max_ms`},
{name: "robot_stay_max_ms", statement: `ALTER TABLE room_robot_rooms ADD COLUMN robot_stay_max_ms BIGINT NOT NULL DEFAULT 600000 AFTER robot_stay_min_ms`},
{name: "robot_replace_min_ms", statement: `ALTER TABLE room_robot_rooms ADD COLUMN robot_replace_min_ms BIGINT NOT NULL DEFAULT 0 AFTER robot_stay_max_ms`},
{name: "robot_replace_max_ms", statement: `ALTER TABLE room_robot_rooms ADD COLUMN robot_replace_max_ms BIGINT NOT NULL DEFAULT 60000 AFTER robot_replace_min_ms`},
{name: "max_gift_senders", statement: `ALTER TABLE room_robot_rooms ADD COLUMN max_gift_senders BIGINT NOT NULL DEFAULT 1 AFTER robot_replace_max_ms`},
}
for _, column := range columns {
exists, err := r.columnExists(ctx, "room_robot_rooms", column.name)
if err != nil {
return err
}
if exists {
continue
}
if _, err := r.db.ExecContext(ctx, column.statement); err != nil {
return err
}
}
return nil
}
func (r *Repository) ensureRoomWeeklyContributionSchema(ctx context.Context) error {
columns := []struct {
column string
@ -863,35 +983,15 @@ func (r *Repository) SaveMutation(ctx context.Context, commit roomservice.Mutati
return err
}
for _, record := range commit.OutboxRecords {
record.AppCode = normalizedRecordAppCode(ctx, record.AppCode)
if record.Envelope != nil {
record.Envelope.AppCode = record.AppCode
}
envelopeBytes, err := proto.Marshal(record.Envelope)
if err != nil {
_ = tx.Rollback()
return err
}
if _, err := tx.ExecContext(ctx,
`INSERT INTO room_outbox (app_code, event_id, event_type, room_id, status, envelope, created_at_ms, retry_count, next_retry_at_ms, last_error, updated_at_ms)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE event_id = event_id`,
record.AppCode,
record.EventID,
record.EventType,
record.RoomID,
record.Status,
envelopeBytes,
record.CreatedAtMS,
record.RetryCount,
record.NextRetryAtMS,
nullableString(record.LastError),
record.CreatedAtMS,
); err != nil {
_ = tx.Rollback()
return err
}
if err := r.insertRoomOutboxRecords(ctx, tx, roomOutboxTable, commit.OutboxRecords); err != nil {
// 任一事件失败就回滚整批,避免 GiftSent/HeatChanged/RankChanged 部分缺失。
_ = tx.Rollback()
return err
}
if err := r.insertRoomOutboxRecords(ctx, tx, roomRobotOutboxTable, commit.RobotOutboxRecords); err != nil {
// robot outbox 也和命令日志同事务提交,避免机器人礼物状态变了但客户端展示事件丢失。
_ = tx.Rollback()
return err
}
if strings.TrimSpace(commit.RoomStatus) != "" {
@ -1075,6 +1175,44 @@ func (r *Repository) SaveMutation(ctx context.Context, commit roomservice.Mutati
return tx.Commit()
}
func (r *Repository) insertRoomOutboxRecords(ctx context.Context, tx *sql.Tx, table string, records []outbox.Record) error {
table = roomOutboxTableName(table)
if len(records) == 0 {
return nil
}
for _, record := range records {
record.AppCode = normalizedRecordAppCode(ctx, record.AppCode)
if record.Envelope != nil {
record.Envelope.AppCode = record.AppCode
}
envelopeBytes, err := proto.Marshal(record.Envelope)
if err != nil {
return err
}
if _, err := tx.ExecContext(ctx,
`INSERT INTO `+table+` (app_code, event_id, event_type, room_id, status, envelope, created_at_ms, retry_count, next_retry_at_ms, last_error, updated_at_ms)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE event_id = event_id`,
record.AppCode,
record.EventID,
record.EventType,
record.RoomID,
record.Status,
envelopeBytes,
record.CreatedAtMS,
record.RetryCount,
record.NextRetryAtMS,
nullableString(record.LastError),
record.CreatedAtMS,
); err != nil {
return err
}
}
return nil
}
// GetRoomSeatConfig 读取当前 App 的房间座位数配置。
func (r *Repository) GetRoomSeatConfig(ctx context.Context) (roomservice.RoomSeatConfig, bool, error) {
row := r.db.QueryRowContext(ctx,
@ -1256,8 +1394,9 @@ func (r *Repository) ListRobotRooms(ctx context.Context, query roomservice.Robot
args = append(args, pageSize, (page-1)*pageSize)
rows, err := r.db.QueryContext(ctx,
`SELECT app_code, room_id, room_short_id, title, cover_url, visible_region_id, status,
owner_robot_user_id, robot_user_ids_json, gift_ids_json, lucky_gift_ids_json,
owner_robot_user_id, robot_user_ids_json, active_robot_count, seat_count, gift_ids_json, lucky_gift_ids_json,
normal_gift_interval_ms, lucky_combo_min, lucky_combo_max, lucky_pause_min_ms, lucky_pause_max_ms,
robot_stay_min_ms, robot_stay_max_ms, robot_replace_min_ms, robot_replace_max_ms, max_gift_senders,
created_by_admin_id, created_at_ms, updated_at_ms
FROM room_robot_rooms `+where+`
ORDER BY updated_at_ms DESC, room_id DESC
@ -1276,8 +1415,9 @@ func (r *Repository) ListRobotRooms(ctx context.Context, query roomservice.Robot
func (r *Repository) GetRobotRoom(ctx context.Context, roomID string) (roomservice.RobotRoomConfig, bool, error) {
row := r.db.QueryRowContext(ctx,
`SELECT app_code, room_id, room_short_id, title, cover_url, visible_region_id, status,
owner_robot_user_id, robot_user_ids_json, gift_ids_json, lucky_gift_ids_json,
owner_robot_user_id, robot_user_ids_json, active_robot_count, seat_count, gift_ids_json, lucky_gift_ids_json,
normal_gift_interval_ms, lucky_combo_min, lucky_combo_max, lucky_pause_min_ms, lucky_pause_max_ms,
robot_stay_min_ms, robot_stay_max_ms, robot_replace_min_ms, robot_replace_max_ms, max_gift_senders,
created_by_admin_id, created_at_ms, updated_at_ms
FROM room_robot_rooms
WHERE app_code = ? AND room_id = ?`,
@ -1324,10 +1464,11 @@ func (r *Repository) CreateRobotRoomConfig(ctx context.Context, input roomservic
_, err = tx.ExecContext(ctx,
`INSERT INTO room_robot_rooms (
app_code, room_id, room_short_id, title, cover_url, visible_region_id, status,
owner_robot_user_id, robot_user_ids_json, gift_ids_json, lucky_gift_ids_json,
owner_robot_user_id, robot_user_ids_json, active_robot_count, seat_count, gift_ids_json, lucky_gift_ids_json,
normal_gift_interval_ms, lucky_combo_min, lucky_combo_max, lucky_pause_min_ms, lucky_pause_max_ms,
robot_stay_min_ms, robot_stay_max_ms, robot_replace_min_ms, robot_replace_max_ms, max_gift_senders,
created_by_admin_id, created_at_ms, updated_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
config.AppCode,
config.RoomID,
config.RoomShortID,
@ -1337,6 +1478,8 @@ func (r *Repository) CreateRobotRoomConfig(ctx context.Context, input roomservic
config.Status,
config.OwnerRobotUserID,
string(rawRobots),
config.ActiveRobotCount,
config.SeatCount,
string(rawGifts),
string(rawLuckyGifts),
config.GiftRule.NormalGiftIntervalMS,
@ -1344,6 +1487,11 @@ func (r *Repository) CreateRobotRoomConfig(ctx context.Context, input roomservic
config.GiftRule.LuckyComboMax,
config.GiftRule.LuckyPauseMinMS,
config.GiftRule.LuckyPauseMaxMS,
config.GiftRule.RobotStayMinMS,
config.GiftRule.RobotStayMaxMS,
config.GiftRule.RobotReplaceMinMS,
config.GiftRule.RobotReplaceMaxMS,
config.GiftRule.MaxGiftSenders,
config.CreatedByAdminID,
config.CreatedAtMS,
config.UpdatedAtMS,
@ -1392,8 +1540,9 @@ func (r *Repository) OccupiedRobotUserIDs(ctx context.Context, userIDs []int64)
func (r *Repository) ListActiveRobotRooms(ctx context.Context) ([]roomservice.RobotRoomConfig, error) {
rows, err := r.db.QueryContext(ctx,
`SELECT app_code, room_id, room_short_id, title, cover_url, visible_region_id, status,
owner_robot_user_id, robot_user_ids_json, gift_ids_json, lucky_gift_ids_json,
owner_robot_user_id, robot_user_ids_json, active_robot_count, seat_count, gift_ids_json, lucky_gift_ids_json,
normal_gift_interval_ms, lucky_combo_min, lucky_combo_max, lucky_pause_min_ms, lucky_pause_max_ms,
robot_stay_min_ms, robot_stay_max_ms, robot_replace_min_ms, robot_replace_max_ms, max_gift_senders,
created_by_admin_id, created_at_ms, updated_at_ms
FROM room_robot_rooms
WHERE status = 'active'
@ -1406,6 +1555,251 @@ func (r *Repository) ListActiveRobotRooms(ctx context.Context) ([]roomservice.Ro
return scanRobotRoomConfigs(rows)
}
// GetHumanRoomRobotConfig 读取真人房间机器人行为配置;没有配置时由 service 层补默认值。
func (r *Repository) GetHumanRoomRobotConfig(ctx context.Context) (roomservice.HumanRoomRobotConfig, bool, error) {
row := r.db.QueryRowContext(ctx,
`SELECT app_code, enabled, candidate_room_max_online, room_full_stop_online, room_target_min_online, room_target_max_online,
robot_stay_min_ms, robot_stay_max_ms, robot_replace_min_ms, robot_replace_max_ms,
normal_gift_interval_ms, normal_gift_interval_min_ms, normal_gift_interval_max_ms,
gift_ids_json, lucky_gift_ids_json, super_lucky_gift_ids_json,
lucky_combo_min, lucky_combo_max, lucky_pause_min_ms, lucky_pause_max_ms, max_gift_senders,
country_pools_json, updated_by_admin_id, created_at_ms, updated_at_ms
FROM room_human_robot_configs
WHERE app_code = ?`,
appcode.FromContext(ctx),
)
config, err := scanHumanRoomRobotConfig(row)
if errors.Is(err, sql.ErrNoRows) {
return roomservice.HumanRoomRobotConfig{}, false, nil
}
return config, err == nil, err
}
// UpsertHumanRoomRobotConfig 保存真人房间机器人行为配置;运行时扫描每轮读取最新配置。
func (r *Repository) UpsertHumanRoomRobotConfig(ctx context.Context, config roomservice.HumanRoomRobotConfig) (roomservice.HumanRoomRobotConfig, error) {
appCode := normalizedRecordAppCode(ctx, config.AppCode)
nowMS := config.UpdatedAtMS
if nowMS <= 0 {
nowMS = time.Now().UTC().UnixMilli()
}
config.AppCode = appCode
config.CreatedAtMS = firstPositiveInt64(config.CreatedAtMS, nowMS)
config.UpdatedAtMS = nowMS
rawGifts, rawLucky, rawSuperLucky, rawPools, err := humanRoomRobotConfigJSON(config)
if err != nil {
return roomservice.HumanRoomRobotConfig{}, err
}
_, err = r.db.ExecContext(ctx,
`INSERT INTO room_human_robot_configs (
app_code, enabled, candidate_room_max_online, room_full_stop_online, room_target_min_online, room_target_max_online,
robot_stay_min_ms, robot_stay_max_ms, robot_replace_min_ms, robot_replace_max_ms,
normal_gift_interval_ms, normal_gift_interval_min_ms, normal_gift_interval_max_ms,
gift_ids_json, lucky_gift_ids_json, super_lucky_gift_ids_json,
lucky_combo_min, lucky_combo_max, lucky_pause_min_ms, lucky_pause_max_ms, max_gift_senders,
country_pools_json, updated_by_admin_id, created_at_ms, updated_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
enabled = VALUES(enabled),
candidate_room_max_online = VALUES(candidate_room_max_online),
room_full_stop_online = VALUES(room_full_stop_online),
room_target_min_online = VALUES(room_target_min_online),
room_target_max_online = VALUES(room_target_max_online),
robot_stay_min_ms = VALUES(robot_stay_min_ms),
robot_stay_max_ms = VALUES(robot_stay_max_ms),
robot_replace_min_ms = VALUES(robot_replace_min_ms),
robot_replace_max_ms = VALUES(robot_replace_max_ms),
normal_gift_interval_ms = VALUES(normal_gift_interval_ms),
normal_gift_interval_min_ms = VALUES(normal_gift_interval_min_ms),
normal_gift_interval_max_ms = VALUES(normal_gift_interval_max_ms),
gift_ids_json = VALUES(gift_ids_json),
lucky_gift_ids_json = VALUES(lucky_gift_ids_json),
super_lucky_gift_ids_json = VALUES(super_lucky_gift_ids_json),
lucky_combo_min = VALUES(lucky_combo_min),
lucky_combo_max = VALUES(lucky_combo_max),
lucky_pause_min_ms = VALUES(lucky_pause_min_ms),
lucky_pause_max_ms = VALUES(lucky_pause_max_ms),
max_gift_senders = VALUES(max_gift_senders),
country_pools_json = VALUES(country_pools_json),
updated_by_admin_id = VALUES(updated_by_admin_id),
updated_at_ms = VALUES(updated_at_ms)`,
config.AppCode,
boolToInt(config.Enabled),
config.CandidateRoomMaxOnline,
config.RoomFullStopOnline,
config.RoomTargetMinOnline,
config.RoomTargetMaxOnline,
config.RobotStayMinMS,
config.RobotStayMaxMS,
config.RobotReplaceMinMS,
config.RobotReplaceMaxMS,
config.NormalGiftIntervalMS,
config.NormalGiftIntervalMinMS,
config.NormalGiftIntervalMaxMS,
string(rawGifts),
string(rawLucky),
string(rawSuperLucky),
config.LuckyComboMin,
config.LuckyComboMax,
config.LuckyPauseMinMS,
config.LuckyPauseMaxMS,
config.MaxGiftSenders,
string(rawPools),
config.UpdatedByAdminID,
config.CreatedAtMS,
config.UpdatedAtMS,
)
if err != nil {
return roomservice.HumanRoomRobotConfig{}, err
}
saved, _, err := r.GetHumanRoomRobotConfig(ctx)
return saved, err
}
// ListHumanRobotCandidateRooms 找出同国家低人数真人房room_id 使用 robot_ 前缀的内部机器人房不参与。
func (r *Repository) ListHumanRobotCandidateRooms(ctx context.Context, appCode string, countryCode string, maxOnline int32, fullStopOnline int32, limit int) ([]roomservice.RoomListEntry, error) {
appCode = normalizedRecordAppCode(ctx, appCode)
countryCode = strings.ToUpper(strings.TrimSpace(countryCode))
if maxOnline <= 0 {
maxOnline = 5
}
if fullStopOnline <= 0 {
fullStopOnline = 10
}
if maxOnline > fullStopOnline {
maxOnline = fullStopOnline
}
if limit <= 0 || limit > 100 {
limit = 50
}
rows, err := r.db.QueryContext(ctx,
`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 status = 'active'
AND owner_country_code = ?
AND online_count < ?
AND online_count < ?
AND room_id NOT LIKE 'robot\_%'
ORDER BY online_count ASC, updated_at_ms DESC, room_id DESC
LIMIT ?`,
appCode,
countryCode,
maxOnline,
fullStopOnline,
limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := make([]roomservice.RoomListEntry, 0, limit)
for rows.Next() {
var entry roomservice.RoomListEntry
if err := rows.Scan(
&entry.AppCode,
&entry.RoomID,
&entry.RoomShortID,
&entry.VisibleRegionID,
&entry.OwnerCountryCode,
&entry.OwnerUserID,
&entry.Title,
&entry.CoverURL,
&entry.Mode,
&entry.Status,
&entry.Locked,
&entry.Heat,
&entry.OnlineCount,
&entry.SeatCount,
&entry.OccupiedSeatCount,
&entry.SortScore,
&entry.CreatedAtMS,
&entry.UpdatedAtMS,
); err != nil {
return nil, err
}
items = append(items, entry)
}
return items, rows.Err()
}
type humanRoomRobotConfigScanner interface {
Scan(dest ...any) error
}
func scanHumanRoomRobotConfig(row humanRoomRobotConfigScanner) (roomservice.HumanRoomRobotConfig, error) {
var config roomservice.HumanRoomRobotConfig
var enabled int
var rawGifts string
var rawLucky string
var rawSuperLucky string
var rawPools string
if err := row.Scan(
&config.AppCode,
&enabled,
&config.CandidateRoomMaxOnline,
&config.RoomFullStopOnline,
&config.RoomTargetMinOnline,
&config.RoomTargetMaxOnline,
&config.RobotStayMinMS,
&config.RobotStayMaxMS,
&config.RobotReplaceMinMS,
&config.RobotReplaceMaxMS,
&config.NormalGiftIntervalMS,
&config.NormalGiftIntervalMinMS,
&config.NormalGiftIntervalMaxMS,
&rawGifts,
&rawLucky,
&rawSuperLucky,
&config.LuckyComboMin,
&config.LuckyComboMax,
&config.LuckyPauseMinMS,
&config.LuckyPauseMaxMS,
&config.MaxGiftSenders,
&rawPools,
&config.UpdatedByAdminID,
&config.CreatedAtMS,
&config.UpdatedAtMS,
); err != nil {
return roomservice.HumanRoomRobotConfig{}, err
}
config.Enabled = enabled == 1
if err := json.Unmarshal([]byte(rawGifts), &config.GiftIDs); err != nil {
return roomservice.HumanRoomRobotConfig{}, err
}
if err := json.Unmarshal([]byte(rawLucky), &config.LuckyGiftIDs); err != nil {
return roomservice.HumanRoomRobotConfig{}, err
}
if err := json.Unmarshal([]byte(rawSuperLucky), &config.SuperLuckyGiftIDs); err != nil {
return roomservice.HumanRoomRobotConfig{}, err
}
if err := json.Unmarshal([]byte(rawPools), &config.CountryPools); err != nil {
return roomservice.HumanRoomRobotConfig{}, err
}
return config, nil
}
func humanRoomRobotConfigJSON(config roomservice.HumanRoomRobotConfig) ([]byte, []byte, []byte, []byte, error) {
rawGifts, err := json.Marshal(config.GiftIDs)
if err != nil {
return nil, nil, nil, nil, err
}
rawLucky, err := json.Marshal(config.LuckyGiftIDs)
if err != nil {
return nil, nil, nil, nil, err
}
rawSuperLucky, err := json.Marshal(config.SuperLuckyGiftIDs)
if err != nil {
return nil, nil, nil, nil, err
}
rawPools, err := json.Marshal(config.CountryPools)
if err != nil {
return nil, nil, nil, nil, err
}
return rawGifts, rawLucky, rawSuperLucky, rawPools, nil
}
type robotRoomScanner interface {
Scan(dest ...any) error
}
@ -1437,6 +1831,8 @@ func scanRobotRoomConfig(row robotRoomScanner) (roomservice.RobotRoomConfig, err
&item.Status,
&item.OwnerRobotUserID,
&rawRobots,
&item.ActiveRobotCount,
&item.SeatCount,
&rawGifts,
&rawLuckyGifts,
&item.GiftRule.NormalGiftIntervalMS,
@ -1444,6 +1840,11 @@ func scanRobotRoomConfig(row robotRoomScanner) (roomservice.RobotRoomConfig, err
&item.GiftRule.LuckyComboMax,
&item.GiftRule.LuckyPauseMinMS,
&item.GiftRule.LuckyPauseMaxMS,
&item.GiftRule.RobotStayMinMS,
&item.GiftRule.RobotStayMaxMS,
&item.GiftRule.RobotReplaceMinMS,
&item.GiftRule.RobotReplaceMaxMS,
&item.GiftRule.MaxGiftSenders,
&item.CreatedByAdminID,
&item.CreatedAtMS,
&item.UpdatedAtMS,
@ -1459,6 +1860,13 @@ func scanRobotRoomConfig(row robotRoomScanner) (roomservice.RobotRoomConfig, err
if err := json.Unmarshal([]byte(rawLuckyGifts), &item.GiftRule.LuckyGiftIDs); err != nil {
return roomservice.RobotRoomConfig{}, err
}
if item.ActiveRobotCount <= 0 {
item.ActiveRobotCount = int32(len(item.RobotUserIDs))
}
if item.SeatCount <= 0 {
item.SeatCount = 10
}
item.GiftRule = roomservice.WithRobotRoomGiftRuleStorageDefaults(item.GiftRule)
return item, nil
}
@ -1659,16 +2067,27 @@ func (r *Repository) SaveOutbox(ctx context.Context, records []outbox.Record) er
// ListPendingOutbox 返回待投递事件。
func (r *Repository) ListPendingOutbox(ctx context.Context, limit int) ([]outbox.Record, error) {
return r.listPendingOutboxFromTable(ctx, roomOutboxTable, limit)
}
// ListPendingRobotOutbox 返回机器人房间待投递展示事件。
func (r *Repository) ListPendingRobotOutbox(ctx context.Context, limit int) ([]outbox.Record, error) {
return r.listPendingOutboxFromTable(ctx, roomRobotOutboxTable, limit)
}
func (r *Repository) listPendingOutboxFromTable(ctx context.Context, table string, limit int) ([]outbox.Record, error) {
if limit <= 0 {
// 默认批量上限避免调用方传 0 导致全表扫描。
limit = 100
}
table = roomOutboxTableName(table)
pendingIndex, _ := roomOutboxIndexes(table)
// 按创建时间顺序扫描 pending尽量保持事件投递顺序。
nowMS := time.Now().UTC().UnixMilli()
rows, err := r.db.QueryContext(ctx,
`SELECT app_code, event_id, event_type, room_id, status, worker_id, lock_until_ms, envelope, created_at_ms, retry_count, next_retry_at_ms, COALESCE(last_error, '')
FROM room_outbox FORCE INDEX (idx_room_outbox_pending)
FROM `+table+` FORCE INDEX (`+pendingIndex+`)
WHERE app_code = ? AND status IN (?, ?)
AND next_retry_at_ms <= ?
ORDER BY created_at_ms ASC
@ -1717,12 +2136,23 @@ func (r *Repository) ListPendingOutbox(ctx context.Context, limit int) ([]outbox
// ClaimPendingOutbox 抢占一批待投递事件,避免多 worker 同时投递同一批。
func (r *Repository) ClaimPendingOutbox(ctx context.Context, workerID string, limit int, lockUntilMS int64) ([]outbox.Record, error) {
return r.claimPendingOutboxFromTable(ctx, roomOutboxTable, workerID, limit, lockUntilMS)
}
// ClaimPendingRobotOutbox 抢占机器人房间展示事件,避免机器人流量占用主 room_outbox worker。
func (r *Repository) ClaimPendingRobotOutbox(ctx context.Context, workerID string, limit int, lockUntilMS int64) ([]outbox.Record, error) {
return r.claimPendingOutboxFromTable(ctx, roomRobotOutboxTable, workerID, limit, lockUntilMS)
}
func (r *Repository) claimPendingOutboxFromTable(ctx context.Context, table string, workerID string, limit int, lockUntilMS int64) ([]outbox.Record, error) {
if limit <= 0 {
limit = 100
}
if strings.TrimSpace(workerID) == "" {
workerID = "room-outbox-worker"
}
table = roomOutboxTableName(table)
pendingIndex, claimIndex := roomOutboxIndexes(table)
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
@ -1738,7 +2168,7 @@ func (r *Repository) ClaimPendingOutbox(ctx context.Context, workerID string, li
}{
{
query: `SELECT app_code, event_id, event_type, room_id, status, worker_id, lock_until_ms, envelope, created_at_ms, retry_count, next_retry_at_ms, COALESCE(last_error, '')
FROM room_outbox FORCE INDEX (idx_room_outbox_pending)
FROM ` + table + ` FORCE INDEX (` + pendingIndex + `)
WHERE app_code = ? AND status = ? AND next_retry_at_ms <= ? AND lock_until_ms IS NULL
ORDER BY created_at_ms ASC, event_id ASC
LIMIT ? FOR UPDATE SKIP LOCKED`,
@ -1746,7 +2176,7 @@ func (r *Repository) ClaimPendingOutbox(ctx context.Context, workerID string, li
},
{
query: `SELECT app_code, event_id, event_type, room_id, status, worker_id, lock_until_ms, envelope, created_at_ms, retry_count, next_retry_at_ms, COALESCE(last_error, '')
FROM room_outbox FORCE INDEX (idx_room_outbox_pending)
FROM ` + table + ` FORCE INDEX (` + pendingIndex + `)
WHERE app_code = ? AND status = ? AND next_retry_at_ms <= ? AND lock_until_ms IS NULL
ORDER BY created_at_ms ASC, event_id ASC
LIMIT ? FOR UPDATE SKIP LOCKED`,
@ -1754,7 +2184,7 @@ func (r *Repository) ClaimPendingOutbox(ctx context.Context, workerID string, li
},
{
query: `SELECT app_code, event_id, event_type, room_id, status, worker_id, lock_until_ms, envelope, created_at_ms, retry_count, next_retry_at_ms, COALESCE(last_error, '')
FROM room_outbox FORCE INDEX (idx_room_outbox_claim)
FROM ` + table + ` FORCE INDEX (` + claimIndex + `)
WHERE app_code = ? AND status = ? AND lock_until_ms <= ?
ORDER BY created_at_ms ASC, event_id ASC
LIMIT ? FOR UPDATE SKIP LOCKED`,
@ -1777,7 +2207,7 @@ func (r *Repository) ClaimPendingOutbox(ctx context.Context, workerID string, li
for _, record := range records {
if _, err := tx.ExecContext(ctx,
`UPDATE room_outbox
`UPDATE `+table+`
SET status = ?, worker_id = ?, lock_until_ms = ?, updated_at_ms = ?
WHERE app_code = ? AND event_id = ?`,
outbox.StatusDelivering,
@ -1841,9 +2271,19 @@ func (r *Repository) queryRoomOutboxRecords(ctx context.Context, tx *sql.Tx, que
// MarkOutboxDelivered 标记事件投递成功。
func (r *Repository) MarkOutboxDelivered(ctx context.Context, eventID string) error {
return r.markOutboxDeliveredInTable(ctx, roomOutboxTable, eventID)
}
// MarkRobotOutboxDelivered 标记机器人展示事件已经投递成功。
func (r *Repository) MarkRobotOutboxDelivered(ctx context.Context, eventID string) error {
return r.markOutboxDeliveredInTable(ctx, roomRobotOutboxTable, eventID)
}
func (r *Repository) markOutboxDeliveredInTable(ctx context.Context, table string, eventID string) error {
table = roomOutboxTableName(table)
// 成功后清空 last_error后续扫描不再返回该事件。
_, err := r.db.ExecContext(ctx,
`UPDATE room_outbox
`UPDATE `+table+`
SET status = ?, worker_id = '', lock_until_ms = NULL, last_error = NULL, updated_at_ms = ?
WHERE app_code = ? AND event_id = ?`,
outbox.StatusDelivered,
@ -1857,9 +2297,19 @@ func (r *Repository) MarkOutboxDelivered(ctx context.Context, eventID string) er
// MarkOutboxRetryable 标记事件投递失败并写入下一次重试时间。
func (r *Repository) MarkOutboxRetryable(ctx context.Context, eventID string, lastErr string, nextRetryAtMS int64) error {
return r.markOutboxRetryableInTable(ctx, roomOutboxTable, eventID, lastErr, nextRetryAtMS)
}
// MarkRobotOutboxRetryable 记录机器人展示事件投递失败,并写入独立重试退避。
func (r *Repository) MarkRobotOutboxRetryable(ctx context.Context, eventID string, lastErr string, nextRetryAtMS int64) error {
return r.markOutboxRetryableInTable(ctx, roomRobotOutboxTable, eventID, lastErr, nextRetryAtMS)
}
func (r *Repository) markOutboxRetryableInTable(ctx context.Context, table string, eventID string, lastErr string, nextRetryAtMS int64) error {
table = roomOutboxTableName(table)
// 失败转入 retryableworker 只有到 next_retry_at_ms 后才会重新抢占。
_, err := r.db.ExecContext(ctx,
`UPDATE room_outbox
`UPDATE `+table+`
SET status = ?, worker_id = '', lock_until_ms = NULL, retry_count = retry_count + 1, next_retry_at_ms = ?, last_error = ?, updated_at_ms = ?
WHERE app_code = ? AND event_id = ?`,
outbox.StatusRetryable,
@ -1875,8 +2325,18 @@ func (r *Repository) MarkOutboxRetryable(ctx context.Context, eventID string, la
// MarkOutboxDead 把超过最大重试次数的事件转入 failed。
func (r *Repository) MarkOutboxDead(ctx context.Context, eventID string, lastErr string) error {
return r.markOutboxDeadInTable(ctx, roomOutboxTable, eventID, lastErr)
}
// MarkRobotOutboxDead 把超过最大重试次数的机器人展示事件转入 failed。
func (r *Repository) MarkRobotOutboxDead(ctx context.Context, eventID string, lastErr string) error {
return r.markOutboxDeadInTable(ctx, roomRobotOutboxTable, eventID, lastErr)
}
func (r *Repository) markOutboxDeadInTable(ctx context.Context, table string, eventID string, lastErr string) error {
table = roomOutboxTableName(table)
_, err := r.db.ExecContext(ctx,
`UPDATE room_outbox
`UPDATE `+table+`
SET status = ?, worker_id = '', lock_until_ms = NULL, last_error = ?, updated_at_ms = ?
WHERE app_code = ? AND event_id = ?`,
outbox.StatusFailed,
@ -1889,6 +2349,22 @@ func (r *Repository) MarkOutboxDead(ctx context.Context, eventID string, lastErr
return err
}
func roomOutboxTableName(table string) string {
switch table {
case roomRobotOutboxTable:
return roomRobotOutboxTable
default:
return roomOutboxTable
}
}
func roomOutboxIndexes(table string) (pending string, claim string) {
if roomOutboxTableName(table) == roomRobotOutboxTable {
return "idx_room_robot_outbox_pending", "idx_room_robot_outbox_claim"
}
return "idx_room_outbox_pending", "idx_room_outbox_claim"
}
// UpsertRoomListEntry 写入房间列表读模型。
func (r *Repository) UpsertRoomListEntry(ctx context.Context, entry roomservice.RoomListEntry) error {
// created_at_ms 首次插入后保持不变,避免 Join/Leave/SendGift 等更新把 new tab 顺序洗掉。
@ -2366,6 +2842,13 @@ func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
countryLiteral := roomListSQLStringLiteral(sortCountryCode)
normalRankExpr = "CASE WHEN r.owner_country_code = " + countryLiteral + " AND r.online_count > 0 THEN 2 WHEN r.owner_country_code <> " + countryLiteral + " AND r.online_count > 0 THEN 3 WHEN r.owner_country_code = " + countryLiteral + " THEN 4 ELSE 5 END"
}
regionPinScopeSQL := "AND rp.visible_region_id = ?"
countryPinScopeSQL := "AND cp.visible_region_id = ?"
if query.AllVisibleRegions {
// 白名单用户查看全区列表时,区域/国家置顶按房间自身区域命中,不能再固定到 viewer 区域。
regionPinScopeSQL = "AND rp.visible_region_id = r.visible_region_id"
countryPinScopeSQL = "AND cp.visible_region_id = r.visible_region_id"
}
pinnedExpr := "CASE WHEN gp.room_id IS NULL AND rp.room_id IS NULL AND cp.room_id IS NULL THEN 0 ELSE 1 END"
pinRankExpr := "CASE WHEN gp.room_id IS NOT NULL THEN 0 WHEN rp.room_id IS NOT NULL THEN 0 WHEN cp.room_id IS NOT NULL THEN 1 ELSE " + normalRankExpr + " END"
pinWeightExpr := "CASE WHEN gp.room_id IS NOT NULL THEN gp.weight WHEN rp.room_id IS NOT NULL THEN rp.weight WHEN cp.room_id IS NOT NULL THEN cp.weight ELSE 0 END"
@ -2386,7 +2869,7 @@ func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
LEFT JOIN room_region_pins rp
ON rp.app_code = r.app_code
AND rp.pin_type = 'region'
AND rp.visible_region_id = ?
` + regionPinScopeSQL + `
AND rp.room_id = r.room_id
AND rp.status = ?
AND rp.pinned_at_ms <= ?
@ -2394,14 +2877,27 @@ func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
LEFT JOIN room_region_pins cp
ON cp.app_code = r.app_code
AND cp.pin_type = 'country'
AND cp.visible_region_id = ?
` + countryPinScopeSQL + `
AND cp.room_id = r.room_id
AND r.owner_country_code = ?
AND cp.status = ?
AND cp.pinned_at_ms <= ?
AND cp.expires_at_ms > ?`
where := []string{"r.app_code = ?", "r.status = ?", "r.visible_region_id = ?"}
args := []any{"active", query.NowMS, query.NowMS, regionID, "active", query.NowMS, query.NowMS, regionID, sortCountryCode, "active", query.NowMS, query.NowMS, appcode.Normalize(query.AppCode), "active", regionID}
where := []string{"r.app_code = ?", "r.status = ?"}
args := []any{"active", query.NowMS, query.NowMS}
if !query.AllVisibleRegions {
args = append(args, regionID)
}
args = append(args, "active", query.NowMS, query.NowMS)
if !query.AllVisibleRegions {
args = append(args, regionID)
}
args = append(args, sortCountryCode, "active", query.NowMS, query.NowMS, appcode.Normalize(query.AppCode), "active")
if !query.AllVisibleRegions {
// 普通发现页必须利用区域索引隔离结果;白名单模式只保留 app/status/可选国家/关键词条件。
where = append(where, "r.visible_region_id = ?")
args = append(args, regionID)
}
if query.OwnerUserID > 0 {
where = append(where, "r.owner_user_id = ?")
args = append(args, query.OwnerUserID)

View File

@ -177,6 +177,11 @@ func (s *Server) AdminUpdateRoomSeatConfig(ctx context.Context, req *roomv1.Admi
return mapServiceResult(s.svc.AdminUpdateRoomSeatConfig(ctx, req))
}
func (s *Server) AdminUpdateHumanRoomRobotConfig(ctx context.Context, req *roomv1.AdminUpdateHumanRoomRobotConfigRequest) (*roomv1.AdminUpdateHumanRoomRobotConfigResponse, error) {
ctx = contextWithMetaApp(ctx, req.GetMeta())
return mapServiceResult(s.svc.AdminUpdateHumanRoomRobotConfig(ctx, req))
}
func (s *Server) AdminCreateRoomPin(ctx context.Context, req *roomv1.AdminCreateRoomPinRequest) (*roomv1.AdminCreateRoomPinResponse, error) {
ctx = contextWithMetaApp(ctx, req.GetMeta())
return mapServiceResult(s.svc.AdminCreateRoomPin(ctx, req))
@ -448,6 +453,11 @@ func (s *Server) AdminGetRoomSeatConfig(ctx context.Context, req *roomv1.AdminGe
return mapServiceResult(s.svc.AdminGetRoomSeatConfig(ctx, req))
}
func (s *Server) AdminGetHumanRoomRobotConfig(ctx context.Context, req *roomv1.AdminGetHumanRoomRobotConfigRequest) (*roomv1.AdminGetHumanRoomRobotConfigResponse, error) {
ctx = contextWithMetaApp(ctx, req.GetMeta())
return mapServiceResult(s.svc.AdminGetHumanRoomRobotConfig(ctx, req))
}
func (s *Server) AdminListRoomPins(ctx context.Context, req *roomv1.AdminListRoomPinsRequest) (*roomv1.AdminListRoomPinsResponse, error) {
ctx = contextWithMetaApp(ctx, req.GetMeta())
return mapServiceResult(s.svc.AdminListRoomPins(ctx, req))

View File

@ -106,6 +106,21 @@ CREATE TABLE IF NOT EXISTS stat_lucky_gift_pool_day_country (
KEY idx_stat_lucky_pool_region (app_code, stat_day, region_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物奖池国家日统计聚合表';
CREATE TABLE IF NOT EXISTS stat_real_room_robot_gift_day_rooms (
app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
stat_day DATE NOT NULL COMMENT 'UTC 统计日',
country_id BIGINT NOT NULL DEFAULT 0 COMMENT '国家维度 ID0 表示未知或全局',
region_id BIGINT NOT NULL DEFAULT 0 COMMENT '区域维度 ID0 表示未知或全局',
room_id VARCHAR(96) NOT NULL COMMENT '真人房间 ID',
normal_gift_coin BIGINT NOT NULL DEFAULT 0 COMMENT '机器人在真人房送出的普通礼物金币价值',
lucky_gift_coin BIGINT NOT NULL DEFAULT 0 COMMENT '机器人在真人房送出的幸运礼物金币价值',
super_lucky_gift_coin BIGINT NOT NULL DEFAULT 0 COMMENT '机器人在真人房送出的超级幸运礼物金币价值',
updated_at_ms BIGINT NOT NULL COMMENT '更新时间UTC epoch ms',
PRIMARY KEY (app_code, stat_day, country_id, region_id, room_id),
KEY idx_stat_real_room_robot_gift_region (app_code, stat_day, region_id),
KEY idx_stat_real_room_robot_gift_country (app_code, stat_day, country_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='真人房机器人礼物房间日统计表';
CREATE TABLE IF NOT EXISTS stat_game_day_country (
app_code VARCHAR(32) NOT NULL,
stat_day DATE NOT NULL,

View File

@ -371,18 +371,21 @@ func roomGiftEvent(body []byte) (mysqlstorage.RoomGiftEvent, bool, error) {
if err := proto.Unmarshal(envelope.GetBody(), &gift); err != nil {
return mysqlstorage.RoomGiftEvent{}, false, err
}
if gift.GetIsRobotGift() {
if gift.GetIsRobotGift() && !gift.GetRealRoomRobotGift() {
return mysqlstorage.RoomGiftEvent{}, false, nil
}
return mysqlstorage.RoomGiftEvent{
AppCode: envelope.GetAppCode(),
EventID: envelope.GetEventId(),
RoomID: envelope.GetRoomId(),
SenderUserID: gift.GetSenderUserId(),
CountryID: gift.GetCountryId(),
VisibleRegionID: firstNonZeroInt64(gift.GetRegionId(), gift.GetVisibleRegionId()),
GiftValue: gift.GetGiftValue(),
CoinSpent: roomGiftCoinSpent(&gift),
PoolID: gift.GetPoolId(),
GiftTypeCode: gift.GetGiftTypeCode(),
RealRoomRobot: gift.GetRealRoomRobotGift(),
OccurredAtMS: envelope.GetOccurredAtMs(),
}, true, nil
}

View File

@ -131,6 +131,28 @@ func TestLocalStatisticsDataScreenFlow(t *testing.T) {
if err := repo.ConsumeRoomGift(ctx, gift); err != nil {
t.Fatalf("consume room gift failed: %v", err)
}
robotGiftBody := roomGiftMessage(t, appCode, "room_gift_robot_1", "room_robot_real", occurredAt, &roomeventsv1.RoomGiftSent{
SenderUserId: 88001,
TargetUserId: 88002,
GiftId: "robot-super",
GiftCount: 1,
GiftValue: 700,
CoinSpent: 900,
VisibleRegionId: regionID,
CommandId: "gift_command_robot_1",
PoolId: "human_robot_super_lucky_display",
GiftTypeCode: "super_lucky",
IsRobotGift: true,
RealRoomRobotGift: true,
SyntheticLuckyGift: true,
})
robotGift, ok, err := roomGiftEvent(robotGiftBody)
if err != nil || !ok {
t.Fatalf("decode real room robot gift failed: ok=%v err=%v", ok, err)
}
if err := repo.ConsumeRoomGift(ctx, robotGift); err != nil {
t.Fatalf("consume real room robot gift failed: %v", err)
}
luckyReward := walletMessage(t, walletmq.WalletOutboxMessage{
AppCode: appCode,
@ -190,6 +212,9 @@ func TestLocalStatisticsDataScreenFlow(t *testing.T) {
if overview.LuckyGiftTurnover != 1_250 || overview.LuckyGiftPayout != 300 || overview.LuckyGiftProfit != 950 || overview.LuckyGiftPayers != 1 {
t.Fatalf("lucky gift metrics mismatch: %+v", overview)
}
if overview.RealRoomRobotSuperGiftCoin != 900 || overview.RealRoomRobotTotalGiftCoin != 900 || overview.RealRoomRobotGiftRoomCount != 1 || overview.RealRoomRobotAvgRoomGiftCoin != 900 {
t.Fatalf("real room robot gift metrics mismatch: %+v", overview)
}
if len(overview.LuckyGiftPools) != 1 {
t.Fatalf("lucky gift pool breakdown missing: %+v", overview.LuckyGiftPools)
}

Some files were not shown because too many files have changed in this diff Show More