Compare commits
6 Commits
c59317c6d2
...
9c056b9cbf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c056b9cbf | ||
|
|
db43da8c85 | ||
|
|
a0c9d055f0 | ||
|
|
c93a30f3db | ||
|
|
0d111d9a88 | ||
|
|
da64d5f189 |
@ -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
@ -1886,6 +1886,134 @@ message GetLuckyGiftDrawSummaryResponse {
|
||||
LuckyGiftDrawSummary summary = 1;
|
||||
}
|
||||
|
||||
message WheelPrizeTier {
|
||||
string tier_id = 1;
|
||||
string display_name = 2;
|
||||
string reward_type = 3;
|
||||
string reward_id = 4;
|
||||
int64 reward_count = 5;
|
||||
int64 reward_coins = 6;
|
||||
int64 rtp_value_coins = 7;
|
||||
int64 weight_ppm = 8;
|
||||
bool enabled = 9;
|
||||
string metadata_json = 10;
|
||||
}
|
||||
|
||||
message WheelRuleConfig {
|
||||
string app_code = 1;
|
||||
string wheel_id = 2;
|
||||
int64 rule_version = 3;
|
||||
bool enabled = 4;
|
||||
int64 draw_price_coins = 5;
|
||||
int64 target_rtp_ppm = 6;
|
||||
int64 pool_rate_ppm = 7;
|
||||
int64 settlement_window_draws = 8;
|
||||
int64 initial_pool_coins = 9;
|
||||
int64 pool_reserve_coins = 10;
|
||||
int64 max_single_rtp_payout = 11;
|
||||
int64 effective_from_ms = 12;
|
||||
int64 created_by_admin_id = 13;
|
||||
int64 created_at_ms = 14;
|
||||
repeated WheelPrizeTier tiers = 15;
|
||||
}
|
||||
|
||||
message WheelDrawMeta {
|
||||
RequestMeta meta = 1;
|
||||
string command_id = 2;
|
||||
string wheel_id = 3;
|
||||
int64 user_id = 4;
|
||||
string device_id = 5;
|
||||
int32 draw_count = 6;
|
||||
int64 coin_spent = 7;
|
||||
int64 paid_at_ms = 8;
|
||||
int64 visible_region_id = 9;
|
||||
}
|
||||
|
||||
message WheelDrawResult {
|
||||
string draw_id = 1;
|
||||
repeated string draw_ids = 2;
|
||||
string command_id = 3;
|
||||
string wheel_id = 4;
|
||||
int64 rule_version = 5;
|
||||
string selected_tier_id = 6;
|
||||
string reward_type = 7;
|
||||
string reward_id = 8;
|
||||
int64 reward_count = 9;
|
||||
int64 reward_coins = 10;
|
||||
int64 rtp_value_coins = 11;
|
||||
string reward_status = 12;
|
||||
int64 rtp_window_index = 13;
|
||||
int64 actual_rtp_ppm = 14;
|
||||
int64 created_at_ms = 15;
|
||||
string wallet_transaction_id = 16;
|
||||
int64 coin_balance_after = 17;
|
||||
string metadata_json = 18;
|
||||
}
|
||||
|
||||
message ExecuteWheelDrawRequest {
|
||||
WheelDrawMeta wheel = 1;
|
||||
}
|
||||
|
||||
message ExecuteWheelDrawResponse {
|
||||
WheelDrawResult result = 1;
|
||||
}
|
||||
|
||||
message GetWheelConfigRequest {
|
||||
RequestMeta meta = 1;
|
||||
string wheel_id = 2;
|
||||
}
|
||||
|
||||
message GetWheelConfigResponse {
|
||||
WheelRuleConfig config = 1;
|
||||
}
|
||||
|
||||
message UpsertWheelConfigRequest {
|
||||
RequestMeta meta = 1;
|
||||
WheelRuleConfig config = 2;
|
||||
int64 operator_admin_id = 3;
|
||||
}
|
||||
|
||||
message UpsertWheelConfigResponse {
|
||||
WheelRuleConfig config = 1;
|
||||
}
|
||||
|
||||
message ListWheelDrawsRequest {
|
||||
RequestMeta meta = 1;
|
||||
string wheel_id = 2;
|
||||
int64 user_id = 3;
|
||||
string status = 4;
|
||||
int32 page = 5;
|
||||
int32 page_size = 6;
|
||||
}
|
||||
|
||||
message ListWheelDrawsResponse {
|
||||
repeated WheelDrawResult draws = 1;
|
||||
int64 total = 2;
|
||||
}
|
||||
|
||||
message WheelDrawSummary {
|
||||
string wheel_id = 1;
|
||||
int64 total_draws = 2;
|
||||
int64 unique_users = 3;
|
||||
int64 total_spent_coins = 4;
|
||||
int64 total_rtp_value_coins = 5;
|
||||
int64 actual_rtp_ppm = 6;
|
||||
int64 pending_draws = 7;
|
||||
int64 granted_draws = 8;
|
||||
int64 failed_draws = 9;
|
||||
}
|
||||
|
||||
message GetWheelDrawSummaryRequest {
|
||||
RequestMeta meta = 1;
|
||||
string wheel_id = 2;
|
||||
int64 user_id = 3;
|
||||
string status = 4;
|
||||
}
|
||||
|
||||
message GetWheelDrawSummaryResponse {
|
||||
WheelDrawSummary summary = 1;
|
||||
}
|
||||
|
||||
// WeeklyStarGift 是周星周期内参与积分的指定礼物。
|
||||
message WeeklyStarGift {
|
||||
string gift_id = 1;
|
||||
@ -2191,6 +2319,10 @@ message AgencyOpeningApplication {
|
||||
int64 granted_at_ms = 16;
|
||||
int64 updated_at_ms = 17;
|
||||
int64 reward_threshold_coin_spent = 18;
|
||||
int64 approved_at_ms = 19;
|
||||
int64 score_start_ms = 20;
|
||||
int64 score_end_ms = 21;
|
||||
int64 reviewed_by_admin_id = 22;
|
||||
}
|
||||
|
||||
// AgencyOpeningAgencySnapshot 是申请页展示和资格判断使用的代理快照。
|
||||
@ -2263,6 +2395,17 @@ message ListAgencyOpeningApplicationsResponse {
|
||||
int64 total = 2;
|
||||
}
|
||||
|
||||
message ReviewAgencyOpeningApplicationRequest {
|
||||
RequestMeta meta = 1;
|
||||
string application_id = 2;
|
||||
string action = 3;
|
||||
int64 operator_admin_id = 4;
|
||||
}
|
||||
|
||||
message ReviewAgencyOpeningApplicationResponse {
|
||||
AgencyOpeningApplication application = 1;
|
||||
}
|
||||
|
||||
message GetAgencyOpeningStatusRequest {
|
||||
RequestMeta meta = 1;
|
||||
int64 user_id = 2;
|
||||
@ -2350,6 +2493,11 @@ service LuckyGiftService {
|
||||
rpc ExecuteLuckyGiftDraw(ExecuteLuckyGiftDrawRequest) returns (ExecuteLuckyGiftDrawResponse);
|
||||
}
|
||||
|
||||
// WheelService owns wheel draw decisions after wallet debit succeeds.
|
||||
service WheelService {
|
||||
rpc ExecuteWheelDraw(ExecuteWheelDrawRequest) returns (ExecuteWheelDrawResponse);
|
||||
}
|
||||
|
||||
// RoomTurnoverRewardService owns App reads for the weekly room turnover reward activity.
|
||||
service RoomTurnoverRewardService {
|
||||
rpc GetRoomTurnoverRewardStatus(GetRoomTurnoverRewardStatusRequest) returns (GetRoomTurnoverRewardStatusResponse);
|
||||
@ -2483,6 +2631,7 @@ service AdminAgencyOpeningService {
|
||||
rpc UpdateAgencyOpeningCycle(UpsertAgencyOpeningCycleRequest) returns (UpsertAgencyOpeningCycleResponse);
|
||||
rpc SetAgencyOpeningCycleStatus(SetAgencyOpeningCycleStatusRequest) returns (SetAgencyOpeningCycleStatusResponse);
|
||||
rpc ListAgencyOpeningApplications(ListAgencyOpeningApplicationsRequest) returns (ListAgencyOpeningApplicationsResponse);
|
||||
rpc ReviewAgencyOpeningApplication(ReviewAgencyOpeningApplicationRequest) returns (ReviewAgencyOpeningApplicationResponse);
|
||||
}
|
||||
|
||||
// SevenDayCheckInService 拥有 App 七日签到查询和签到命令。
|
||||
@ -2520,3 +2669,11 @@ service AdminLuckyGiftService {
|
||||
rpc ListLuckyGiftDraws(ListLuckyGiftDrawsRequest) returns (ListLuckyGiftDrawsResponse);
|
||||
rpc GetLuckyGiftDrawSummary(GetLuckyGiftDrawSummaryRequest) returns (GetLuckyGiftDrawSummaryResponse);
|
||||
}
|
||||
|
||||
// AdminWheelService is the admin entry for wheel rule versions, draw records, and RTP statistics.
|
||||
service AdminWheelService {
|
||||
rpc GetWheelConfig(GetWheelConfigRequest) returns (GetWheelConfigResponse);
|
||||
rpc UpsertWheelConfig(UpsertWheelConfigRequest) returns (UpsertWheelConfigResponse);
|
||||
rpc ListWheelDraws(ListWheelDrawsRequest) returns (ListWheelDrawsResponse);
|
||||
rpc GetWheelDrawSummary(GetWheelDrawSummaryRequest) returns (GetWheelDrawSummaryResponse);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
@ -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.
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
@ -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
@ -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
@ -1471,6 +1471,22 @@ message DebitCPBreakupFeeResponse {
|
||||
AssetBalance balance = 4;
|
||||
}
|
||||
|
||||
message DebitWheelDrawRequest {
|
||||
string command_id = 1;
|
||||
string app_code = 2;
|
||||
int64 user_id = 3;
|
||||
string wheel_id = 4;
|
||||
int32 draw_count = 5;
|
||||
int64 amount = 6;
|
||||
}
|
||||
|
||||
message DebitWheelDrawResponse {
|
||||
string transaction_id = 1;
|
||||
int64 coin_spent = 2;
|
||||
int64 coin_balance_after = 3;
|
||||
AssetBalance balance = 4;
|
||||
}
|
||||
|
||||
message GrantVipRequest {
|
||||
string command_id = 1;
|
||||
string app_code = 2;
|
||||
@ -1563,6 +1579,27 @@ message CreditLuckyGiftRewardResponse {
|
||||
int64 granted_at_ms = 4;
|
||||
}
|
||||
|
||||
// CreditWheelRewardRequest 是 activity-service 转盘金币奖品 outbox 调用的钱包入账命令。
|
||||
message CreditWheelRewardRequest {
|
||||
string command_id = 1;
|
||||
string app_code = 2;
|
||||
int64 target_user_id = 3;
|
||||
int64 amount = 4;
|
||||
string draw_id = 5;
|
||||
string wheel_id = 6;
|
||||
string selected_tier_id = 7;
|
||||
string reason = 8;
|
||||
int64 visible_region_id = 9;
|
||||
}
|
||||
|
||||
// CreditWheelRewardResponse 返回转盘金币奖品入账流水和用户 COIN 账后余额。
|
||||
message CreditWheelRewardResponse {
|
||||
string transaction_id = 1;
|
||||
AssetBalance balance = 2;
|
||||
int64 amount = 3;
|
||||
int64 granted_at_ms = 4;
|
||||
}
|
||||
|
||||
// CreditRoomTurnoverRewardRequest 是 activity-service 每周房间流水奖励结算后的金币入账命令。
|
||||
message CreditRoomTurnoverRewardRequest {
|
||||
string command_id = 1;
|
||||
@ -1928,11 +1965,13 @@ service WalletService {
|
||||
rpc GetMyVip(GetMyVipRequest) returns (GetMyVipResponse);
|
||||
rpc PurchaseVip(PurchaseVipRequest) returns (PurchaseVipResponse);
|
||||
rpc DebitCPBreakupFee(DebitCPBreakupFeeRequest) returns (DebitCPBreakupFeeResponse);
|
||||
rpc DebitWheelDraw(DebitWheelDrawRequest) returns (DebitWheelDrawResponse);
|
||||
rpc GrantVip(GrantVipRequest) returns (GrantVipResponse);
|
||||
rpc ListAdminVipLevels(ListAdminVipLevelsRequest) returns (ListAdminVipLevelsResponse);
|
||||
rpc UpdateAdminVipLevels(UpdateAdminVipLevelsRequest) returns (UpdateAdminVipLevelsResponse);
|
||||
rpc CreditTaskReward(CreditTaskRewardRequest) returns (CreditTaskRewardResponse);
|
||||
rpc CreditLuckyGiftReward(CreditLuckyGiftRewardRequest) returns (CreditLuckyGiftRewardResponse);
|
||||
rpc CreditWheelReward(CreditWheelRewardRequest) returns (CreditWheelRewardResponse);
|
||||
rpc CreditRoomTurnoverReward(CreditRoomTurnoverRewardRequest) returns (CreditRoomTurnoverRewardResponse);
|
||||
rpc CreditInviteActivityReward(CreditInviteActivityRewardRequest) returns (CreditInviteActivityRewardResponse);
|
||||
rpc CreditAgencyOpeningReward(CreditAgencyOpeningRewardRequest) returns (CreditAgencyOpeningRewardResponse);
|
||||
|
||||
@ -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.
|
||||
@ -265,11 +265,13 @@ const (
|
||||
WalletService_GetMyVip_FullMethodName = "/hyapp.wallet.v1.WalletService/GetMyVip"
|
||||
WalletService_PurchaseVip_FullMethodName = "/hyapp.wallet.v1.WalletService/PurchaseVip"
|
||||
WalletService_DebitCPBreakupFee_FullMethodName = "/hyapp.wallet.v1.WalletService/DebitCPBreakupFee"
|
||||
WalletService_DebitWheelDraw_FullMethodName = "/hyapp.wallet.v1.WalletService/DebitWheelDraw"
|
||||
WalletService_GrantVip_FullMethodName = "/hyapp.wallet.v1.WalletService/GrantVip"
|
||||
WalletService_ListAdminVipLevels_FullMethodName = "/hyapp.wallet.v1.WalletService/ListAdminVipLevels"
|
||||
WalletService_UpdateAdminVipLevels_FullMethodName = "/hyapp.wallet.v1.WalletService/UpdateAdminVipLevels"
|
||||
WalletService_CreditTaskReward_FullMethodName = "/hyapp.wallet.v1.WalletService/CreditTaskReward"
|
||||
WalletService_CreditLuckyGiftReward_FullMethodName = "/hyapp.wallet.v1.WalletService/CreditLuckyGiftReward"
|
||||
WalletService_CreditWheelReward_FullMethodName = "/hyapp.wallet.v1.WalletService/CreditWheelReward"
|
||||
WalletService_CreditRoomTurnoverReward_FullMethodName = "/hyapp.wallet.v1.WalletService/CreditRoomTurnoverReward"
|
||||
WalletService_CreditInviteActivityReward_FullMethodName = "/hyapp.wallet.v1.WalletService/CreditInviteActivityReward"
|
||||
WalletService_CreditAgencyOpeningReward_FullMethodName = "/hyapp.wallet.v1.WalletService/CreditAgencyOpeningReward"
|
||||
@ -354,11 +356,13 @@ type WalletServiceClient interface {
|
||||
GetMyVip(ctx context.Context, in *GetMyVipRequest, opts ...grpc.CallOption) (*GetMyVipResponse, error)
|
||||
PurchaseVip(ctx context.Context, in *PurchaseVipRequest, opts ...grpc.CallOption) (*PurchaseVipResponse, error)
|
||||
DebitCPBreakupFee(ctx context.Context, in *DebitCPBreakupFeeRequest, opts ...grpc.CallOption) (*DebitCPBreakupFeeResponse, error)
|
||||
DebitWheelDraw(ctx context.Context, in *DebitWheelDrawRequest, opts ...grpc.CallOption) (*DebitWheelDrawResponse, error)
|
||||
GrantVip(ctx context.Context, in *GrantVipRequest, opts ...grpc.CallOption) (*GrantVipResponse, error)
|
||||
ListAdminVipLevels(ctx context.Context, in *ListAdminVipLevelsRequest, opts ...grpc.CallOption) (*ListAdminVipLevelsResponse, error)
|
||||
UpdateAdminVipLevels(ctx context.Context, in *UpdateAdminVipLevelsRequest, opts ...grpc.CallOption) (*UpdateAdminVipLevelsResponse, error)
|
||||
CreditTaskReward(ctx context.Context, in *CreditTaskRewardRequest, opts ...grpc.CallOption) (*CreditTaskRewardResponse, error)
|
||||
CreditLuckyGiftReward(ctx context.Context, in *CreditLuckyGiftRewardRequest, opts ...grpc.CallOption) (*CreditLuckyGiftRewardResponse, error)
|
||||
CreditWheelReward(ctx context.Context, in *CreditWheelRewardRequest, opts ...grpc.CallOption) (*CreditWheelRewardResponse, error)
|
||||
CreditRoomTurnoverReward(ctx context.Context, in *CreditRoomTurnoverRewardRequest, opts ...grpc.CallOption) (*CreditRoomTurnoverRewardResponse, error)
|
||||
CreditInviteActivityReward(ctx context.Context, in *CreditInviteActivityRewardRequest, opts ...grpc.CallOption) (*CreditInviteActivityRewardResponse, error)
|
||||
CreditAgencyOpeningReward(ctx context.Context, in *CreditAgencyOpeningRewardRequest, opts ...grpc.CallOption) (*CreditAgencyOpeningRewardResponse, error)
|
||||
@ -1021,6 +1025,16 @@ func (c *walletServiceClient) DebitCPBreakupFee(ctx context.Context, in *DebitCP
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) DebitWheelDraw(ctx context.Context, in *DebitWheelDrawRequest, opts ...grpc.CallOption) (*DebitWheelDrawResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DebitWheelDrawResponse)
|
||||
err := c.cc.Invoke(ctx, WalletService_DebitWheelDraw_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) GrantVip(ctx context.Context, in *GrantVipRequest, opts ...grpc.CallOption) (*GrantVipResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GrantVipResponse)
|
||||
@ -1071,6 +1085,16 @@ func (c *walletServiceClient) CreditLuckyGiftReward(ctx context.Context, in *Cre
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) CreditWheelReward(ctx context.Context, in *CreditWheelRewardRequest, opts ...grpc.CallOption) (*CreditWheelRewardResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreditWheelRewardResponse)
|
||||
err := c.cc.Invoke(ctx, WalletService_CreditWheelReward_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) CreditRoomTurnoverReward(ctx context.Context, in *CreditRoomTurnoverRewardRequest, opts ...grpc.CallOption) (*CreditRoomTurnoverRewardResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreditRoomTurnoverRewardResponse)
|
||||
@ -1261,11 +1285,13 @@ type WalletServiceServer interface {
|
||||
GetMyVip(context.Context, *GetMyVipRequest) (*GetMyVipResponse, error)
|
||||
PurchaseVip(context.Context, *PurchaseVipRequest) (*PurchaseVipResponse, error)
|
||||
DebitCPBreakupFee(context.Context, *DebitCPBreakupFeeRequest) (*DebitCPBreakupFeeResponse, error)
|
||||
DebitWheelDraw(context.Context, *DebitWheelDrawRequest) (*DebitWheelDrawResponse, error)
|
||||
GrantVip(context.Context, *GrantVipRequest) (*GrantVipResponse, error)
|
||||
ListAdminVipLevels(context.Context, *ListAdminVipLevelsRequest) (*ListAdminVipLevelsResponse, error)
|
||||
UpdateAdminVipLevels(context.Context, *UpdateAdminVipLevelsRequest) (*UpdateAdminVipLevelsResponse, error)
|
||||
CreditTaskReward(context.Context, *CreditTaskRewardRequest) (*CreditTaskRewardResponse, error)
|
||||
CreditLuckyGiftReward(context.Context, *CreditLuckyGiftRewardRequest) (*CreditLuckyGiftRewardResponse, error)
|
||||
CreditWheelReward(context.Context, *CreditWheelRewardRequest) (*CreditWheelRewardResponse, error)
|
||||
CreditRoomTurnoverReward(context.Context, *CreditRoomTurnoverRewardRequest) (*CreditRoomTurnoverRewardResponse, error)
|
||||
CreditInviteActivityReward(context.Context, *CreditInviteActivityRewardRequest) (*CreditInviteActivityRewardResponse, error)
|
||||
CreditAgencyOpeningReward(context.Context, *CreditAgencyOpeningRewardRequest) (*CreditAgencyOpeningRewardResponse, error)
|
||||
@ -1289,247 +1315,253 @@ 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) DebitWheelDraw(context.Context, *DebitWheelDrawRequest) (*DebitWheelDrawResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DebitWheelDraw 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) CreditWheelReward(context.Context, *CreditWheelRewardRequest) (*CreditWheelRewardResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreditWheelReward 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 +1574,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.
|
||||
@ -2704,6 +2736,24 @@ func _WalletService_DebitCPBreakupFee_Handler(srv interface{}, ctx context.Conte
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_DebitWheelDraw_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DebitWheelDrawRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WalletServiceServer).DebitWheelDraw(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: WalletService_DebitWheelDraw_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WalletServiceServer).DebitWheelDraw(ctx, req.(*DebitWheelDrawRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_GrantVip_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GrantVipRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -2794,6 +2844,24 @@ func _WalletService_CreditLuckyGiftReward_Handler(srv interface{}, ctx context.C
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_CreditWheelReward_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreditWheelRewardRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WalletServiceServer).CreditWheelReward(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: WalletService_CreditWheelReward_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WalletServiceServer).CreditWheelReward(ctx, req.(*CreditWheelRewardRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_CreditRoomTurnoverReward_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreditRoomTurnoverRewardRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -3273,6 +3341,10 @@ var WalletService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "DebitCPBreakupFee",
|
||||
Handler: _WalletService_DebitCPBreakupFee_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DebitWheelDraw",
|
||||
Handler: _WalletService_DebitWheelDraw_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GrantVip",
|
||||
Handler: _WalletService_GrantVip_Handler,
|
||||
@ -3293,6 +3365,10 @@ var WalletService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "CreditLuckyGiftReward",
|
||||
Handler: _WalletService_CreditLuckyGiftReward_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreditWheelReward",
|
||||
Handler: _WalletService_CreditWheelReward_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreditRoomTurnoverReward",
|
||||
Handler: _WalletService_CreditRoomTurnoverReward_Handler,
|
||||
|
||||
@ -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
|
||||
|
||||
444
docs/通用抽奖引擎技术文档.md
Normal file
444
docs/通用抽奖引擎技术文档.md
Normal file
@ -0,0 +1,444 @@
|
||||
# 通用抽奖引擎技术文档
|
||||
|
||||
本文档描述当前服务端通用抽奖能力的代码结构、运行口径和转盘落地方式。抽奖通用能力目前由 `activity-service` 持有,钱包入账由 `wallet-service` 持有。幸运礼物已经复用通用权重选择;转盘新增独立配置、抽奖记录、RTP 统计、钱包 reason 和后台查询入口。
|
||||
|
||||
## 一、边界和结论
|
||||
|
||||
| 模块 | Owner | 当前职责 | 不做什么 | 代码位置 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 通用抽奖引擎 | `activity-service` | 候选归一化、权重随机、奖品类型归一化、RTP 计值归一化 | 不读取数据库、不判断资格、不改奖池、不发奖 | `services/activity-service/internal/domain/lotteryengine/engine.go` |
|
||||
| 幸运礼物 | `activity-service` | 继续拥有幸运礼物规则、奖池、RTP 窗口、风控、记录和 outbox;候选随机改为调用通用引擎 | 不改变原有幸运礼物 RTP 观察和不可支付过滤逻辑 | `services/activity-service/internal/storage/mysql/lucky_gift_repository.go` |
|
||||
| 转盘 | `activity-service` | 独立规则版本、奖档、奖池、RTP 窗口、抽奖记录、后台统计、金币快路径发奖 | 不复用幸运礼物表;不把道具/装扮价值计入 RTP | `services/activity-service/internal/domain/wheel`、`internal/service/wheel`、`internal/storage/mysql/wheel_repository.go` |
|
||||
| 钱包 reason | `wallet-service` | 新增 `wheel_reward` 入账 reason、交易、分录、钱包 outbox | 不判断转盘中奖资格,不计算 RTP | `services/wallet-service/internal/service/wallet/service.go`、`internal/storage/mysql/repository.go` |
|
||||
| Proto/gRPC | `api/proto` + transport | 暴露转盘抽奖和后台配置/记录/统计 RPC | 当前未新增 gateway HTTP 包装 | `api/proto/activity/v1/activity.proto`、`services/activity-service/internal/transport/grpc/wheel_server.go` |
|
||||
|
||||
核心原则:
|
||||
|
||||
1. 通用引擎只负责“从已过滤候选里按权重选中一个奖档”。
|
||||
2. 业务模块必须在调用引擎前完成资格、价格、奖池、风控和预算过滤。
|
||||
3. RTP 只使用 `rtp_value_coins` 作为分子;转盘道具和装扮无论配置价值多少,运行态都强制为 0。
|
||||
4. 金币发放必须走钱包独立 reason `wheel_reward`,不能混用 `lucky_gift_reward`。
|
||||
5. 转盘配置、记录和统计使用 `wheel_*` 表,不能写入幸运礼物表。
|
||||
|
||||
## 二、代码索引
|
||||
|
||||
### 2.1 通用抽奖引擎
|
||||
|
||||
| 文件 | 关键符号 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `services/activity-service/internal/domain/lotteryengine/engine.go` | `Candidate` | 引擎唯一输入视图:`ID`、`Weight`、`PrizeKind`、`RTPValueCoins` |
|
||||
| 同上 | `NormalizeCandidates` | 复制并清洗候选;负权重拒绝;全部权重为 0 时退化为等权随机 |
|
||||
| 同上 | `SelectWeighted` | 使用 `crypto/rand` 生成随机下标,按权重选择候选 |
|
||||
| 同上 | `NormalizePrizeKind` | 把 `coin/gift/prop/dress` 及同义值归一化 |
|
||||
| 同上 | `NormalizeRTPValueCoins` | 金币/礼物保留非负 RTP 价值;`prop/dress` 强制归零 |
|
||||
| `services/activity-service/internal/domain/lotteryengine/engine_test.go` | 单测 | 覆盖权重选择、全 0 权重兜底、道具/装扮 RTP 归零 |
|
||||
|
||||
### 2.2 转盘代码
|
||||
|
||||
| 文件 | 关键符号 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `services/activity-service/internal/domain/wheel/wheel.go` | `RuleConfig`、`Tier`、`DrawCommand`、`DrawResult`、`DrawSummary` | 转盘领域模型 |
|
||||
| `services/activity-service/internal/service/wheel/config.go` | `NormalizeRuleConfig`、`ValidateRuleConfig` | 后台配置发布前归一化和硬边界校验 |
|
||||
| `services/activity-service/internal/service/wheel/service.go` | `Service.Draw`、`UpsertConfig`、`GetConfig`、`ListDraws`、`GetDrawSummary` | 转盘用例入口 |
|
||||
| 同上 | `creditCoinRewardFastPath` | 金币奖品同步调用钱包 `CreditWheelReward`,成功后回写 draw、统计和 outbox |
|
||||
| `services/activity-service/internal/storage/mysql/wheel_repository.go` | `PublishWheelRuleConfig` | 发布不可变规则版本和奖档 |
|
||||
| 同上 | `ExecuteWheelDraw` | 转盘抽奖主事务:幂等、规则锁定、价格校验、RTP 窗口、奖池、记录、统计、outbox |
|
||||
| 同上 | `executeSingleWheelDraw` | 单次命中奖档、更新 RTP 窗口、写 draw record 和 outbox |
|
||||
| 同上 | `wheelPayableCandidates` | 按奖池容量和单次 RTP 上限过滤候选;道具/装扮 RTP 价值归零 |
|
||||
| 同上 | `ListWheelDraws`、`GetWheelDrawSummary` | 后台抽奖明细和汇总统计读取 |
|
||||
| 同上 | `MarkWheelDrawsGranted` | 金币发放成功后回写记录、统计和 `activity_outbox` |
|
||||
| `services/activity-service/internal/storage/mysql/wheel_schema.go` | `ensureWheelTables` | 运行时兜底创建 `wheel_*` 表 |
|
||||
| `services/activity-service/deploy/mysql/initdb/001_activity_service.sql` | `wheel_*` DDL | 新环境初始化表结构 |
|
||||
| `services/activity-service/internal/transport/grpc/wheel_server.go` | `WheelServer`、`AdminWheelServer` | 转盘 App 抽奖和后台配置/统计 gRPC |
|
||||
| `services/activity-service/internal/app/services.go` | `wheelservice.New` | activity-service 装配转盘 service |
|
||||
| `services/activity-service/internal/app/grpc_registration.go` | `RegisterWheelServiceServer`、`RegisterAdminWheelServiceServer` | 注册转盘 gRPC 服务 |
|
||||
|
||||
### 2.3 钱包代码
|
||||
|
||||
| 文件 | 关键符号 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `api/proto/wallet/v1/wallet.proto` | `CreditWheelRewardRequest`、`CreditWheelReward` | 钱包转盘金币奖品入账 RPC |
|
||||
| `services/wallet-service/internal/domain/ledger/ledger.go` | `WheelRewardCommand`、`WheelRewardReceipt` | 钱包 service/repository 间领域命令 |
|
||||
| `services/wallet-service/internal/service/wallet/service.go` | `CreditWheelReward` | 校验转盘金币奖品入账命令,固定钱包职责边界 |
|
||||
| `services/wallet-service/internal/storage/mysql/repository.go` | `bizTypeWheelReward`、`CreditWheelReward` | 交易、账户余额、分录和钱包 outbox 同事务提交 |
|
||||
| 同上 | `wheelRewardRequestHash` | 保证同一转盘 draw 幂等入账 |
|
||||
| `services/wallet-service/internal/transport/grpc/server.go` | `CreditWheelReward` | gRPC 请求转换为钱包领域命令 |
|
||||
|
||||
### 2.4 Proto 契约
|
||||
|
||||
| 文件 | RPC/Message | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `api/proto/activity/v1/activity.proto` | `WheelService.ExecuteWheelDraw` | 扣费后执行转盘抽奖 |
|
||||
| 同上 | `AdminWheelService.GetWheelConfig` | 后台读取当前转盘配置 |
|
||||
| 同上 | `AdminWheelService.UpsertWheelConfig` | 后台发布新规则版本 |
|
||||
| 同上 | `AdminWheelService.ListWheelDraws` | 后台查看抽奖明细 |
|
||||
| 同上 | `AdminWheelService.GetWheelDrawSummary` | 后台查看转盘统计汇总 |
|
||||
| 同上 | `WheelRuleConfig`、`WheelPrizeTier` | 转盘规则和奖档配置 |
|
||||
| 同上 | `WheelDrawMeta`、`WheelDrawResult`、`WheelDrawSummary` | 抽奖入参、结果和统计 |
|
||||
| `api/proto/wallet/v1/wallet.proto` | `CreditWheelRewardRequest`、`CreditWheelRewardResponse` | 转盘金币发放钱包契约 |
|
||||
|
||||
## 三、通用引擎模型
|
||||
|
||||
### 3.1 Candidate
|
||||
|
||||
`lotteryengine.Candidate` 是通用引擎唯一关心的数据:
|
||||
|
||||
| 字段 | 含义 | 规则 |
|
||||
| --- | --- | --- |
|
||||
| `ID` | 业务奖档 ID | 引擎只原样返回,业务侧负责保证唯一 |
|
||||
| `Weight` | 权重 | 负数拒绝;正数参与随机;全部为 0 时每个候选权重按 1 处理 |
|
||||
| `PrizeKind` | 奖品类型 | 归一化为 `coin/gift/prop/dress` 等标准值 |
|
||||
| `RTPValueCoins` | 计入 RTP 的金币价值 | 负数按 0;`prop/dress` 强制为 0 |
|
||||
|
||||
引擎不直接使用 `RewardCoins`、`RewardID`、库存、奖池余额、用户信息。这些都属于业务模块。
|
||||
|
||||
### 3.2 权重选择
|
||||
|
||||
流程:
|
||||
|
||||
1. 调用方传入已过滤候选。
|
||||
2. `NormalizeCandidates` 清洗权重、奖品类型和 RTP 价值。
|
||||
3. `SelectWeighted` 汇总权重。
|
||||
4. 用 `crypto/rand.Int` 生成 `[0,totalWeight)` 的随机数。
|
||||
5. 按权重区间返回命中的 `Candidate`。
|
||||
|
||||
设计原因:
|
||||
|
||||
| 设计 | 原因 |
|
||||
| --- | --- |
|
||||
| 使用 `crypto/rand` | 高价值奖品不能被时间种子或进程启动顺序预测 |
|
||||
| 全 0 权重兜底为等权 | 兼容旧配置或临时配置错误,避免整个活动不可抽 |
|
||||
| 负权重直接失败 | 负权重没有业务语义,继续运行会让概率不可解释 |
|
||||
| 不在引擎内做 RTP 修正 | RTP 修正依赖奖池、预算、用户风险和活动策略,必须留在业务层 |
|
||||
|
||||
## 四、转盘配置模型
|
||||
|
||||
### 4.1 RuleConfig
|
||||
|
||||
`domain/wheel.RuleConfig` 是一个不可变版本快照:
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `WheelID` | 转盘 ID,空值归一为 `default` |
|
||||
| `RuleVersion` | 不可变规则版本,每次发布 +1 |
|
||||
| `Enabled` | 是否启用 |
|
||||
| `DrawPriceCoins` | 单抽价格 |
|
||||
| `TargetRTPPPM` | RTP 目标,ppm |
|
||||
| `PoolRatePPM` | 每笔消耗进入转盘奖池比例,ppm |
|
||||
| `SettlementWindowDraws` | RTP 观察窗口抽数 |
|
||||
| `InitialPoolCoins` | 初始奖池水位 |
|
||||
| `PoolReserveCoins` | 奖池保底水位 |
|
||||
| `MaxSingleRTPPayout` | 单次可支付的 RTP 价值上限 |
|
||||
| `Tiers` | 奖档列表 |
|
||||
|
||||
### 4.2 Tier
|
||||
|
||||
| 字段 | 含义 | 特殊规则 |
|
||||
| --- | --- | --- |
|
||||
| `TierID` | 奖档 ID | 同一规则版本内必须唯一 |
|
||||
| `DisplayName` | 展示名称快照 | 只用于后台和前端展示 |
|
||||
| `RewardType` | `coin/gift/prop/dress` | 会调用通用引擎归一化 |
|
||||
| `RewardID` | 礼物、道具、装扮资源 ID | 非金币奖品必填 |
|
||||
| `RewardCount` | 奖励数量 | 小于等于 0 时归一为 1 |
|
||||
| `RewardCoins` | 金币奖励金额 | `coin` 使用 |
|
||||
| `RTPValueCoins` | 计入 RTP 的价值 | `prop/dress` 强制为 0 |
|
||||
| `WeightPPM` | 随机权重 | 当前作为权重值使用,不要求总和等于 1000000 |
|
||||
| `Enabled` | 是否启用 | 至少需要一个启用奖档 |
|
||||
| `MetadataJSON` | 展示和发放扩展快照 | 空值或非法 JSON 归一为 `{}` |
|
||||
|
||||
### 4.3 配置校验
|
||||
|
||||
入口:`services/activity-service/internal/service/wheel/config.go`
|
||||
|
||||
规则:
|
||||
|
||||
1. `draw_price_coins` 必须大于 0。
|
||||
2. `target_rtp_ppm`、`pool_rate_ppm` 不能为负。
|
||||
3. `settlement_window_draws` 必须大于 0。
|
||||
4. 奖档不能为空。
|
||||
5. `tier_id` 必须唯一。
|
||||
6. `weight_ppm` 不能为负。
|
||||
7. `coin` 奖档的 `reward_coins` 不能为负。
|
||||
8. `gift/prop/dress` 必须有 `reward_id`。
|
||||
9. `prop/dress` 的 `rtp_value_coins` 在归一化后必须为 0。
|
||||
10. 至少一个奖档启用。
|
||||
|
||||
## 五、转盘抽奖链路
|
||||
|
||||
### 5.1 调用前提
|
||||
|
||||
转盘抽奖 RPC 是扣费后的服务端事实入口:
|
||||
|
||||
| 阶段 | Owner | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 扣费 | 调用方 + wallet-service | 先扣用户金币,拿到真实 `coin_spent` 和 `paid_at_ms` |
|
||||
| 抽奖 | activity-service | 使用 `ExecuteWheelDraw` 固化中奖结果和 RTP |
|
||||
| 金币发放 | wallet-service | `coin` 奖品通过 `CreditWheelReward` 入账 |
|
||||
| 礼物/道具/装扮发放 | 对应资产 owner | 当前只固化 pending 记录和 outbox 事实,后续接资产发放接口 |
|
||||
|
||||
转盘 repository 会校验:
|
||||
|
||||
```text
|
||||
coin_spent == draw_price_coins * draw_count
|
||||
```
|
||||
|
||||
这样避免客户端或调用方伪造 RTP 分母。
|
||||
|
||||
### 5.2 主事务
|
||||
|
||||
入口:`Repository.ExecuteWheelDraw`
|
||||
|
||||
事务内顺序:
|
||||
|
||||
1. 归一化 `wheel_id` 和 `draw_count`。
|
||||
2. 按 `command_id` 收集已有 draw,完整存在则幂等返回。
|
||||
3. 如果只存在部分子抽,返回冲突,避免重复发奖。
|
||||
4. 锁定当前启用的转盘规则版本。
|
||||
5. 校验 `coin_spent` 与当前单价一致。
|
||||
6. 获取或创建 RTP 窗口。
|
||||
7. 获取或创建转盘奖池。
|
||||
8. 按 `draw_count` 拆分每次消耗。
|
||||
9. 每一抽调用 `executeSingleWheelDraw`。
|
||||
10. 汇总写回奖池净变化。
|
||||
11. 更新后台统计。
|
||||
12. 提交事务。
|
||||
|
||||
### 5.3 单抽
|
||||
|
||||
入口:`executeSingleWheelDraw`
|
||||
|
||||
单抽顺序:
|
||||
|
||||
1. `wheelPayableCandidates` 过滤可支付候选。
|
||||
2. 组装 `lotteryengine.Candidate`。
|
||||
3. 调用 `lotteryengine.SelectWeighted` 命中奖档。
|
||||
4. 用命中奖档的 `RTPValueCoins` 更新奖池和 RTP 窗口。
|
||||
5. 写入 `wheel_draw_records`。
|
||||
6. 如果奖品需要发放,写入 `activity_outbox`,事件类型为 `WheelRewardSettlement`。
|
||||
7. 返回 `DrawResult`。
|
||||
|
||||
候选过滤口径:
|
||||
|
||||
| 过滤项 | 说明 |
|
||||
| --- | --- |
|
||||
| `tier.Enabled` | 未启用奖档不参与 |
|
||||
| `RTPValueCoins` | `prop/dress` 强制为 0 |
|
||||
| 奖池容量 | `pool.balance - reserve_floor` |
|
||||
| 单次上限 | `max_single_rtp_payout` 大于 0 时限制容量 |
|
||||
|
||||
注意:道具/装扮 `RTPValueCoins=0`,所以不会因为展示价值占用奖池,也不会提高 RTP 分子。
|
||||
|
||||
### 5.4 批量抽奖
|
||||
|
||||
当前转盘支持 `draw_count`:
|
||||
|
||||
| 功能 | 代码 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 子命令 ID | `wheelSubCommandID` | 单抽使用原 command,多抽追加 `#000001` 这类后缀 |
|
||||
| 金额拆分 | 复用 `luckyDrawUnitSpend` | 总金额按次数拆分,余数给前几抽 |
|
||||
| 幂等聚合 | `collectWheelDrawsByCommand`、`aggregateWheelDrawResults` | 完整存在则聚合返回 |
|
||||
| 发放限制 | `creditCoinRewardFastPath` | 当前只对单抽金币做同步快路径,多抽保留 pending/outbox |
|
||||
|
||||
## 六、RTP 口径
|
||||
|
||||
### 6.1 分子和分母
|
||||
|
||||
| 项 | 字段 | 来源 |
|
||||
| --- | --- | --- |
|
||||
| RTP 分母 | `coin_spent` / `wager_coins` | 用户实际扣费金币 |
|
||||
| RTP 分子 | `rtp_value_coins` / `actual_rtp_value_coins` | 命中奖档计入 RTP 的价值 |
|
||||
| 目标值 | `target_rtp_ppm` | 后台规则配置 |
|
||||
| 当前值 | `actual_rtp_ppm` | `actual_rtp_value_coins * 1000000 / wager_coins` |
|
||||
|
||||
### 6.2 奖品类型口径
|
||||
|
||||
| 奖品类型 | 是否可配置 | 是否发放 | 是否计入 RTP |
|
||||
| --- | --- | --- | --- |
|
||||
| `coin` | 是 | 钱包 `wheel_reward` | 是,使用 `rtp_value_coins` |
|
||||
| `gift` | 是 | 待接礼物/资源 owner | 是,使用 `rtp_value_coins` |
|
||||
| `prop` | 是 | 待接道具 owner | 否,强制 0 |
|
||||
| `dress` | 是 | 待接装扮 owner | 否,强制 0 |
|
||||
|
||||
强制归零的位置:
|
||||
|
||||
| 层 | 代码 |
|
||||
| --- | --- |
|
||||
| 通用引擎 | `lotteryengine.NormalizeRTPValueCoins` |
|
||||
| 转盘配置 | `wheel.NormalizeRuleConfig` |
|
||||
| 转盘仓储 | `normalizeWheelTiers`、`wheelPayableCandidates` |
|
||||
| 转盘测试 | `services/activity-service/internal/service/wheel/config_test.go`、`domain/lotteryengine/engine_test.go` |
|
||||
|
||||
## 七、发奖和 outbox
|
||||
|
||||
### 7.1 金币奖品
|
||||
|
||||
金币奖品路径:
|
||||
|
||||
1. `ExecuteWheelDraw` 写入 `wheel_draw_records`,初始状态为 `pending`。
|
||||
2. `Service.Draw` 在事务提交后进入 `creditCoinRewardFastPath`。
|
||||
3. 调用 wallet-service `CreditWheelReward`。
|
||||
4. wallet-service 以 `biz_type=wheel_reward` 写交易、账户、分录和 wallet outbox。
|
||||
5. activity-service 调用 `MarkWheelDrawsGranted`。
|
||||
6. `MarkWheelDrawsGranted` 同事务更新:
|
||||
- `wheel_draw_records.reward_status = granted`
|
||||
- `wheel_draw_records.reward_transaction_id`
|
||||
- `wheel_draw_stats.pending_draws/granted_draws`
|
||||
- `activity_outbox.status = delivered`
|
||||
|
||||
钱包 reason:
|
||||
|
||||
| 项 | 值 |
|
||||
| --- | --- |
|
||||
| wallet biz type | `wheel_reward` |
|
||||
| RPC reason | `wheel_reward` |
|
||||
| command ID | `wheel_reward:<draw_id>` |
|
||||
| 钱包事件 | `WalletWheelRewardCredited` |
|
||||
|
||||
### 7.2 礼物/道具/装扮奖品
|
||||
|
||||
当前状态:
|
||||
|
||||
1. 抽奖结果会落 `wheel_draw_records`。
|
||||
2. `reward_status` 为 `pending`。
|
||||
3. `activity_outbox` 会写 `WheelRewardSettlement`。
|
||||
4. 具体发放 worker 和资产 owner RPC 还没有接入。
|
||||
|
||||
后续接入时必须遵守:
|
||||
|
||||
1. 不允许在 activity-service 直接改钱包或资产表。
|
||||
2. 发放成功后调用转盘仓储状态回写方法,保持 draw record、统计和 outbox 一致。
|
||||
3. 道具/装扮发放成功也不能把展示价值写入 RTP。
|
||||
4. 礼物如果要计入 RTP,必须使用抽奖时固化的 `rtp_value_coins`,不能按发放时礼物价格重新估值。
|
||||
|
||||
## 八、后台记录和统计
|
||||
|
||||
### 8.1 明细
|
||||
|
||||
入口:`AdminWheelService.ListWheelDraws`
|
||||
|
||||
仓储:`Repository.ListWheelDraws`
|
||||
|
||||
支持筛选:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `wheel_id` | 转盘 ID |
|
||||
| `user_id` | 用户 ID |
|
||||
| `status` | `pending/granted/failed` |
|
||||
| `page/page_size` | 分页,`page_size` 最大 100 |
|
||||
|
||||
返回字段包括:
|
||||
|
||||
`draw_id`、`command_id`、`wheel_id`、`rule_version`、`selected_tier_id`、`reward_type`、`reward_id`、`reward_count`、`reward_coins`、`rtp_value_coins`、`reward_status`、`wallet_transaction_id`、`rtp_window_index`、`metadata_json`。
|
||||
|
||||
### 8.2 汇总
|
||||
|
||||
入口:`AdminWheelService.GetWheelDrawSummary`
|
||||
|
||||
仓储:`Repository.GetWheelDrawSummary`
|
||||
|
||||
统计字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `total_draws` | 抽奖次数 |
|
||||
| `unique_users` | 去重用户数 |
|
||||
| `total_spent_coins` | 总消耗金币 |
|
||||
| `total_rtp_value_coins` | 计入 RTP 的返奖价值 |
|
||||
| `actual_rtp_ppm` | 实际 RTP |
|
||||
| `pending_draws` | 待发放 |
|
||||
| `granted_draws` | 已发放 |
|
||||
| `failed_draws` | 失败 |
|
||||
|
||||
当只按 `wheel_id` 汇总时,优先读 `wheel_draw_stats`;带 `user_id/status` 过滤时直接聚合 `wheel_draw_records`。
|
||||
|
||||
## 九、数据表
|
||||
|
||||
| 表 | 用途 | 代码 |
|
||||
| --- | --- | --- |
|
||||
| `wheel_rule_versions` | 转盘不可变规则版本 | `wheel_schema.go`、`001_activity_service.sql` |
|
||||
| `wheel_prize_tiers` | 每个规则版本的奖档快照 | 同上 |
|
||||
| `wheel_rtp_windows` | RTP 观察窗口 | `getOpenWheelRTPWindow`、`createWheelRTPWindow` |
|
||||
| `wheel_pools` | 转盘奖池水位 | `getOrCreateWheelPool`、`persistWheelPoolDelta` |
|
||||
| `wheel_draw_records` | 抽奖事实明细 | `executeSingleWheelDraw`、`ListWheelDraws` |
|
||||
| `wheel_draw_stats` | 后台汇总统计 | `updateWheelStats`、`GetWheelDrawSummary` |
|
||||
| `wheel_draw_stat_users` | 统计去重用户 | `updateWheelStats` |
|
||||
| `activity_outbox` | 转盘发奖补偿事实 | `insertWheelRewardOutbox`、`MarkWheelDrawsGranted` |
|
||||
| `wallet_transactions` | 钱包交易 | `wallet-service/internal/storage/mysql.Repository.CreditWheelReward` |
|
||||
| `wallet_outbox` | 钱包余额和奖励事实 | 同上 |
|
||||
|
||||
## 十、和幸运礼物的关系
|
||||
|
||||
幸运礼物不是直接迁移成转盘,也不是把转盘塞进幸运礼物:
|
||||
|
||||
| 项 | 幸运礼物 | 转盘 |
|
||||
| --- | --- | --- |
|
||||
| 规则维度 | `pool_id`,房间送礼场景 | `wheel_id`,H5/活动转盘场景 |
|
||||
| 奖品 | 金币返奖 | 金币、礼物、道具、装扮 |
|
||||
| RTP 口径 | 原幸运礼物基础返奖口径 | `rtp_value_coins`,道具/装扮强制 0 |
|
||||
| 记录表 | `lucky_draw_records` | `wheel_draw_records` |
|
||||
| 钱包 reason | `lucky_gift_reward` | `wheel_reward` |
|
||||
| 通用引擎使用 | 候选随机复用 `lotteryengine.SelectWeighted` | 候选随机和 RTP 归一化都复用 |
|
||||
|
||||
幸运礼物保留自己的奖池、风控、用户阶段和 room IM 逻辑。通用引擎只替换了“已过滤候选里的权重随机”这一小段,避免改动原业务行为。
|
||||
|
||||
## 十一、扩展新抽奖活动的步骤
|
||||
|
||||
新增一个抽奖活动时,不要复制幸运礼物或转盘整套逻辑。按下面顺序接入:
|
||||
|
||||
1. 新建独立 domain,定义自己的 `RuleConfig`、`Tier`、`DrawCommand`、`DrawResult`。
|
||||
2. 新建 service,负责入参归一化、配置校验和跨服务调用。
|
||||
3. 新建 storage,负责规则版本、奖池、RTP 窗口、记录、统计和 outbox。
|
||||
4. 业务层先过滤资格、预算、库存、奖池和风控。
|
||||
5. 把过滤后的候选转换成 `lotteryengine.Candidate`。
|
||||
6. 调用 `lotteryengine.SelectWeighted`。
|
||||
7. 用返回候选固化抽奖结果。
|
||||
8. 如果有金币奖品,在 wallet-service 增加独立 reason,不复用已有 reason。
|
||||
9. 如果有非金币奖品,接对应 owner service 的发放接口。
|
||||
10. 补 proto、gRPC、表结构、initdb 和测试。
|
||||
|
||||
必须明确回答的问题:
|
||||
|
||||
| 问题 | 必须落地的位置 |
|
||||
| --- | --- |
|
||||
| 奖品有哪些类型 | domain `Tier.RewardType` 和 proto |
|
||||
| 哪些奖品计入 RTP | `RTPValueCoins` 归一化 |
|
||||
| 哪个服务发奖 | service 跨服务依赖 |
|
||||
| 钱包 reason 是什么 | wallet-service domain/service/storage/proto |
|
||||
| 如何幂等 | command ID、draw ID、钱包 request hash |
|
||||
| 后台查什么 | draw records 和 summary |
|
||||
| 失败如何补偿 | activity outbox 或 owner outbox |
|
||||
|
||||
## 十二、验证命令
|
||||
|
||||
当前相关验证命令:
|
||||
|
||||
```bash
|
||||
PATH=/Users/hy/go/bin:$PATH make proto
|
||||
go test ./services/activity-service/internal/domain/lotteryengine
|
||||
go test ./services/activity-service/internal/service/wheel
|
||||
go test ./services/activity-service/internal/storage/mysql
|
||||
go test ./services/activity-service/internal/transport/grpc
|
||||
go test ./services/activity-service/internal/app
|
||||
go test ./services/wallet-service/internal/service/wallet ./services/wallet-service/internal/storage/mysql ./services/wallet-service/internal/transport/grpc
|
||||
go test ./services/activity-service/...
|
||||
```
|
||||
|
||||
已知当前仓库全量 `make test` 仍会失败在既有 MifaPay 配置测试:
|
||||
|
||||
```text
|
||||
services/wallet-service/internal/config.TestLoadMifaPayMerchantConfig
|
||||
mifapay merchant identity mismatch in ../../configs/config.docker.yaml
|
||||
```
|
||||
|
||||
该失败与通用抽奖和转盘改动无关。
|
||||
|
||||
## 十三、当前未完成事项
|
||||
|
||||
| 事项 | 原因 | 后续接入位置 |
|
||||
| --- | --- | --- |
|
||||
| 礼物奖品真实发放 | 需要确认礼物/资源 owner 的发放接口和背包表现 | activity-service 转盘 outbox worker + 对应 owner RPC |
|
||||
| 道具/装扮真实发放 | 需要确认装扮资源 owner、有效期和背包协议 | activity-service 转盘 outbox worker + resource/wallet owner |
|
||||
| Gateway HTTP/H5 接口 | 当前只到 activity gRPC;H5 页面还需要 gateway 包装 | `services/gateway-service/internal/transport/http/activityapi` |
|
||||
| 后台管理页面 | 当前只有 gRPC 后台能力,未接 admin web 模块 | `server/admin` |
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -70,6 +70,7 @@ import (
|
||||
userleaderboardmodule "hyapp-admin-server/internal/modules/userleaderboard"
|
||||
vipconfigmodule "hyapp-admin-server/internal/modules/vipconfig"
|
||||
weeklystarmodule "hyapp-admin-server/internal/modules/weeklystar"
|
||||
wheelmodule "hyapp-admin-server/internal/modules/wheel"
|
||||
"hyapp-admin-server/internal/platform/logging"
|
||||
"hyapp-admin-server/internal/platform/tencentcos"
|
||||
"hyapp-admin-server/internal/repository"
|
||||
@ -272,6 +273,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 +293,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),
|
||||
@ -302,6 +304,7 @@ func main() {
|
||||
UserLeaderboard: userleaderboardmodule.New(walletDB, userDB, roomClient),
|
||||
VIPConfig: vipconfigmodule.New(walletclient.NewGRPC(walletConn), auditHandler),
|
||||
WeeklyStar: weeklystarmodule.New(activityclient.NewGRPC(activityConn), auditHandler),
|
||||
Wheel: wheelmodule.New(activityclient.NewGRPC(activityConn), cfg.ActivityService.RequestTimeout, auditHandler),
|
||||
}
|
||||
engine := router.New(cfg, auth, handlers)
|
||||
|
||||
|
||||
@ -48,6 +48,7 @@ type Client interface {
|
||||
UpdateAgencyOpeningCycle(ctx context.Context, req *activityv1.UpsertAgencyOpeningCycleRequest) (*activityv1.UpsertAgencyOpeningCycleResponse, error)
|
||||
SetAgencyOpeningCycleStatus(ctx context.Context, req *activityv1.SetAgencyOpeningCycleStatusRequest) (*activityv1.SetAgencyOpeningCycleStatusResponse, error)
|
||||
ListAgencyOpeningApplications(ctx context.Context, req *activityv1.ListAgencyOpeningApplicationsRequest) (*activityv1.ListAgencyOpeningApplicationsResponse, error)
|
||||
ReviewAgencyOpeningApplication(ctx context.Context, req *activityv1.ReviewAgencyOpeningApplicationRequest) (*activityv1.ReviewAgencyOpeningApplicationResponse, error)
|
||||
GetCPWeeklyRankConfig(ctx context.Context, req *activityv1.GetCPWeeklyRankConfigRequest) (*activityv1.GetCPWeeklyRankConfigResponse, error)
|
||||
UpdateCPWeeklyRankConfig(ctx context.Context, req *activityv1.UpdateCPWeeklyRankConfigRequest) (*activityv1.UpdateCPWeeklyRankConfigResponse, error)
|
||||
ListCPWeeklyRankSettlements(ctx context.Context, req *activityv1.ListCPWeeklyRankSettlementsRequest) (*activityv1.ListCPWeeklyRankSettlementsResponse, error)
|
||||
@ -56,11 +57,16 @@ type Client interface {
|
||||
ListLuckyGiftConfigs(ctx context.Context, req *activityv1.ListLuckyGiftConfigsRequest) (*activityv1.ListLuckyGiftConfigsResponse, error)
|
||||
ListLuckyGiftDraws(ctx context.Context, req *activityv1.ListLuckyGiftDrawsRequest) (*activityv1.ListLuckyGiftDrawsResponse, error)
|
||||
GetLuckyGiftDrawSummary(ctx context.Context, req *activityv1.GetLuckyGiftDrawSummaryRequest) (*activityv1.GetLuckyGiftDrawSummaryResponse, error)
|
||||
GetWheelConfig(ctx context.Context, req *activityv1.GetWheelConfigRequest) (*activityv1.GetWheelConfigResponse, error)
|
||||
UpsertWheelConfig(ctx context.Context, req *activityv1.UpsertWheelConfigRequest) (*activityv1.UpsertWheelConfigResponse, error)
|
||||
ListWheelDraws(ctx context.Context, req *activityv1.ListWheelDrawsRequest) (*activityv1.ListWheelDrawsResponse, error)
|
||||
GetWheelDrawSummary(ctx context.Context, req *activityv1.GetWheelDrawSummaryRequest) (*activityv1.GetWheelDrawSummaryResponse, error)
|
||||
RemoveRegionBroadcastMember(ctx context.Context, req *activityv1.RemoveRegionBroadcastMemberRequest) (*activityv1.RemoveRegionBroadcastMemberResponse, error)
|
||||
ListLevelConfig(ctx context.Context, req *activityv1.ListLevelConfigRequest) (*activityv1.ListLevelConfigResponse, error)
|
||||
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)
|
||||
}
|
||||
@ -78,7 +84,9 @@ type GRPCClient struct {
|
||||
agencyOpeningClient activityv1.AdminAgencyOpeningServiceClient
|
||||
cpWeeklyRankClient activityv1.AdminCPWeeklyRankServiceClient
|
||||
luckyGiftClient activityv1.AdminLuckyGiftServiceClient
|
||||
wheelClient activityv1.AdminWheelServiceClient
|
||||
broadcastClient activityv1.BroadcastServiceClient
|
||||
levelClient activityv1.GrowthLevelServiceClient
|
||||
growthClient activityv1.AdminGrowthLevelServiceClient
|
||||
messageClient activityv1.MessageInboxServiceClient
|
||||
}
|
||||
@ -97,7 +105,9 @@ func NewGRPC(conn grpc.ClientConnInterface) *GRPCClient {
|
||||
agencyOpeningClient: activityv1.NewAdminAgencyOpeningServiceClient(conn),
|
||||
cpWeeklyRankClient: activityv1.NewAdminCPWeeklyRankServiceClient(conn),
|
||||
luckyGiftClient: activityv1.NewAdminLuckyGiftServiceClient(conn),
|
||||
wheelClient: activityv1.NewAdminWheelServiceClient(conn),
|
||||
broadcastClient: activityv1.NewBroadcastServiceClient(conn),
|
||||
levelClient: activityv1.NewGrowthLevelServiceClient(conn),
|
||||
growthClient: activityv1.NewAdminGrowthLevelServiceClient(conn),
|
||||
messageClient: activityv1.NewMessageInboxServiceClient(conn),
|
||||
}
|
||||
@ -255,6 +265,10 @@ func (c *GRPCClient) ListAgencyOpeningApplications(ctx context.Context, req *act
|
||||
return c.agencyOpeningClient.ListAgencyOpeningApplications(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) ReviewAgencyOpeningApplication(ctx context.Context, req *activityv1.ReviewAgencyOpeningApplicationRequest) (*activityv1.ReviewAgencyOpeningApplicationResponse, error) {
|
||||
return c.agencyOpeningClient.ReviewAgencyOpeningApplication(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) GetCPWeeklyRankConfig(ctx context.Context, req *activityv1.GetCPWeeklyRankConfigRequest) (*activityv1.GetCPWeeklyRankConfigResponse, error) {
|
||||
return c.cpWeeklyRankClient.GetCPWeeklyRankConfig(ctx, req)
|
||||
}
|
||||
@ -287,6 +301,22 @@ func (c *GRPCClient) GetLuckyGiftDrawSummary(ctx context.Context, req *activityv
|
||||
return c.luckyGiftClient.GetLuckyGiftDrawSummary(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) GetWheelConfig(ctx context.Context, req *activityv1.GetWheelConfigRequest) (*activityv1.GetWheelConfigResponse, error) {
|
||||
return c.wheelClient.GetWheelConfig(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) UpsertWheelConfig(ctx context.Context, req *activityv1.UpsertWheelConfigRequest) (*activityv1.UpsertWheelConfigResponse, error) {
|
||||
return c.wheelClient.UpsertWheelConfig(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) ListWheelDraws(ctx context.Context, req *activityv1.ListWheelDrawsRequest) (*activityv1.ListWheelDrawsResponse, error) {
|
||||
return c.wheelClient.ListWheelDraws(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) GetWheelDrawSummary(ctx context.Context, req *activityv1.GetWheelDrawSummaryRequest) (*activityv1.GetWheelDrawSummaryResponse, error) {
|
||||
return c.wheelClient.GetWheelDrawSummary(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) RemoveRegionBroadcastMember(ctx context.Context, req *activityv1.RemoveRegionBroadcastMemberRequest) (*activityv1.RemoveRegionBroadcastMemberResponse, error) {
|
||||
return c.broadcastClient.RemoveRegionBroadcastMember(ctx, req)
|
||||
}
|
||||
@ -307,6 +337,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)
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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"`
|
||||
|
||||
@ -81,6 +81,10 @@ type applicationDTO struct {
|
||||
WalletTransactionID string `json:"wallet_transaction_id"`
|
||||
FailureReason string `json:"failure_reason"`
|
||||
AppliedAtMS int64 `json:"applied_at_ms"`
|
||||
ApprovedAtMS int64 `json:"approved_at_ms"`
|
||||
ScoreStartMS int64 `json:"score_start_ms"`
|
||||
ScoreEndMS int64 `json:"score_end_ms"`
|
||||
ReviewedByAdminID int64 `json:"reviewed_by_admin_id"`
|
||||
GrantedAtMS int64 `json:"granted_at_ms"`
|
||||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||||
}
|
||||
@ -201,6 +205,23 @@ func (h *Handler) ListApplications(c *gin.Context) {
|
||||
response.OK(c, response.Page{Items: items, Page: options.Page, PageSize: options.PageSize, Total: resp.GetTotal()})
|
||||
}
|
||||
|
||||
func (h *Handler) ApproveApplication(c *gin.Context) {
|
||||
applicationID := strings.TrimSpace(c.Param("application_id"))
|
||||
resp, err := h.activity.ReviewAgencyOpeningApplication(c.Request.Context(), &activityv1.ReviewAgencyOpeningApplicationRequest{
|
||||
Meta: h.meta(c),
|
||||
ApplicationId: applicationID,
|
||||
Action: "approve",
|
||||
OperatorAdminId: int64(middleware.CurrentUserID(c)),
|
||||
})
|
||||
if err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
item := applicationFromProto(resp.GetApplication())
|
||||
shared.OperationLogWithResourceID(c, h.audit, "approve-agency-opening-application", "agency_opening_applications", item.ApplicationID, "success", "")
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) meta(c *gin.Context) *activityv1.RequestMeta {
|
||||
return &activityv1.RequestMeta{
|
||||
RequestId: middleware.CurrentRequestID(c),
|
||||
@ -288,6 +309,10 @@ func applicationFromProto(item *activityv1.AgencyOpeningApplication) application
|
||||
WalletTransactionID: item.GetWalletTransactionId(),
|
||||
FailureReason: item.GetFailureReason(),
|
||||
AppliedAtMS: item.GetAppliedAtMs(),
|
||||
ApprovedAtMS: item.GetApprovedAtMs(),
|
||||
ScoreStartMS: item.GetScoreStartMs(),
|
||||
ScoreEndMS: item.GetScoreEndMs(),
|
||||
ReviewedByAdminID: item.GetReviewedByAdminId(),
|
||||
GrantedAtMS: item.GetGrantedAtMs(),
|
||||
UpdatedAtMS: item.GetUpdatedAtMs(),
|
||||
}
|
||||
|
||||
102
server/admin/internal/modules/agencyopening/handler_test.go
Normal file
102
server/admin/internal/modules/agencyopening/handler_test.go
Normal file
@ -0,0 +1,102 @@
|
||||
package agencyopening
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"hyapp-admin-server/internal/appctx"
|
||||
"hyapp-admin-server/internal/integration/activityclient"
|
||||
"hyapp-admin-server/internal/middleware"
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestApproveApplicationForwardsReviewRequest(t *testing.T) {
|
||||
activity := &fakeAgencyOpeningActivityClient{}
|
||||
router := newAgencyOpeningHandlerTestRouter(New(activity, nil))
|
||||
request := httptest.NewRequest(http.MethodPost, "/admin/activity/agency-opening/applications/application-1/approve", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if activity.lastReview == nil ||
|
||||
activity.lastReview.GetApplicationId() != "application-1" ||
|
||||
activity.lastReview.GetAction() != "approve" ||
|
||||
activity.lastReview.GetOperatorAdminId() != 7 ||
|
||||
activity.lastReview.GetMeta().GetAppCode() != "lalu" ||
|
||||
activity.lastReview.GetMeta().GetCaller() != "admin-server" {
|
||||
t.Fatalf("review request mismatch: %+v", activity.lastReview)
|
||||
}
|
||||
|
||||
var envelope struct {
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
ApplicationID string `json:"application_id"`
|
||||
Status string `json:"status"`
|
||||
ApprovedAtMS int64 `json:"approved_at_ms"`
|
||||
ScoreStartMS int64 `json:"score_start_ms"`
|
||||
ScoreEndMS int64 `json:"score_end_ms"`
|
||||
ReviewedByAdminID int64 `json:"reviewed_by_admin_id"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(recorder.Body.Bytes(), &envelope); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if envelope.Code != 0 ||
|
||||
envelope.Data.ApplicationID != "application-1" ||
|
||||
envelope.Data.Status != "approved" ||
|
||||
envelope.Data.ApprovedAtMS != 2000 ||
|
||||
envelope.Data.ScoreStartMS != 2000 ||
|
||||
envelope.Data.ScoreEndMS != 2000+24*60*60*1000 ||
|
||||
envelope.Data.ReviewedByAdminID != 7 {
|
||||
t.Fatalf("approve response mismatch: %+v", envelope)
|
||||
}
|
||||
}
|
||||
|
||||
func newAgencyOpeningHandlerTestRouter(handler *Handler) *gin.Engine {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
router.Use(func(c *gin.Context) {
|
||||
// 这里模拟后台鉴权中间件已经把 app_code、request_id 和操作者写入上下文,测试只关注接口参数透传。
|
||||
c.Request = c.Request.WithContext(appctx.WithContext(c.Request.Context(), "lalu"))
|
||||
c.Set(middleware.ContextRequestID, "agency-opening-handler-test")
|
||||
c.Set(middleware.ContextUserID, uint(7))
|
||||
c.Set(middleware.ContextUsername, "tester")
|
||||
c.Next()
|
||||
})
|
||||
router.POST("/admin/activity/agency-opening/applications/:application_id/approve", handler.ApproveApplication)
|
||||
return router
|
||||
}
|
||||
|
||||
type fakeAgencyOpeningActivityClient struct {
|
||||
activityclient.Client
|
||||
|
||||
lastReview *activityv1.ReviewAgencyOpeningApplicationRequest
|
||||
}
|
||||
|
||||
func (f *fakeAgencyOpeningActivityClient) ReviewAgencyOpeningApplication(_ context.Context, req *activityv1.ReviewAgencyOpeningApplicationRequest) (*activityv1.ReviewAgencyOpeningApplicationResponse, error) {
|
||||
f.lastReview = req
|
||||
return &activityv1.ReviewAgencyOpeningApplicationResponse{
|
||||
Application: &activityv1.AgencyOpeningApplication{
|
||||
ApplicationId: req.GetApplicationId(),
|
||||
CycleId: "cycle-1",
|
||||
AgencyId: 8001,
|
||||
AgencyOwnerUserId: 42001,
|
||||
AgencyName: "Window Agency",
|
||||
HostCount: 12,
|
||||
Status: "approved",
|
||||
AppliedAtMs: 1000,
|
||||
ApprovedAtMs: 2000,
|
||||
ScoreStartMs: 2000,
|
||||
ScoreEndMs: 2000 + int64((24 * 60 * 60 * 1000)),
|
||||
ReviewedByAdminId: req.GetOperatorAdminId(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@ -16,4 +16,5 @@ func RegisterRoutes(protected *gin.RouterGroup, h *Handler) {
|
||||
protected.PUT("/admin/activity/agency-opening/cycles/:cycle_id", middleware.RequirePermission("agency-opening:update"), h.UpdateCycle)
|
||||
protected.PATCH("/admin/activity/agency-opening/cycles/:cycle_id/status", middleware.RequirePermission("agency-opening:update"), h.SetCycleStatus)
|
||||
protected.GET("/admin/activity/agency-opening/applications", middleware.RequirePermission("agency-opening:view"), h.ListApplications)
|
||||
protected.POST("/admin/activity/agency-opening/applications/:application_id/approve", middleware.RequirePermission("agency-opening:update"), h.ApproveApplication)
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
188
server/admin/internal/modules/gamemanagement/robot_appearance.go
Normal file
188
server/admin/internal/modules/gamemanagement/robot_appearance.go
Normal file
@ -0,0 +1,188 @@
|
||||
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,
|
||||
})
|
||||
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" {
|
||||
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,
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
|
||||
@ -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,53 @@ func (c *fakeRobotGameClient) RegisterDiceRobots(_ context.Context, req *gamev1.
|
||||
return &gamev1.RegisterDiceRobotsResponse{Robots: robots}, nil
|
||||
}
|
||||
|
||||
type fakeRobotWalletClient struct {
|
||||
walletclient.Client
|
||||
listRequests []*walletv1.ListResourcesRequest
|
||||
grants []string
|
||||
equips []int64
|
||||
}
|
||||
|
||||
func (c *fakeRobotWalletClient) ListResources(_ context.Context, req *walletv1.ListResourcesRequest) (*walletv1.ListResourcesResponse, error) {
|
||||
c.listRequests = append(c.listRequests, req)
|
||||
switch req.GetResourceType() {
|
||||
case "avatar_frame":
|
||||
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{{ResourceId: 101, ResourceType: "avatar_frame", Status: "active", ManagerGrantEnabled: false}}}, nil
|
||||
case "vehicle":
|
||||
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{{ResourceId: 201, ResourceType: "vehicle", Status: "active", ManagerGrantEnabled: false}}}, nil
|
||||
case "badge":
|
||||
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{
|
||||
{ResourceId: 301, ResourceType: "badge", Status: "active", ManagerGrantEnabled: false, MetadataJson: `{"badge_form":"strip"}`},
|
||||
{ResourceId: 302, ResourceType: "badge", Status: "active", ManagerGrantEnabled: false, 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 +118,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 +157,29 @@ 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 _, req := range wallets.listRequests {
|
||||
if req.GetManagerGrantOnly() {
|
||||
t.Fatalf("robot appearance resource list must not require manager grant: %+v", req)
|
||||
}
|
||||
if !req.GetActiveOnly() {
|
||||
t.Fatalf("robot appearance resource list must still require active resources: %+v", req)
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
||||
@ -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,
|
||||
})
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
package roomadmin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type listQuery struct {
|
||||
Page int
|
||||
PageSize int
|
||||
@ -26,20 +33,81 @@ type robotRoomListQuery struct {
|
||||
}
|
||||
|
||||
type createRobotRoomRequest struct {
|
||||
OwnerRobotUserID int64 `json:"ownerRobotUserId"`
|
||||
CandidateRobotUserIDs []int64 `json:"candidateRobotUserIds"`
|
||||
MinRobotCount int32 `json:"minRobotCount"`
|
||||
MaxRobotCount int32 `json:"maxRobotCount"`
|
||||
RoomName string `json:"roomName"`
|
||||
RoomAvatar string `json:"roomAvatar"`
|
||||
VisibleRegionID int64 `json:"visibleRegionId"`
|
||||
GiftIDs []string `json:"giftIds"`
|
||||
LuckyGiftIDs []string `json:"luckyGiftIds"`
|
||||
NormalGiftIntervalMS int64 `json:"normalGiftIntervalMs"`
|
||||
LuckyComboMin int64 `json:"luckyComboMin"`
|
||||
LuckyComboMax int64 `json:"luckyComboMax"`
|
||||
LuckyPauseMinMS int64 `json:"luckyPauseMinMs"`
|
||||
LuckyPauseMaxMS int64 `json:"luckyPauseMaxMs"`
|
||||
OwnerRobotUserID flexibleJSONInt64 `json:"ownerRobotUserId"`
|
||||
CandidateRobotUserIDs flexibleJSONInt64Slice `json:"candidateRobotUserIds"`
|
||||
MinRobotCount int32 `json:"minRobotCount"`
|
||||
MaxRobotCount int32 `json:"maxRobotCount"`
|
||||
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"`
|
||||
LuckyComboMin int64 `json:"luckyComboMin"`
|
||||
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
|
||||
|
||||
type flexibleJSONInt64Slice []int64
|
||||
|
||||
func (v *flexibleJSONInt64) UnmarshalJSON(data []byte) error {
|
||||
// 机器人用户 ID 来自 int64,前端必须按字符串提交才能避开 JS 安全整数上限;这里同时兼容旧脚本传数字。
|
||||
value, err := parseFlexibleJSONInt64(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = flexibleJSONInt64(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (values *flexibleJSONInt64Slice) UnmarshalJSON(data []byte) error {
|
||||
// JSON 数组逐项走同一套 int64 解析,避免候选机器人列表里混入浮点或科学计数法。
|
||||
var raw []json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
out := make([]int64, 0, len(raw))
|
||||
for _, item := range raw {
|
||||
value, err := parseFlexibleJSONInt64(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, value)
|
||||
}
|
||||
*values = out
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseFlexibleJSONInt64(data []byte) (int64, error) {
|
||||
raw := strings.TrimSpace(string(data))
|
||||
if raw == "" || raw == "null" {
|
||||
return 0, nil
|
||||
}
|
||||
if strings.HasPrefix(raw, "\"") {
|
||||
var text string
|
||||
if err := json.Unmarshal(data, &text); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
raw = strings.TrimSpace(text)
|
||||
}
|
||||
if raw == "" {
|
||||
return 0, nil
|
||||
}
|
||||
if strings.ContainsAny(raw, ".eE") {
|
||||
// ID 没有小数语义,拒绝 float/scientific notation,避免 18 位 ID 被中间层改写精度。
|
||||
return 0, fmt.Errorf("integer id must not be decimal")
|
||||
}
|
||||
return strconv.ParseInt(raw, 10, 64)
|
||||
}
|
||||
|
||||
type createRoomPinRequest struct {
|
||||
@ -65,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
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ import (
|
||||
"hyapp-admin-server/internal/modules/shared"
|
||||
)
|
||||
|
||||
const availableRoomRobotPageSize = int32(200)
|
||||
|
||||
type RobotRoom struct {
|
||||
AppCode string `json:"appCode"`
|
||||
RoomID string `json:"roomId"`
|
||||
@ -24,6 +26,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 +42,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 +58,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")
|
||||
@ -87,15 +123,12 @@ func (s *Service) ListAvailableRoomRobots(ctx context.Context) ([]AvailableRoomR
|
||||
if s.robotClient == nil || s.roomClient == nil {
|
||||
return nil, fmt.Errorf("robot or room service client is not configured")
|
||||
}
|
||||
result, err := s.robotClient.ListGameRobots(ctx, robotclient.ListGameRobotsRequest{
|
||||
Status: "active",
|
||||
PageSize: 200,
|
||||
})
|
||||
robots, err := listAllActiveGameRobots(ctx, s.robotClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userIDs := make([]int64, 0, len(result.Robots))
|
||||
for _, item := range result.Robots {
|
||||
userIDs := make([]int64, 0, len(robots))
|
||||
for _, item := range robots {
|
||||
if item.UserID > 0 {
|
||||
userIDs = append(userIDs, item.UserID)
|
||||
}
|
||||
@ -110,7 +143,85 @@ func (s *Service) ListAvailableRoomRobots(ctx context.Context) ([]AvailableRoomR
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return availableRoomRobotsFromGamePool(result.Robots, available.AvailableUserIDs, owners), nil
|
||||
return availableRoomRobotsFromGamePool(robots, available.AvailableUserIDs, owners), nil
|
||||
}
|
||||
|
||||
func listAllActiveGameRobots(ctx context.Context, client robotclient.Client) ([]robotclient.Robot, error) {
|
||||
if client == nil {
|
||||
return nil, fmt.Errorf("robot service client is not configured")
|
||||
}
|
||||
cursor := ""
|
||||
seenCursors := make(map[string]bool)
|
||||
robots := make([]robotclient.Robot, 0, availableRoomRobotPageSize)
|
||||
for {
|
||||
// 机器人房间下拉要先拿到完整全站 active 机器人池,再统一交给 room-service 做占用过滤;
|
||||
// 只取第一页会在测试服机器人数量超过 200 或第一页大多已占用时,把后续地区的新机器人挡在下拉外。
|
||||
result, err := client.ListGameRobots(ctx, robotclient.ListGameRobotsRequest{
|
||||
Status: "active",
|
||||
PageSize: availableRoomRobotPageSize,
|
||||
Cursor: cursor,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
robots = append(robots, result.Robots...)
|
||||
next := strings.TrimSpace(result.NextCursor)
|
||||
if next == "" {
|
||||
return robots, nil
|
||||
}
|
||||
if seenCursors[next] {
|
||||
return nil, fmt.Errorf("robot service returned repeated cursor %q", next)
|
||||
}
|
||||
seenCursors[next] = true
|
||||
cursor = next
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -135,6 +246,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")
|
||||
@ -148,13 +303,15 @@ func (s *Service) CreateRobotRoom(ctx context.Context, req createRobotRoomReques
|
||||
return RobotRoom{}, err
|
||||
}
|
||||
created, err := s.roomClient.CreateRobotRoom(ctx, roomclient.CreateRobotRoomRequest{
|
||||
OwnerRobotUserID: req.OwnerRobotUserID,
|
||||
CandidateRobotUserIDs: req.CandidateRobotUserIDs,
|
||||
OwnerRobotUserID: int64(req.OwnerRobotUserID),
|
||||
CandidateRobotUserIDs: []int64(req.CandidateRobotUserIDs),
|
||||
MinRobotCount: req.MinRobotCount,
|
||||
MaxRobotCount: req.MaxRobotCount,
|
||||
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 +320,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),
|
||||
})
|
||||
@ -180,21 +342,28 @@ func (s *Service) applyOwnerProfileToRobotRoomRequest(ctx context.Context, req *
|
||||
if s.userDB == nil {
|
||||
return fmt.Errorf("user database is not configured")
|
||||
}
|
||||
owners, err := s.queryRoomOwners(ctx, []int64{req.OwnerRobotUserID})
|
||||
ownerID := int64(req.OwnerRobotUserID)
|
||||
owners, err := s.queryRoomOwners(ctx, []int64{ownerID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
owner, ok := owners[req.OwnerRobotUserID]
|
||||
owner, ok := owners[ownerID]
|
||||
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
|
||||
}
|
||||
|
||||
@ -235,13 +404,21 @@ func (s *Service) SetRobotRoomStatus(ctx context.Context, roomID string, status
|
||||
}
|
||||
|
||||
func normalizeCreateRobotRoomRequest(req createRobotRoomRequest) (createRobotRoomRequest, error) {
|
||||
if req.OwnerRobotUserID <= 0 {
|
||||
ownerID := int64(req.OwnerRobotUserID)
|
||||
if ownerID <= 0 {
|
||||
return req, fmt.Errorf("%w: 请选择房主机器人", ErrInvalidArgument)
|
||||
}
|
||||
if req.MinRobotCount <= 0 || req.MaxRobotCount < req.MinRobotCount {
|
||||
return req, fmt.Errorf("%w: 机器人数量范围不正确", ErrInvalidArgument)
|
||||
}
|
||||
if len(req.CandidateRobotUserIDs) == 0 {
|
||||
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)
|
||||
}
|
||||
if len(req.GiftIDs) == 0 {
|
||||
@ -259,9 +436,42 @@ 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))
|
||||
for _, value := range values {
|
||||
// 房主由 room-service 单独并入机器人集合;候选列表只保留其他机器人,避免前端重复选择或旧脚本传入重复 ID。
|
||||
if value <= 0 || value == ownerID || seen[value] {
|
||||
continue
|
||||
}
|
||||
seen[value] = true
|
||||
out = append(out, value)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func robotRoomsFromClient(items []roomclient.RobotRoom) []RobotRoom {
|
||||
out := make([]RobotRoom, 0, len(items))
|
||||
for _, item := range items {
|
||||
@ -285,6 +495,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,
|
||||
@ -293,6 +505,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,
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -1,9 +1,16 @@
|
||||
package roomadmin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hyapp-admin-server/internal/integration/robotclient"
|
||||
)
|
||||
|
||||
@ -77,6 +84,115 @@ 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(`{
|
||||
"ownerRobotUserId":"325379237278126080",
|
||||
"candidateRobotUserIds":["325379237278126080","325455441691676672","325455441691676672"],
|
||||
"minRobotCount":2,
|
||||
"maxRobotCount":8,
|
||||
"giftIds":["84"],
|
||||
"luckyGiftIds":["28"],
|
||||
"normalGiftIntervalMs":10000,
|
||||
"luckyComboMin":100,
|
||||
"luckyComboMax":10000,
|
||||
"luckyPauseMinMs":5000,
|
||||
"luckyPauseMaxMs":20000
|
||||
}`), &req); err != nil {
|
||||
t.Fatalf("robot room request should accept string int64 ids: %v", err)
|
||||
}
|
||||
|
||||
normalized, err := normalizeCreateRobotRoomRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("robot room request should normalize: %v", err)
|
||||
}
|
||||
if got := int64(normalized.OwnerRobotUserID); got != 325379237278126080 {
|
||||
t.Fatalf("owner id mismatch: got %d", got)
|
||||
}
|
||||
if got := []int64(normalized.CandidateRobotUserIDs); len(got) != 1 || got[0] != 325455441691676672 {
|
||||
t.Fatalf("candidate ids should drop owner and duplicates, got %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
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},
|
||||
@ -99,3 +215,50 @@ func TestAvailableRoomRobotsFromGamePoolKeepsOnlyRoomAvailableUsers(t *testing.T
|
||||
t.Fatalf("second available robot mismatch: %+v", items[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAllActiveGameRobotsFollowsCursor(t *testing.T) {
|
||||
client := &pagedRobotClient{
|
||||
pages: map[string]robotclient.ListGameRobotsResult{
|
||||
"": {
|
||||
Robots: []robotclient.Robot{{UserID: 101}, {UserID: 102}},
|
||||
NextCursor: "102",
|
||||
},
|
||||
"102": {
|
||||
Robots: []robotclient.Robot{{UserID: 201}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
robots, err := listAllActiveGameRobots(context.Background(), client)
|
||||
if err != nil {
|
||||
t.Fatalf("list all active game robots failed: %v", err)
|
||||
}
|
||||
if len(robots) != 3 || robots[0].UserID != 101 || robots[1].UserID != 102 || robots[2].UserID != 201 {
|
||||
t.Fatalf("robots should include every cursor page, got %+v", robots)
|
||||
}
|
||||
if len(client.requests) != 2 {
|
||||
t.Fatalf("expected two page requests, got %+v", client.requests)
|
||||
}
|
||||
if client.requests[0].Cursor != "" || client.requests[1].Cursor != "102" {
|
||||
t.Fatalf("cursor chain mismatch: %+v", client.requests)
|
||||
}
|
||||
for _, req := range client.requests {
|
||||
if req.Status != "active" || req.PageSize != availableRoomRobotPageSize {
|
||||
t.Fatalf("request should use active status and page size %d, got %+v", availableRoomRobotPageSize, req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type pagedRobotClient struct {
|
||||
pages map[string]robotclient.ListGameRobotsResult
|
||||
requests []robotclient.ListGameRobotsRequest
|
||||
}
|
||||
|
||||
func (c *pagedRobotClient) ListGameRobots(_ context.Context, req robotclient.ListGameRobotsRequest) (robotclient.ListGameRobotsResult, error) {
|
||||
c.requests = append(c.requests, req)
|
||||
return c.pages[req.Cursor], nil
|
||||
}
|
||||
|
||||
func (c *pagedRobotClient) ListRoomRobots(context.Context, robotclient.ListRoomRobotsRequest) (robotclient.ListRoomRobotsResult, error) {
|
||||
return robotclient.ListRoomRobotsResult{}, errors.New("not used")
|
||||
}
|
||||
|
||||
112
server/admin/internal/modules/roomadmin/whitelist.go
Normal file
112
server/admin/internal/modules/roomadmin/whitelist.go
Normal 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
|
||||
}
|
||||
483
server/admin/internal/modules/wheel/handler.go
Normal file
483
server/admin/internal/modules/wheel/handler.go
Normal file
@ -0,0 +1,483 @@
|
||||
package wheel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"hyapp-admin-server/internal/appctx"
|
||||
"hyapp-admin-server/internal/integration/activityclient"
|
||||
"hyapp-admin-server/internal/middleware"
|
||||
"hyapp-admin-server/internal/modules/shared"
|
||||
"hyapp-admin-server/internal/response"
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const defaultWheelID = "default"
|
||||
|
||||
var wheelTierCounts = map[string]int{
|
||||
"classic": 9,
|
||||
"luxury": 8,
|
||||
"advanced": 12,
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
activity activityclient.Client
|
||||
requestTimeout time.Duration
|
||||
audit shared.OperationLogger
|
||||
}
|
||||
|
||||
func New(activity activityclient.Client, requestTimeout time.Duration, audit shared.OperationLogger) *Handler {
|
||||
if requestTimeout <= 0 {
|
||||
requestTimeout = 3 * time.Second
|
||||
}
|
||||
return &Handler{activity: activity, requestTimeout: requestTimeout, audit: audit}
|
||||
}
|
||||
|
||||
type configRequest struct {
|
||||
WheelID string `json:"wheel_id"`
|
||||
Enabled bool `json:"enabled"`
|
||||
DrawPriceCoins int64 `json:"draw_price_coins"`
|
||||
TargetRTPPercent float64 `json:"target_rtp_percent"`
|
||||
PoolRatePercent float64 `json:"pool_rate_percent"`
|
||||
SettlementWindowDraws int64 `json:"settlement_window_draws"`
|
||||
InitialPoolCoins int64 `json:"initial_pool_coins"`
|
||||
PoolReserveCoins int64 `json:"pool_reserve_coins"`
|
||||
MaxSingleRTPPayout int64 `json:"max_single_rtp_payout"`
|
||||
EffectiveFromMS int64 `json:"effective_from_ms"`
|
||||
Tiers []tierDTO `json:"tiers"`
|
||||
}
|
||||
|
||||
type configDTO struct {
|
||||
configRequest
|
||||
AppCode string `json:"app_code"`
|
||||
RuleVersion int64 `json:"rule_version"`
|
||||
CreatedByAdminID int64 `json:"created_by_admin_id"`
|
||||
CreatedAtMS int64 `json:"created_at_ms"`
|
||||
}
|
||||
|
||||
type tierDTO struct {
|
||||
TierID string `json:"tier_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
RewardType string `json:"reward_type"`
|
||||
RewardID string `json:"reward_id"`
|
||||
RewardCount int64 `json:"reward_count"`
|
||||
RewardCoins int64 `json:"reward_coins"`
|
||||
RTPValueCoins int64 `json:"rtp_value_coins"`
|
||||
ProbabilityPercent float64 `json:"probability_percent"`
|
||||
Enabled bool `json:"enabled"`
|
||||
MetadataJSON string `json:"metadata_json"`
|
||||
}
|
||||
|
||||
type drawDTO struct {
|
||||
DrawID string `json:"draw_id"`
|
||||
DrawIDs []string `json:"draw_ids"`
|
||||
CommandID string `json:"command_id"`
|
||||
WheelID string `json:"wheel_id"`
|
||||
RuleVersion int64 `json:"rule_version"`
|
||||
SelectedTierID string `json:"selected_tier_id"`
|
||||
RewardType string `json:"reward_type"`
|
||||
RewardID string `json:"reward_id"`
|
||||
RewardCount int64 `json:"reward_count"`
|
||||
RewardCoins int64 `json:"reward_coins"`
|
||||
RTPValueCoins int64 `json:"rtp_value_coins"`
|
||||
RewardStatus string `json:"reward_status"`
|
||||
RTPWindowIndex int64 `json:"rtp_window_index"`
|
||||
ActualRTPPPM int64 `json:"actual_rtp_ppm"`
|
||||
CreatedAtMS int64 `json:"created_at_ms"`
|
||||
WalletTransactionID string `json:"wallet_transaction_id"`
|
||||
CoinBalanceAfter int64 `json:"coin_balance_after"`
|
||||
MetadataJSON string `json:"metadata_json"`
|
||||
}
|
||||
|
||||
type drawSummaryDTO struct {
|
||||
WheelID string `json:"wheel_id"`
|
||||
TotalDraws int64 `json:"total_draws"`
|
||||
UniqueUsers int64 `json:"unique_users"`
|
||||
TotalSpentCoins int64 `json:"total_spent_coins"`
|
||||
TotalRTPValueCoins int64 `json:"total_rtp_value_coins"`
|
||||
ActualRTPPPM int64 `json:"actual_rtp_ppm"`
|
||||
PendingDraws int64 `json:"pending_draws"`
|
||||
GrantedDraws int64 `json:"granted_draws"`
|
||||
FailedDraws int64 `json:"failed_draws"`
|
||||
}
|
||||
|
||||
func (h *Handler) GetConfig(c *gin.Context) {
|
||||
wheelID := normalizeWheelID(firstQuery(c, "wheel_id", "wheelId"))
|
||||
ctx, cancel := h.activityContext(c)
|
||||
defer cancel()
|
||||
resp, err := h.activity.GetWheelConfig(ctx, &activityv1.GetWheelConfigRequest{Meta: h.meta(c), WheelId: wheelID})
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
response.OK(c, defaultConfigDTO(wheelID))
|
||||
return
|
||||
}
|
||||
response.ServerError(c, "获取转盘配置失败")
|
||||
return
|
||||
}
|
||||
response.OK(c, configFromProto(resp.GetConfig()))
|
||||
}
|
||||
|
||||
func (h *Handler) UpsertConfig(c *gin.Context) {
|
||||
var req configRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "转盘配置参数不正确")
|
||||
return
|
||||
}
|
||||
if req.WheelID == "" {
|
||||
req.WheelID = firstQuery(c, "wheel_id", "wheelId")
|
||||
}
|
||||
if err := validateConfigRequest(req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
ctx, cancel := h.activityContext(c)
|
||||
defer cancel()
|
||||
resp, err := h.activity.UpsertWheelConfig(ctx, &activityv1.UpsertWheelConfigRequest{
|
||||
Meta: h.meta(c),
|
||||
Config: configToProto(req),
|
||||
OperatorAdminId: int64(middleware.CurrentUserID(c)),
|
||||
})
|
||||
if err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
item := configFromProto(resp.GetConfig())
|
||||
shared.OperationLogWithResourceID(c, h.audit, "upsert-wheel-config", "wheel_rule_versions", item.WheelID, "success", "")
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) ListDraws(c *gin.Context) {
|
||||
options := shared.ListOptions(c)
|
||||
ctx, cancel := h.activityContext(c)
|
||||
defer cancel()
|
||||
resp, err := h.activity.ListWheelDraws(ctx, &activityv1.ListWheelDrawsRequest{
|
||||
Meta: h.meta(c),
|
||||
WheelId: normalizeWheelID(firstQuery(c, "wheel_id", "wheelId")),
|
||||
UserId: parseOptionalInt64(firstQuery(c, "user_id", "userId")),
|
||||
Status: strings.TrimSpace(options.Status),
|
||||
Page: int32(options.Page),
|
||||
PageSize: int32(options.PageSize),
|
||||
})
|
||||
if err != nil {
|
||||
response.ServerError(c, "获取转盘抽奖记录失败")
|
||||
return
|
||||
}
|
||||
items := make([]drawDTO, 0, len(resp.GetDraws()))
|
||||
for _, draw := range resp.GetDraws() {
|
||||
items = append(items, drawFromProto(draw))
|
||||
}
|
||||
response.OK(c, response.Page{Items: items, Page: options.Page, PageSize: options.PageSize, Total: resp.GetTotal()})
|
||||
}
|
||||
|
||||
func (h *Handler) GetDrawSummary(c *gin.Context) {
|
||||
ctx, cancel := h.activityContext(c)
|
||||
defer cancel()
|
||||
resp, err := h.activity.GetWheelDrawSummary(ctx, &activityv1.GetWheelDrawSummaryRequest{
|
||||
Meta: h.meta(c),
|
||||
WheelId: normalizeWheelID(firstQuery(c, "wheel_id", "wheelId")),
|
||||
UserId: parseOptionalInt64(firstQuery(c, "user_id", "userId")),
|
||||
Status: strings.TrimSpace(c.Query("status")),
|
||||
})
|
||||
if err != nil {
|
||||
response.ServerError(c, "获取转盘抽奖汇总失败")
|
||||
return
|
||||
}
|
||||
response.OK(c, drawSummaryFromProto(resp.GetSummary()))
|
||||
}
|
||||
|
||||
func (h *Handler) meta(c *gin.Context) *activityv1.RequestMeta {
|
||||
return &activityv1.RequestMeta{
|
||||
RequestId: middleware.CurrentRequestID(c),
|
||||
Caller: "admin-server",
|
||||
AppCode: appctx.FromContext(c.Request.Context()),
|
||||
SentAtMs: time.Now().UTC().UnixMilli(),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) activityContext(c *gin.Context) (context.Context, context.CancelFunc) {
|
||||
return context.WithTimeout(c.Request.Context(), h.requestTimeout)
|
||||
}
|
||||
|
||||
func validateConfigRequest(req configRequest) error {
|
||||
if normalizeWheelID(req.WheelID) == "" {
|
||||
return fmt.Errorf("wheel_id 不能为空")
|
||||
}
|
||||
expectedCount := expectedWheelTierCount(req.WheelID)
|
||||
// 转盘前端布局是固定格子数:classic=9、luxury=8、advanced=12。这里按池子强校验,
|
||||
// 避免运营导入资源组后少格或多格,导致 H5 动画序列和后端奖品配置无法一一对应。
|
||||
if len(req.Tiers) != expectedCount {
|
||||
return fmt.Errorf("%s 转盘必须配置 %d 个奖品档位", normalizeWheelID(req.WheelID), expectedCount)
|
||||
}
|
||||
var totalProbability float64
|
||||
for _, tier := range req.Tiers {
|
||||
rewardType := normalizeRewardType(tier.RewardType)
|
||||
if rewardType == "" {
|
||||
return fmt.Errorf("奖品类型不能为空")
|
||||
}
|
||||
totalProbability += tier.ProbabilityPercent
|
||||
switch rewardType {
|
||||
case "coin":
|
||||
if tier.RewardCoins <= 0 {
|
||||
return fmt.Errorf("金币档 reward_coins 必须大于 0")
|
||||
}
|
||||
case "gift":
|
||||
if strings.TrimSpace(tier.RewardID) == "" {
|
||||
return fmt.Errorf("礼物档 reward_id 不能为空")
|
||||
}
|
||||
case "prop", "dress":
|
||||
if strings.TrimSpace(tier.RewardID) == "" {
|
||||
return fmt.Errorf("道具或装扮档 reward_id 不能为空")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("奖品类型只支持 coin、gift、prop、dress")
|
||||
}
|
||||
// 道具和装扮用于背包展示,不进入 RTP 支出;真实清零在 configToProto 里执行,
|
||||
// 这里保留运营输入兼容性,防止旧配置带值时直接无法打开保存。
|
||||
if tier.ProbabilityPercent < 0 {
|
||||
return fmt.Errorf("奖品概率不能为负数")
|
||||
}
|
||||
}
|
||||
if math.Abs(totalProbability-100) > 0.000001 {
|
||||
return fmt.Errorf("奖品档位概率合计必须等于 100")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func configToProto(req configRequest) *activityv1.WheelRuleConfig {
|
||||
tiers := make([]*activityv1.WheelPrizeTier, 0, len(req.Tiers))
|
||||
for index, tier := range req.Tiers {
|
||||
rewardType := normalizeRewardType(tier.RewardType)
|
||||
rtpValue := tier.RTPValueCoins
|
||||
rewardCoins := tier.RewardCoins
|
||||
if rewardType == "coin" && rtpValue <= 0 {
|
||||
rtpValue = rewardCoins
|
||||
}
|
||||
if rewardType == "prop" || rewardType == "dress" {
|
||||
rtpValue = 0
|
||||
}
|
||||
tiers = append(tiers, &activityv1.WheelPrizeTier{
|
||||
TierId: generatedTierID(tier.TierID, rewardType, index),
|
||||
DisplayName: strings.TrimSpace(tier.DisplayName),
|
||||
RewardType: rewardType,
|
||||
RewardId: strings.TrimSpace(tier.RewardID),
|
||||
RewardCount: tier.RewardCount,
|
||||
RewardCoins: rewardCoins,
|
||||
RtpValueCoins: rtpValue,
|
||||
WeightPpm: percentToPPM(tier.ProbabilityPercent),
|
||||
Enabled: tier.Enabled,
|
||||
MetadataJson: normalizeMetadataJSON(tier.MetadataJSON),
|
||||
})
|
||||
}
|
||||
return &activityv1.WheelRuleConfig{
|
||||
WheelId: normalizeWheelID(req.WheelID),
|
||||
Enabled: req.Enabled,
|
||||
DrawPriceCoins: req.DrawPriceCoins,
|
||||
TargetRtpPpm: percentToPPM(req.TargetRTPPercent),
|
||||
PoolRatePpm: percentToPPM(req.PoolRatePercent),
|
||||
SettlementWindowDraws: req.SettlementWindowDraws,
|
||||
InitialPoolCoins: req.InitialPoolCoins,
|
||||
PoolReserveCoins: req.PoolReserveCoins,
|
||||
MaxSingleRtpPayout: req.MaxSingleRTPPayout,
|
||||
EffectiveFromMs: req.EffectiveFromMS,
|
||||
Tiers: tiers,
|
||||
}
|
||||
}
|
||||
|
||||
func configFromProto(config *activityv1.WheelRuleConfig) configDTO {
|
||||
if config == nil {
|
||||
return configDTO{}
|
||||
}
|
||||
tiers := make([]tierDTO, 0, len(config.GetTiers()))
|
||||
for _, tier := range config.GetTiers() {
|
||||
tiers = append(tiers, tierDTO{
|
||||
TierID: tier.GetTierId(),
|
||||
DisplayName: tier.GetDisplayName(),
|
||||
RewardType: tier.GetRewardType(),
|
||||
RewardID: tier.GetRewardId(),
|
||||
RewardCount: tier.GetRewardCount(),
|
||||
RewardCoins: tier.GetRewardCoins(),
|
||||
RTPValueCoins: tier.GetRtpValueCoins(),
|
||||
ProbabilityPercent: ppmToPercent(tier.GetWeightPpm()),
|
||||
Enabled: tier.GetEnabled(),
|
||||
MetadataJSON: tier.GetMetadataJson(),
|
||||
})
|
||||
}
|
||||
return configDTO{
|
||||
AppCode: config.GetAppCode(),
|
||||
RuleVersion: config.GetRuleVersion(),
|
||||
CreatedByAdminID: config.GetCreatedByAdminId(),
|
||||
CreatedAtMS: config.GetCreatedAtMs(),
|
||||
configRequest: configRequest{
|
||||
WheelID: normalizeWheelID(config.GetWheelId()),
|
||||
Enabled: config.GetEnabled(),
|
||||
DrawPriceCoins: config.GetDrawPriceCoins(),
|
||||
TargetRTPPercent: ppmToPercent(config.GetTargetRtpPpm()),
|
||||
PoolRatePercent: ppmToPercent(config.GetPoolRatePpm()),
|
||||
SettlementWindowDraws: config.GetSettlementWindowDraws(),
|
||||
InitialPoolCoins: config.GetInitialPoolCoins(),
|
||||
PoolReserveCoins: config.GetPoolReserveCoins(),
|
||||
MaxSingleRTPPayout: config.GetMaxSingleRtpPayout(),
|
||||
EffectiveFromMS: config.GetEffectiveFromMs(),
|
||||
Tiers: tiers,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func defaultConfigDTO(wheelID string) configDTO {
|
||||
wheelID = normalizeWheelID(wheelID)
|
||||
// 没有保存过配置时只返回基础参数和空档位。奖品档位必须从资源组导入,
|
||||
// 不能用占位奖品冒充真实配置,否则运营会误以为当前池子已经可发布。
|
||||
return configDTO{configRequest: configRequest{
|
||||
WheelID: wheelID,
|
||||
Enabled: false,
|
||||
DrawPriceCoins: 10_000,
|
||||
TargetRTPPercent: 90,
|
||||
PoolRatePercent: 90,
|
||||
SettlementWindowDraws: 1000,
|
||||
InitialPoolCoins: 0,
|
||||
PoolReserveCoins: 0,
|
||||
MaxSingleRTPPayout: 0,
|
||||
Tiers: []tierDTO{},
|
||||
}}
|
||||
}
|
||||
|
||||
func expectedWheelTierCount(wheelID string) int {
|
||||
if count, ok := wheelTierCounts[normalizeWheelID(wheelID)]; ok {
|
||||
return count
|
||||
}
|
||||
return wheelTierCounts["classic"]
|
||||
}
|
||||
|
||||
func defaultProbabilityPercent(index int, count int) float64 {
|
||||
if count <= 0 {
|
||||
return 0
|
||||
}
|
||||
base := math.Floor(10000/float64(count)) / 100
|
||||
if index == count-1 {
|
||||
return 100 - base*float64(count-1)
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
func drawFromProto(draw *activityv1.WheelDrawResult) drawDTO {
|
||||
if draw == nil {
|
||||
return drawDTO{}
|
||||
}
|
||||
return drawDTO{
|
||||
DrawID: draw.GetDrawId(),
|
||||
DrawIDs: draw.GetDrawIds(),
|
||||
CommandID: draw.GetCommandId(),
|
||||
WheelID: draw.GetWheelId(),
|
||||
RuleVersion: draw.GetRuleVersion(),
|
||||
SelectedTierID: draw.GetSelectedTierId(),
|
||||
RewardType: draw.GetRewardType(),
|
||||
RewardID: draw.GetRewardId(),
|
||||
RewardCount: draw.GetRewardCount(),
|
||||
RewardCoins: draw.GetRewardCoins(),
|
||||
RTPValueCoins: draw.GetRtpValueCoins(),
|
||||
RewardStatus: draw.GetRewardStatus(),
|
||||
RTPWindowIndex: draw.GetRtpWindowIndex(),
|
||||
ActualRTPPPM: draw.GetActualRtpPpm(),
|
||||
CreatedAtMS: draw.GetCreatedAtMs(),
|
||||
WalletTransactionID: draw.GetWalletTransactionId(),
|
||||
CoinBalanceAfter: draw.GetCoinBalanceAfter(),
|
||||
MetadataJSON: draw.GetMetadataJson(),
|
||||
}
|
||||
}
|
||||
|
||||
func drawSummaryFromProto(summary *activityv1.WheelDrawSummary) drawSummaryDTO {
|
||||
if summary == nil {
|
||||
return drawSummaryDTO{}
|
||||
}
|
||||
return drawSummaryDTO{
|
||||
WheelID: summary.GetWheelId(),
|
||||
TotalDraws: summary.GetTotalDraws(),
|
||||
UniqueUsers: summary.GetUniqueUsers(),
|
||||
TotalSpentCoins: summary.GetTotalSpentCoins(),
|
||||
TotalRTPValueCoins: summary.GetTotalRtpValueCoins(),
|
||||
ActualRTPPPM: summary.GetActualRtpPpm(),
|
||||
PendingDraws: summary.GetPendingDraws(),
|
||||
GrantedDraws: summary.GetGrantedDraws(),
|
||||
FailedDraws: summary.GetFailedDraws(),
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeRewardType(value string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||
case "coin":
|
||||
return "coin"
|
||||
case "gift":
|
||||
return "gift"
|
||||
case "prop", "item", "decoration", "resource":
|
||||
return "prop"
|
||||
case "dress", "dress_up", "costume":
|
||||
return "dress"
|
||||
default:
|
||||
return strings.ToLower(strings.TrimSpace(value))
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeWheelID(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return defaultWheelID
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func generatedTierID(raw string, rewardType string, index int) string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw != "" {
|
||||
return raw
|
||||
}
|
||||
// 同一奖池现在允许多个金币、多个礼物或多个装扮;缺省 ID 必须带序号,
|
||||
// 否则多档同类型会落到同一个 tier_id,抽奖结果无法稳定回显到正确格子。
|
||||
return fmt.Sprintf("%s-%02d", rewardType, index+1)
|
||||
}
|
||||
|
||||
func normalizeMetadataJSON(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return "{}"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func percentToPPM(value float64) int64 {
|
||||
return int64(math.Round(value * 10_000))
|
||||
}
|
||||
|
||||
func ppmToPercent(value int64) float64 {
|
||||
return float64(value) / 10_000
|
||||
}
|
||||
|
||||
func firstQuery(c *gin.Context, names ...string) string {
|
||||
for _, name := range names {
|
||||
if value := strings.TrimSpace(c.Query(name)); value != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func parseOptionalInt64(value string) int64 {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return 0
|
||||
}
|
||||
var result int64
|
||||
for _, char := range value {
|
||||
if char < '0' || char > '9' {
|
||||
return 0
|
||||
}
|
||||
result = result*10 + int64(char-'0')
|
||||
}
|
||||
return result
|
||||
}
|
||||
114
server/admin/internal/modules/wheel/handler_test.go
Normal file
114
server/admin/internal/modules/wheel/handler_test.go
Normal file
@ -0,0 +1,114 @@
|
||||
package wheel
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
)
|
||||
|
||||
func TestConfigToProtoSupportsPoolTierCountAndForcesPropRTPZero(t *testing.T) {
|
||||
tiers := validClassicTiers()
|
||||
tiers[0] = tierDTO{DisplayName: "金币", RewardType: " coin ", RewardCount: 1, RewardCoins: 1000, ProbabilityPercent: defaultProbabilityPercent(0, 9), Enabled: true}
|
||||
tiers[1] = tierDTO{DisplayName: "礼物", RewardType: "gift", RewardID: "gift_1", RewardCount: 1, RTPValueCoins: 5000, ProbabilityPercent: defaultProbabilityPercent(1, 9), Enabled: true}
|
||||
tiers[2] = tierDTO{DisplayName: "装扮", RewardType: "dress_up", RewardID: "dress_1", RewardCount: 1, RTPValueCoins: 999999, ProbabilityPercent: defaultProbabilityPercent(2, 9), Enabled: true}
|
||||
req := configRequest{
|
||||
WheelID: " classic ",
|
||||
Enabled: true,
|
||||
DrawPriceCoins: 10000,
|
||||
TargetRTPPercent: 90,
|
||||
PoolRatePercent: 92,
|
||||
SettlementWindowDraws: 1000,
|
||||
Tiers: tiers,
|
||||
}
|
||||
if err := validateConfigRequest(req); err != nil {
|
||||
t.Fatalf("validate config failed: %v", err)
|
||||
}
|
||||
config := configToProto(req)
|
||||
if config.GetWheelId() != "classic" {
|
||||
t.Fatalf("wheel id = %q, want classic", config.GetWheelId())
|
||||
}
|
||||
if config.GetTargetRtpPpm() != 900000 || config.GetPoolRatePpm() != 920000 {
|
||||
t.Fatalf("ppm mismatch: target=%d pool=%d", config.GetTargetRtpPpm(), config.GetPoolRatePpm())
|
||||
}
|
||||
protoTiers := config.GetTiers()
|
||||
if len(protoTiers) != 9 {
|
||||
t.Fatalf("tier count = %d, want 9", len(protoTiers))
|
||||
}
|
||||
if protoTiers[0].GetTierId() != "coin-01" || protoTiers[0].GetRtpValueCoins() != 1000 {
|
||||
t.Fatalf("coin tier mismatch: %+v", protoTiers[0])
|
||||
}
|
||||
if protoTiers[2].GetRewardType() != "dress" || protoTiers[2].GetRtpValueCoins() != 0 {
|
||||
t.Fatalf("dress tier must force rtp to zero: %+v", protoTiers[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateConfigRequiresPoolTierCountAndProbabilitySum(t *testing.T) {
|
||||
err := validateConfigRequest(configRequest{
|
||||
WheelID: "classic",
|
||||
Tiers: []tierDTO{
|
||||
{RewardType: "coin", RewardCoins: 100, ProbabilityPercent: 50},
|
||||
{RewardType: "gift", RewardID: "gift_1", ProbabilityPercent: 30},
|
||||
{RewardType: "gift", RewardID: "gift_2", ProbabilityPercent: 20},
|
||||
},
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "9 个奖品档位") {
|
||||
t.Fatalf("classic tier count should be rejected, got %v", err)
|
||||
}
|
||||
tiers := validClassicTiers()
|
||||
tiers[8].ProbabilityPercent = 1
|
||||
err = validateConfigRequest(configRequest{
|
||||
WheelID: "classic",
|
||||
Tiers: tiers,
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "概率合计") {
|
||||
t.Fatalf("probability sum should be rejected, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultConfigDoesNotCreateMockPrizeTiers(t *testing.T) {
|
||||
config := defaultConfigDTO("classic")
|
||||
if len(config.Tiers) != 0 {
|
||||
t.Fatalf("default config must not create mock prize tiers: %+v", config.Tiers)
|
||||
}
|
||||
if config.WheelID != "classic" || config.DrawPriceCoins <= 0 {
|
||||
t.Fatalf("default base config mismatch: %+v", config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigFromProtoConvertsPPMToPercent(t *testing.T) {
|
||||
config := configFromProto(&activityv1.WheelRuleConfig{
|
||||
AppCode: "lalu",
|
||||
WheelId: "default",
|
||||
RuleVersion: 3,
|
||||
Enabled: true,
|
||||
DrawPriceCoins: 10000,
|
||||
TargetRtpPpm: 900000,
|
||||
PoolRatePpm: 920000,
|
||||
SettlementWindowDraws: 1000,
|
||||
Tiers: []*activityv1.WheelPrizeTier{
|
||||
{TierId: "coin", DisplayName: "金币", RewardType: "coin", RewardCoins: 1000, RtpValueCoins: 1000, WeightPpm: 600000, Enabled: true},
|
||||
},
|
||||
})
|
||||
if config.TargetRTPPercent != 90 || config.PoolRatePercent != 92 {
|
||||
t.Fatalf("percent mismatch: target=%v pool=%v", config.TargetRTPPercent, config.PoolRatePercent)
|
||||
}
|
||||
if len(config.Tiers) != 1 || config.Tiers[0].ProbabilityPercent != 60 {
|
||||
t.Fatalf("tier probability mismatch: %+v", config.Tiers)
|
||||
}
|
||||
}
|
||||
|
||||
func validClassicTiers() []tierDTO {
|
||||
tiers := make([]tierDTO, 0, 9)
|
||||
for index := 0; index < 9; index++ {
|
||||
tiers = append(tiers, tierDTO{
|
||||
DisplayName: "金币",
|
||||
RewardType: "coin",
|
||||
RewardCount: 1,
|
||||
RewardCoins: 100,
|
||||
ProbabilityPercent: defaultProbabilityPercent(index, 9),
|
||||
Enabled: true,
|
||||
})
|
||||
}
|
||||
return tiers
|
||||
}
|
||||
17
server/admin/internal/modules/wheel/routes.go
Normal file
17
server/admin/internal/modules/wheel/routes.go
Normal file
@ -0,0 +1,17 @@
|
||||
package wheel
|
||||
|
||||
import (
|
||||
"hyapp-admin-server/internal/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterRoutes(protected *gin.RouterGroup, h *Handler) {
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
protected.GET("/admin/activity/wheel/config", middleware.RequirePermission("wheel:view"), h.GetConfig)
|
||||
protected.PUT("/admin/activity/wheel/config", middleware.RequirePermission("wheel:update"), h.UpsertConfig)
|
||||
protected.GET("/admin/activity/wheel/draws", middleware.RequirePermission("wheel:view"), h.ListDraws)
|
||||
protected.GET("/admin/activity/wheel/draw-summary", middleware.RequirePermission("wheel:view"), h.GetDrawSummary)
|
||||
}
|
||||
@ -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"},
|
||||
@ -128,6 +130,8 @@ var defaultPermissions = []model.Permission{
|
||||
{Name: "七日签到更新", Code: "seven-day-checkin:update", Kind: "button"},
|
||||
{Name: "幸运礼物查看", Code: "lucky-gift:view", Kind: "menu"},
|
||||
{Name: "幸运礼物更新", Code: "lucky-gift:update", Kind: "button"},
|
||||
{Name: "转盘抽奖查看", Code: "wheel:view", Kind: "menu"},
|
||||
{Name: "转盘抽奖更新", Code: "wheel:update", Kind: "button"},
|
||||
{Name: "房间火箭查看", Code: "room-rocket:view", Kind: "menu"},
|
||||
{Name: "房间火箭更新", Code: "room-rocket:update", Kind: "button"},
|
||||
{Name: "用户榜单查看", Code: "user-leaderboard:view", Kind: "menu"},
|
||||
@ -263,7 +267,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},
|
||||
@ -280,9 +285,9 @@ func (s *Store) seedMenus() error {
|
||||
{ParentID: &operationsID, Title: "币商流水", Code: "operation-coin-seller-ledger", Path: "/operations/coin-seller-ledger", Icon: "receipt", PermissionCode: "coin-seller-ledger:view", Sort: 69, Visible: true},
|
||||
{ParentID: &operationsID, Title: "金币增减", Code: "operation-coin-adjustment", Path: "/operations/coin-adjustments", Icon: "wallet", PermissionCode: "coin-adjustment:view", Sort: 70, Visible: true},
|
||||
{ParentID: &operationsID, Title: "幸运礼物", Code: "lucky-gift", Path: "/operations/lucky-gift", Icon: "redeem", PermissionCode: "lucky-gift:view", Sort: 71, Visible: true},
|
||||
{ParentID: &operationsID, Title: "举报列表", Code: "operation-reports", Path: "/operations/reports", Icon: "flag", PermissionCode: "report:view", Sort: 72, Visible: true},
|
||||
{ParentID: &operationsID, Title: "礼物钻石", Code: "operation-gift-diamond", Path: "/operations/gift-diamonds", Icon: "diamond", PermissionCode: "gift-diamond:view", Sort: 73, Visible: true},
|
||||
{ParentID: &operationsID, Title: "全服通知", Code: "operation-full-server-notice", Path: "/operations/full-server-notices", Icon: "campaign", PermissionCode: "full-server-notice:view", Sort: 74, Visible: true},
|
||||
{ParentID: &operationsID, Title: "举报列表", Code: "operation-reports", Path: "/operations/reports", Icon: "flag", PermissionCode: "report:view", Sort: 73, Visible: true},
|
||||
{ParentID: &operationsID, Title: "礼物钻石", Code: "operation-gift-diamond", Path: "/operations/gift-diamonds", Icon: "diamond", PermissionCode: "gift-diamond:view", Sort: 74, Visible: true},
|
||||
{ParentID: &operationsID, Title: "全服通知", Code: "operation-full-server-notice", Path: "/operations/full-server-notices", Icon: "campaign", PermissionCode: "full-server-notice:view", Sort: 75, Visible: true},
|
||||
{ParentID: &paymentID, Title: "账单列表", Code: "payment-bill-list", Path: "/payment/bills", Icon: "receipt", PermissionCode: "payment-bill:view", Sort: 68, Visible: true},
|
||||
{ParentID: &paymentID, Title: "三方支付", Code: "payment-third-party", Path: "/payment/third-party", Icon: "wallet", PermissionCode: "payment-third-party:view", Sort: 69, Visible: true},
|
||||
{ParentID: &paymentID, Title: "支付内购商品", Code: "payment-recharge-products", Path: "/payment/recharge-products", Icon: "wallet", PermissionCode: "payment-product:view", Sort: 70, Visible: true},
|
||||
@ -297,6 +302,7 @@ func (s *Store) seedMenus() error {
|
||||
{ParentID: &activityID, Title: "VIP配置", Code: "vip-config", Path: "/activities/vip-config", Icon: "workspace_premium", PermissionCode: "vip-config:view", Sort: 77, Visible: true},
|
||||
{ParentID: &activityID, Title: "周星配置", Code: "weekly-star", Path: "/activities/weekly-star", Icon: "star", PermissionCode: "weekly-star:view", Sort: 78, Visible: true},
|
||||
{ParentID: &activityID, Title: "代理开业活动", Code: "agency-opening", Path: "/activities/agency-opening", Icon: "workspace_premium", PermissionCode: "agency-opening:view", Sort: 79, Visible: true},
|
||||
{ParentID: &activityID, Title: "转盘抽奖", Code: "wheel", Path: "/activities/wheel", Icon: "casino", PermissionCode: "wheel:view", Sort: 80, Visible: true},
|
||||
{ParentID: &gameID, Title: "游戏列表", Code: "game-list", Path: "/games", Icon: "sports_esports", PermissionCode: "game:view", Sort: 70, Visible: true},
|
||||
{ParentID: &gameID, Title: "自研游戏", Code: "self-games", Path: "/games/self-games", Icon: "settings", PermissionCode: "game:view", Sort: 80, Visible: true},
|
||||
{ParentID: &gameID, Title: "全站机器人", Code: "game-robots", Path: "/games/robots", Icon: "team", PermissionCode: "game:view", Sort: 90, Visible: true},
|
||||
@ -522,7 +528,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",
|
||||
@ -538,7 +544,7 @@ func defaultRolePermissionCodes(code string) []string {
|
||||
"bd:view", "bd:create", "bd:update",
|
||||
"coin-seller:view", "coin-seller:create", "coin-seller:update", "coin-seller:stock-credit", "coin-seller:exchange-rate",
|
||||
"coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "coin-adjustment:create", "report:view", "gift-diamond:view", "gift-diamond:update", "full-server-notice:view", "full-server-notice:send", "payment-bill:view", "payment-third-party:view", "payment-third-party:update", "payment-product:view", "payment-product:create", "payment-product:update", "payment-product:delete",
|
||||
"lucky-gift:view", "lucky-gift:update",
|
||||
"lucky-gift:view", "lucky-gift:update", "wheel:view", "wheel:update",
|
||||
"game:view", "game:create", "game:update", "game:status", "game:delete",
|
||||
"daily-task:view", "daily-task:create", "daily-task:update", "daily-task:status",
|
||||
"achievement:view", "achievement:create", "achievement:update",
|
||||
@ -554,7 +560,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", "wheel: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 +572,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",
|
||||
@ -591,6 +598,7 @@ func defaultRolePermissionCodes(code string) []string {
|
||||
"gift-diamond:view",
|
||||
"full-server-notice:view",
|
||||
"lucky-gift:view",
|
||||
"wheel:view",
|
||||
"payment-bill:view",
|
||||
"payment-third-party:view",
|
||||
"payment-product:view",
|
||||
@ -620,7 +628,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",
|
||||
@ -638,7 +646,7 @@ func defaultRolePermissionMigrationCodes(code string) []string {
|
||||
"host-agency-policy:view", "host-agency-policy:create", "host-agency-policy:update", "host-agency-policy:delete", "host-agency-policy:publish", "team-salary-policy:view", "team-salary-policy:create", "team-salary-policy:update", "team-salary-policy:delete", "host-salary-settlement:view", "host-salary-settlement:settle",
|
||||
"coin-seller:view", "coin-seller:create", "coin-seller:update", "coin-seller:stock-credit", "coin-seller:exchange-rate",
|
||||
"coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "coin-adjustment:create", "report:view", "gift-diamond:view", "gift-diamond:update", "full-server-notice:view", "full-server-notice:send", "payment-bill:view", "payment-third-party:view", "payment-third-party:update", "payment-product:view", "payment-product:create", "payment-product:update", "payment-product:delete",
|
||||
"lucky-gift:view", "lucky-gift:update",
|
||||
"lucky-gift:view", "lucky-gift:update", "wheel:view", "wheel:update",
|
||||
"game:view", "game:create", "game:update", "game:status", "game:delete",
|
||||
"daily-task:view", "daily-task:create", "daily-task:update", "daily-task:status",
|
||||
"achievement:view", "achievement:create", "achievement:update",
|
||||
@ -651,7 +659,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", "wheel: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
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ import (
|
||||
"hyapp-admin-server/internal/modules/userleaderboard"
|
||||
"hyapp-admin-server/internal/modules/vipconfig"
|
||||
"hyapp-admin-server/internal/modules/weeklystar"
|
||||
"hyapp-admin-server/internal/modules/wheel"
|
||||
"hyapp-admin-server/internal/platform/logging"
|
||||
"hyapp-admin-server/internal/service"
|
||||
|
||||
@ -102,6 +103,7 @@ type Handlers struct {
|
||||
UserLeaderboard *userleaderboard.Handler
|
||||
VIPConfig *vipconfig.Handler
|
||||
WeeklyStar *weeklystar.Handler
|
||||
Wheel *wheel.Handler
|
||||
}
|
||||
|
||||
func New(cfg config.Config, auth *service.AuthService, h Handlers) *gin.Engine {
|
||||
@ -160,6 +162,7 @@ func New(cfg config.Config, auth *service.AuthService, h Handlers) *gin.Engine {
|
||||
userleaderboard.RegisterRoutes(protected, h.UserLeaderboard)
|
||||
vipconfig.RegisterRoutes(protected, h.VIPConfig)
|
||||
weeklystar.RegisterRoutes(protected, h.WeeklyStar)
|
||||
wheel.RegisterRoutes(protected, h.Wheel)
|
||||
|
||||
return engine
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 '显示范围,多选逗号分隔:首页、房间内、充值页或我的页';
|
||||
|
||||
41
server/admin/migrations/055_room_whitelist_navigation.sql
Normal file
41
server/admin/migrations/055_room_whitelist_navigation.sql
Normal 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');
|
||||
59
server/admin/migrations/056_wheel_navigation.sql
Normal file
59
server/admin/migrations/056_wheel_navigation.sql
Normal file
@ -0,0 +1,59 @@
|
||||
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- 转盘抽奖规则、记录和统计都归 activity-service;后台提供活动管理入口和 gRPC 配置适配。
|
||||
SET @now_ms = CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED);
|
||||
|
||||
INSERT INTO admin_permissions (name, code, kind, description, created_at_ms, updated_at_ms) VALUES
|
||||
('转盘抽奖查看', 'wheel:view', 'menu', '', @now_ms, @now_ms),
|
||||
('转盘抽奖更新', 'wheel:update', 'button', '', @now_ms, @now_ms)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
name = VALUES(name),
|
||||
kind = VALUES(kind),
|
||||
description = VALUES(description),
|
||||
updated_at_ms = @now_ms;
|
||||
|
||||
INSERT INTO admin_menus (parent_id, title, code, path, icon, permission_code, sort, visible, created_at_ms, updated_at_ms) VALUES
|
||||
(NULL, '活动管理', 'activities', '', 'campaign', '', 80, TRUE, @now_ms, @now_ms)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
title = VALUES(title),
|
||||
path = VALUES(path),
|
||||
icon = VALUES(icon),
|
||||
permission_code = VALUES(permission_code),
|
||||
sort = VALUES(sort),
|
||||
visible = VALUES(visible),
|
||||
updated_at_ms = @now_ms;
|
||||
|
||||
INSERT INTO admin_menus (parent_id, title, code, path, icon, permission_code, sort, visible, created_at_ms, updated_at_ms)
|
||||
SELECT parent.id, '转盘抽奖', 'wheel', '/activities/wheel', 'casino', 'wheel:view', 80, TRUE, @now_ms, @now_ms
|
||||
FROM admin_menus parent
|
||||
WHERE parent.code = 'activities'
|
||||
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 = @now_ms;
|
||||
|
||||
INSERT IGNORE INTO admin_role_permissions (role_id, permission_id)
|
||||
SELECT admin_role.id, admin_permission.id
|
||||
FROM admin_roles admin_role
|
||||
JOIN admin_permissions admin_permission
|
||||
WHERE admin_role.code = 'platform-admin'
|
||||
AND admin_permission.code IN ('wheel:view', 'wheel:update');
|
||||
|
||||
INSERT IGNORE INTO admin_role_permissions (role_id, permission_id)
|
||||
SELECT admin_role.id, admin_permission.id
|
||||
FROM admin_roles admin_role
|
||||
JOIN admin_permissions admin_permission
|
||||
WHERE admin_role.code = 'ops-admin'
|
||||
AND admin_permission.code IN ('wheel:view', 'wheel:update');
|
||||
|
||||
INSERT IGNORE INTO admin_role_permissions (role_id, permission_id)
|
||||
SELECT admin_role.id, admin_permission.id
|
||||
FROM admin_roles admin_role
|
||||
JOIN admin_permissions admin_permission
|
||||
WHERE admin_role.code IN ('auditor', 'readonly')
|
||||
AND admin_permission.code = 'wheel:view';
|
||||
26
server/admin/migrations/057_move_wheel_to_activities.sql
Normal file
26
server/admin/migrations/057_move_wheel_to_activities.sql
Normal file
@ -0,0 +1,26 @@
|
||||
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- 056 初版曾把转盘抽奖放在运营管理;这里单独迁移到活动管理,保证已执行过 056 的库也能修正菜单位置。
|
||||
SET @now_ms = CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED);
|
||||
|
||||
INSERT INTO admin_menus (parent_id, title, code, path, icon, permission_code, sort, visible, created_at_ms, updated_at_ms) VALUES
|
||||
(NULL, '活动管理', 'activities', '', 'campaign', '', 80, TRUE, @now_ms, @now_ms)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
title = VALUES(title),
|
||||
path = VALUES(path),
|
||||
icon = VALUES(icon),
|
||||
permission_code = VALUES(permission_code),
|
||||
sort = VALUES(sort),
|
||||
visible = VALUES(visible),
|
||||
updated_at_ms = @now_ms;
|
||||
|
||||
UPDATE admin_menus wheel
|
||||
JOIN admin_menus activities ON activities.code = 'activities'
|
||||
SET wheel.parent_id = activities.id,
|
||||
wheel.path = '/activities/wheel',
|
||||
wheel.sort = 80,
|
||||
wheel.icon = 'casino',
|
||||
wheel.permission_code = 'wheel:view',
|
||||
wheel.visible = TRUE,
|
||||
wheel.updated_at_ms = @now_ms
|
||||
WHERE wheel.code = 'wheel';
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -287,6 +287,131 @@ CREATE TABLE IF NOT EXISTS lucky_draw_pool_stat_cursors (
|
||||
PRIMARY KEY (app_code, cursor_name)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物后台统计快照游标';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wheel_rule_versions (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
rule_version BIGINT NOT NULL COMMENT '不可变规则版本',
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否启用',
|
||||
draw_price_coins BIGINT NOT NULL COMMENT '单抽价格,金币',
|
||||
target_rtp_ppm BIGINT NOT NULL COMMENT '金币和礼物 RTP 目标,ppm',
|
||||
pool_rate_ppm BIGINT NOT NULL COMMENT '每笔消耗进入转盘基础奖池比例,ppm',
|
||||
settlement_window_draws BIGINT NOT NULL COMMENT 'RTP 观察窗口抽数',
|
||||
initial_pool_coins BIGINT NOT NULL DEFAULT 0 COMMENT '初始奖池水位',
|
||||
pool_reserve_coins BIGINT NOT NULL DEFAULT 0 COMMENT '奖池安全水位',
|
||||
max_single_rtp_payout BIGINT NOT NULL DEFAULT 0 COMMENT '单次计入 RTP 的最大返奖',
|
||||
effective_from_ms BIGINT NOT NULL COMMENT '生效时间,UTC epoch ms',
|
||||
created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '发布人',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id, rule_version),
|
||||
KEY idx_wheel_rule_versions_latest (app_code, wheel_id, rule_version),
|
||||
KEY idx_wheel_rule_versions_enabled (app_code, enabled, created_at_ms)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘规则版本表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wheel_prize_tiers (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
rule_version BIGINT NOT NULL COMMENT '规则版本',
|
||||
tier_id VARCHAR(96) NOT NULL COMMENT '奖档 ID',
|
||||
display_name VARCHAR(128) NOT NULL DEFAULT '' COMMENT '展示名称快照',
|
||||
reward_type VARCHAR(32) NOT NULL COMMENT 'coin/gift/prop/dress',
|
||||
reward_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '礼物或道具资源 ID',
|
||||
reward_count BIGINT NOT NULL DEFAULT 1 COMMENT '奖励数量',
|
||||
reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '金币奖励金额',
|
||||
rtp_value_coins BIGINT NOT NULL DEFAULT 0 COMMENT '计入 RTP 的奖励价值;道具装扮强制为 0',
|
||||
weight_ppm BIGINT NOT NULL COMMENT '随机权重,ppm 口径',
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
|
||||
metadata_json JSON NOT NULL COMMENT '奖品展示和发放扩展快照',
|
||||
PRIMARY KEY (app_code, wheel_id, rule_version, tier_id),
|
||||
KEY idx_wheel_prize_tiers_rule (app_code, wheel_id, rule_version)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘奖档表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wheel_rtp_windows (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
window_index BIGINT NOT NULL COMMENT 'RTP 窗口序号',
|
||||
target_rtp_ppm BIGINT NOT NULL COMMENT '窗口目标 RTP',
|
||||
control_window_draws BIGINT NOT NULL COMMENT '窗口抽数',
|
||||
paid_draws BIGINT NOT NULL DEFAULT 0 COMMENT '已抽次数',
|
||||
wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '消耗金币',
|
||||
target_payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '目标返奖',
|
||||
actual_rtp_value_coins BIGINT NOT NULL DEFAULT 0 COMMENT '实际计入 RTP 的返奖',
|
||||
carry_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '整数除法余数',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'open' COMMENT 'open/closed',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id, window_index),
|
||||
KEY idx_wheel_rtp_windows_open (app_code, wheel_id, status, window_index)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘 RTP 观察窗口';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wheel_pools (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
balance BIGINT NOT NULL DEFAULT 0 COMMENT '当前可用水位',
|
||||
reserve_floor BIGINT NOT NULL DEFAULT 0 COMMENT '安全水位',
|
||||
total_in BIGINT NOT NULL DEFAULT 0 COMMENT '累计入池',
|
||||
total_out BIGINT NOT NULL DEFAULT 0 COMMENT '累计 RTP 价值支出',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘基础奖池';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wheel_draw_records (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
draw_id VARCHAR(128) NOT NULL COMMENT '抽奖 ID',
|
||||
command_id VARCHAR(128) NOT NULL COMMENT '幂等命令 ID',
|
||||
user_id BIGINT NOT NULL COMMENT '用户 ID',
|
||||
device_id VARCHAR(128) NOT NULL COMMENT '设备 ID',
|
||||
visible_region_id BIGINT NOT NULL DEFAULT 0 COMMENT '可见区域 ID',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
coin_spent BIGINT NOT NULL COMMENT '消耗金币',
|
||||
rule_version BIGINT NOT NULL COMMENT '规则版本',
|
||||
rtp_window_index BIGINT NOT NULL COMMENT 'RTP 窗口',
|
||||
selected_tier_id VARCHAR(96) NOT NULL COMMENT '命中奖档',
|
||||
reward_type VARCHAR(32) NOT NULL COMMENT 'coin/gift/prop/dress',
|
||||
reward_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '礼物或道具资源 ID',
|
||||
reward_count BIGINT NOT NULL DEFAULT 0 COMMENT '奖励数量',
|
||||
reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '金币奖励金额',
|
||||
rtp_value_coins BIGINT NOT NULL DEFAULT 0 COMMENT '计入 RTP 的奖励价值',
|
||||
candidate_tiers_json JSON NOT NULL COMMENT '候选过滤快照',
|
||||
rtp_snapshot_json JSON NOT NULL COMMENT 'RTP 快照',
|
||||
prize_metadata_json JSON NOT NULL COMMENT '奖品扩展快照',
|
||||
reward_status VARCHAR(32) NOT NULL COMMENT 'pending/granted/failed',
|
||||
reward_transaction_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '钱包或资产发放交易 ID',
|
||||
reward_failure_reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '发放失败原因',
|
||||
paid_at_ms BIGINT NOT NULL COMMENT '扣费时间,UTC epoch ms',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, draw_id),
|
||||
UNIQUE KEY uk_wheel_draw_command (app_code, command_id),
|
||||
KEY idx_wheel_draw_wheel (app_code, wheel_id, created_at_ms),
|
||||
KEY idx_wheel_draw_user (app_code, user_id, created_at_ms),
|
||||
KEY idx_wheel_draw_status (app_code, reward_status, updated_at_ms),
|
||||
KEY idx_wheel_draw_created (app_code, created_at_ms, draw_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘抽奖事实';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wheel_draw_stats (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
total_draws BIGINT NOT NULL DEFAULT 0 COMMENT '抽奖次数',
|
||||
unique_users BIGINT NOT NULL DEFAULT 0 COMMENT '参与用户数',
|
||||
total_spent_coins BIGINT NOT NULL DEFAULT 0 COMMENT '消耗金币',
|
||||
total_rtp_value_coins BIGINT NOT NULL DEFAULT 0 COMMENT '计入 RTP 的返奖价值',
|
||||
pending_draws BIGINT NOT NULL DEFAULT 0 COMMENT '待发放数量',
|
||||
granted_draws BIGINT NOT NULL DEFAULT 0 COMMENT '已发放数量',
|
||||
failed_draws BIGINT NOT NULL DEFAULT 0 COMMENT '发放失败数量',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘后台汇总统计';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wheel_draw_stat_users (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
user_id BIGINT NOT NULL COMMENT '用户 ID',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id, user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘统计用户去重';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS im_broadcast_outbox (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码,用于多租户隔离',
|
||||
event_id VARCHAR(128) NOT NULL COMMENT '事件幂等 ID',
|
||||
@ -1352,12 +1477,13 @@ CREATE TABLE IF NOT EXISTS agency_opening_cycles (
|
||||
CREATE TABLE IF NOT EXISTS agency_opening_cycle_rewards (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
cycle_id VARCHAR(96) NOT NULL COMMENT '代理开业周期 ID',
|
||||
rank_no INT NOT NULL COMMENT '榜单名次',
|
||||
rank_no INT NOT NULL COMMENT '档位序号',
|
||||
threshold_coin_spent BIGINT NOT NULL DEFAULT 0 COMMENT '命中该档需要的代理房间流水金币',
|
||||
reward_coin_amount BIGINT NOT NULL DEFAULT 0 COMMENT '奖励金币',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, cycle_id, rank_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='代理开业榜单奖励';
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='代理开业流水奖励档位';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agency_opening_applications (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
@ -1368,14 +1494,19 @@ CREATE TABLE IF NOT EXISTS agency_opening_applications (
|
||||
agency_name VARCHAR(128) NOT NULL DEFAULT '' COMMENT '代理名称快照',
|
||||
host_count INT NOT NULL DEFAULT 0 COMMENT '申请时有效主播数快照',
|
||||
agency_created_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '代理创建时间快照',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'applied' COMMENT 'applied/pending/granted/failed',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'applied' COMMENT 'applied/approved/pending/granted/failed/expired',
|
||||
score_coin_amount BIGINT NOT NULL DEFAULT 0 COMMENT '周期内开业流水金币',
|
||||
reward_rank_no INT NOT NULL DEFAULT 0 COMMENT '结算榜单名次',
|
||||
reward_threshold_coin_spent BIGINT NOT NULL DEFAULT 0 COMMENT '结算命中的流水阈值',
|
||||
reward_coin_amount BIGINT NOT NULL DEFAULT 0 COMMENT '结算奖励金币',
|
||||
wallet_command_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '钱包幂等命令',
|
||||
wallet_transaction_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '钱包交易 ID',
|
||||
failure_reason VARCHAR(512) NOT NULL DEFAULT '' COMMENT '失败原因',
|
||||
applied_at_ms BIGINT NOT NULL COMMENT '申请时间',
|
||||
approved_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '后台同意时间',
|
||||
score_start_ms BIGINT NOT NULL DEFAULT 0 COMMENT '计分开始时间',
|
||||
score_end_ms BIGINT NOT NULL DEFAULT 0 COMMENT '计分截止时间',
|
||||
reviewed_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '审核管理员',
|
||||
granted_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '发奖时间',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
|
||||
@ -40,7 +40,7 @@ CREATE TABLE IF NOT EXISTS agency_opening_applications (
|
||||
agency_name VARCHAR(128) NOT NULL DEFAULT '' COMMENT '代理名称快照',
|
||||
host_count INT NOT NULL DEFAULT 0 COMMENT '申请时有效主播数快照',
|
||||
agency_created_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '代理创建时间快照',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'applied' COMMENT 'applied/pending/granted/failed',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'applied' COMMENT 'applied/approved/pending/granted/failed/expired',
|
||||
score_coin_amount BIGINT NOT NULL DEFAULT 0 COMMENT '周期内开业流水金币',
|
||||
reward_rank_no INT NOT NULL DEFAULT 0 COMMENT '结算命中的档位序号',
|
||||
reward_threshold_coin_spent BIGINT NOT NULL DEFAULT 0 COMMENT '结算命中的流水阈值',
|
||||
@ -49,6 +49,10 @@ CREATE TABLE IF NOT EXISTS agency_opening_applications (
|
||||
wallet_transaction_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '钱包交易 ID',
|
||||
failure_reason VARCHAR(512) NOT NULL DEFAULT '' COMMENT '失败原因',
|
||||
applied_at_ms BIGINT NOT NULL COMMENT '申请时间',
|
||||
approved_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '后台同意时间',
|
||||
score_start_ms BIGINT NOT NULL DEFAULT 0 COMMENT '计分开始时间',
|
||||
score_end_ms BIGINT NOT NULL DEFAULT 0 COMMENT '计分截止时间',
|
||||
reviewed_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '审核管理员',
|
||||
granted_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '发奖时间',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
|
||||
@ -20,6 +20,8 @@ func registerGRPCServers(server *grpc.Server, services *serviceBundle) {
|
||||
activityv1.RegisterAdminAchievementServiceServer(server, grpcserver.NewAdminAchievementServer(services.achievement))
|
||||
activityv1.RegisterLuckyGiftServiceServer(server, grpcserver.NewLuckyGiftServer(services.luckyGift))
|
||||
activityv1.RegisterAdminLuckyGiftServiceServer(server, grpcserver.NewAdminLuckyGiftServer(services.luckyGift))
|
||||
activityv1.RegisterWheelServiceServer(server, grpcserver.NewWheelServer(services.wheel))
|
||||
activityv1.RegisterAdminWheelServiceServer(server, grpcserver.NewAdminWheelServer(services.wheel))
|
||||
activityv1.RegisterRegistrationRewardServiceServer(server, grpcserver.NewRegistrationRewardServer(services.registrationReward))
|
||||
activityv1.RegisterAdminRegistrationRewardServiceServer(server, grpcserver.NewAdminRegistrationRewardServer(services.registrationReward))
|
||||
activityv1.RegisterSevenDayCheckInServiceServer(server, grpcserver.NewSevenDayCheckInServer(services.sevenDayCheckIn))
|
||||
|
||||
@ -24,6 +24,7 @@ import (
|
||||
sevendaycheckinservice "hyapp/services/activity-service/internal/service/sevendaycheckin"
|
||||
taskservice "hyapp/services/activity-service/internal/service/task"
|
||||
weeklystarservice "hyapp/services/activity-service/internal/service/weeklystar"
|
||||
wheelservice "hyapp/services/activity-service/internal/service/wheel"
|
||||
mysqlstorage "hyapp/services/activity-service/internal/storage/mysql"
|
||||
)
|
||||
|
||||
@ -41,6 +42,7 @@ type serviceBundle struct {
|
||||
roomTurnoverReward *roomturnoverrewardservice.Service
|
||||
broadcast *broadcastservice.Service
|
||||
luckyGift *luckygiftservice.Service
|
||||
wheel *wheelservice.Service
|
||||
firstRechargeReward *firstrechargeservice.Service
|
||||
cumulativeRecharge *cumulativerechargeservice.Service
|
||||
inviteActivityReward *inviteactivityservice.Service
|
||||
@ -96,6 +98,7 @@ func buildServiceBundle(cfg config.Config, repository *mysqlstorage.Repository,
|
||||
luckygiftservice.WithRoomPublisher(tencentClient),
|
||||
luckygiftservice.WithRegionBroadcaster(broadcastSvc),
|
||||
)
|
||||
wheelSvc := wheelservice.New(repository, wheelservice.WithWallet(walletClient))
|
||||
firstRechargeRewardSvc := firstrechargeservice.New(repository, walletClient)
|
||||
cumulativeRechargeSvc := cumulativerechargeservice.New(repository, walletClient)
|
||||
inviteActivityRewardSvc := inviteactivityservice.New(repository, walletClient, activityclient.NewGRPCInviteAttributionSource(clients.userConn))
|
||||
@ -114,6 +117,7 @@ func buildServiceBundle(cfg config.Config, repository *mysqlstorage.Repository,
|
||||
roomTurnoverReward: roomTurnoverRewardSvc,
|
||||
broadcast: broadcastSvc,
|
||||
luckyGift: luckyGiftSvc,
|
||||
wheel: wheelSvc,
|
||||
firstRechargeReward: firstRechargeRewardSvc,
|
||||
cumulativeRecharge: cumulativeRechargeSvc,
|
||||
inviteActivityReward: inviteActivityRewardSvc,
|
||||
|
||||
@ -9,10 +9,12 @@ const (
|
||||
StatusSettling = "settling"
|
||||
StatusSettled = "settled"
|
||||
|
||||
ApplicationStatusApplied = "applied"
|
||||
ApplicationStatusPending = "pending"
|
||||
ApplicationStatusGranted = "granted"
|
||||
ApplicationStatusFailed = "failed"
|
||||
ApplicationStatusApplied = "applied"
|
||||
ApplicationStatusApproved = "approved"
|
||||
ApplicationStatusPending = "pending"
|
||||
ApplicationStatusGranted = "granted"
|
||||
ApplicationStatusFailed = "failed"
|
||||
ApplicationStatusExpired = "expired"
|
||||
|
||||
EventStatusConsumed = "consumed"
|
||||
EventStatusDuplicate = "duplicate"
|
||||
@ -86,6 +88,10 @@ type Application struct {
|
||||
WalletTransactionID string
|
||||
FailureReason string
|
||||
AppliedAtMS int64
|
||||
ApprovedAtMS int64
|
||||
ScoreStartMS int64
|
||||
ScoreEndMS int64
|
||||
ReviewedByAdminID int64
|
||||
GrantedAtMS int64
|
||||
CreatedAtMS int64
|
||||
UpdatedAtMS int64
|
||||
|
||||
@ -0,0 +1,130 @@
|
||||
package lotteryengine
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
PrizeKindCoin = "coin"
|
||||
PrizeKindGift = "gift"
|
||||
PrizeKindProp = "prop"
|
||||
PrizeKindDress = "dress"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoCandidate = errors.New("lottery candidate is empty")
|
||||
ErrInvalidWeight = errors.New("lottery candidate weight is invalid")
|
||||
)
|
||||
|
||||
// Candidate 是抽奖引擎唯一关心的奖档视图。
|
||||
// 业务模块负责在进入引擎前完成资格、奖池和风控过滤;引擎只保证权重随机和 RTP 计值口径一致。
|
||||
type Candidate struct {
|
||||
ID string
|
||||
Weight int64
|
||||
PrizeKind string
|
||||
RTPValueCoins int64
|
||||
}
|
||||
|
||||
// NormalizeCandidates 复制并清洗候选集,避免调用方的业务快照被引擎内部兜底权重改写。
|
||||
// 全部候选权重都为 0 时退化成等权随机,是为了兼容旧配置或脏数据;负权重直接拒绝,防止配置错误改变概率方向。
|
||||
func NormalizeCandidates(candidates []Candidate) ([]Candidate, error) {
|
||||
if len(candidates) == 0 {
|
||||
return nil, ErrNoCandidate
|
||||
}
|
||||
out := make([]Candidate, 0, len(candidates))
|
||||
var totalWeight int64
|
||||
for _, candidate := range candidates {
|
||||
if candidate.Weight < 0 {
|
||||
return nil, ErrInvalidWeight
|
||||
}
|
||||
candidate.PrizeKind = NormalizePrizeKind(candidate.PrizeKind)
|
||||
candidate.RTPValueCoins = NormalizeRTPValueCoins(candidate.PrizeKind, candidate.RTPValueCoins)
|
||||
if candidate.Weight > 0 {
|
||||
totalWeight += candidate.Weight
|
||||
out = append(out, candidate)
|
||||
}
|
||||
}
|
||||
if totalWeight > 0 {
|
||||
return out, nil
|
||||
}
|
||||
out = out[:0]
|
||||
for _, candidate := range candidates {
|
||||
candidate.PrizeKind = NormalizePrizeKind(candidate.PrizeKind)
|
||||
candidate.RTPValueCoins = NormalizeRTPValueCoins(candidate.PrizeKind, candidate.RTPValueCoins)
|
||||
candidate.Weight = 1
|
||||
out = append(out, candidate)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// SelectWeighted 从已经归一化的候选中按权重抽一档。
|
||||
// 随机源使用 crypto/rand,避免高价值奖档被时间种子或并发顺序预测。
|
||||
func SelectWeighted(candidates []Candidate) (Candidate, error) {
|
||||
normalized, err := NormalizeCandidates(candidates)
|
||||
if err != nil {
|
||||
return Candidate{}, err
|
||||
}
|
||||
var totalWeight int64
|
||||
for _, candidate := range normalized {
|
||||
totalWeight += candidate.Weight
|
||||
}
|
||||
if totalWeight <= 0 {
|
||||
return Candidate{}, ErrNoCandidate
|
||||
}
|
||||
index, err := secureIndex(totalWeight)
|
||||
if err != nil {
|
||||
return Candidate{}, err
|
||||
}
|
||||
for _, candidate := range normalized {
|
||||
if index < candidate.Weight {
|
||||
return candidate, nil
|
||||
}
|
||||
index -= candidate.Weight
|
||||
}
|
||||
return normalized[len(normalized)-1], nil
|
||||
}
|
||||
|
||||
// NormalizePrizeKind 把后台和活动配置里的同义奖品类型收敛到引擎内部口径。
|
||||
// prop 和 dress 都表示装扮/道具类权益,后续发放可以不同,但 RTP 口径必须一致归零。
|
||||
func NormalizePrizeKind(kind string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(kind)) {
|
||||
case PrizeKindCoin:
|
||||
return PrizeKindCoin
|
||||
case PrizeKindGift:
|
||||
return PrizeKindGift
|
||||
case PrizeKindProp, "item", "decoration", "resource":
|
||||
return PrizeKindProp
|
||||
case PrizeKindDress, "dress_up", "costume":
|
||||
return PrizeKindDress
|
||||
default:
|
||||
return strings.ToLower(strings.TrimSpace(kind))
|
||||
}
|
||||
}
|
||||
|
||||
// NormalizeRTPValueCoins 是转盘和其它抽奖共用的 RTP 计值入口。
|
||||
// 装扮/道具无论后台配置了多少展示价值,都不能进入 RTP 返奖分子;金币和礼物保留配置值,负数按 0 处理。
|
||||
func NormalizeRTPValueCoins(kind string, value int64) int64 {
|
||||
if value < 0 {
|
||||
value = 0
|
||||
}
|
||||
switch NormalizePrizeKind(kind) {
|
||||
case PrizeKindProp, PrizeKindDress:
|
||||
return 0
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
func secureIndex(totalWeight int64) (int64, error) {
|
||||
if totalWeight <= 0 {
|
||||
return 0, ErrNoCandidate
|
||||
}
|
||||
n, err := crand.Int(crand.Reader, big.NewInt(totalWeight))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return n.Int64(), nil
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package lotteryengine
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNormalizeCandidatesKeepsPositiveWeights(t *testing.T) {
|
||||
candidates, err := NormalizeCandidates([]Candidate{
|
||||
{ID: "zero", Weight: 0, PrizeKind: PrizeKindCoin, RTPValueCoins: 10},
|
||||
{ID: "coin", Weight: 7, PrizeKind: PrizeKindCoin, RTPValueCoins: 20},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NormalizeCandidates failed: %v", err)
|
||||
}
|
||||
if len(candidates) != 1 || candidates[0].ID != "coin" || candidates[0].Weight != 7 || candidates[0].RTPValueCoins != 20 {
|
||||
t.Fatalf("unexpected normalized candidates: %#v", candidates)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeCandidatesFallsBackToEqualWeight(t *testing.T) {
|
||||
candidates, err := NormalizeCandidates([]Candidate{
|
||||
{ID: "a", PrizeKind: PrizeKindCoin},
|
||||
{ID: "b", PrizeKind: PrizeKindGift},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NormalizeCandidates failed: %v", err)
|
||||
}
|
||||
if len(candidates) != 2 || candidates[0].Weight != 1 || candidates[1].Weight != 1 {
|
||||
t.Fatalf("zero-weight candidates should become equal-weight candidates: %#v", candidates)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeRTPValueCoinsForcesPropsAndDressToZero(t *testing.T) {
|
||||
tests := []string{PrizeKindProp, PrizeKindDress, "item", "decoration", "resource", "costume"}
|
||||
for _, kind := range tests {
|
||||
if got := NormalizeRTPValueCoins(kind, 999_999); got != 0 {
|
||||
t.Fatalf("kind %s should not count into RTP, got %d", kind, got)
|
||||
}
|
||||
}
|
||||
if got := NormalizeRTPValueCoins(PrizeKindCoin, 500); got != 500 {
|
||||
t.Fatalf("coin should keep rtp value, got %d", got)
|
||||
}
|
||||
if got := NormalizeRTPValueCoins(PrizeKindGift, -1); got != 0 {
|
||||
t.Fatalf("negative gift rtp value should clamp to zero, got %d", got)
|
||||
}
|
||||
}
|
||||
102
services/activity-service/internal/domain/wheel/wheel.go
Normal file
102
services/activity-service/internal/domain/wheel/wheel.go
Normal file
@ -0,0 +1,102 @@
|
||||
package wheel
|
||||
|
||||
const (
|
||||
StatusDraft = "draft"
|
||||
StatusActive = "active"
|
||||
StatusPending = "pending"
|
||||
StatusGranted = "granted"
|
||||
StatusFailed = "failed"
|
||||
|
||||
RewardTypeCoin = "coin"
|
||||
RewardTypeGift = "gift"
|
||||
RewardTypeProp = "prop"
|
||||
RewardTypeDress = "dress"
|
||||
|
||||
EventTypeWheelRewardSettlement = "WheelRewardSettlement"
|
||||
)
|
||||
|
||||
// RuleConfig 是转盘配置的不可变版本快照。
|
||||
// 金币和礼物可以配置 RTP 计值,道具/装扮即使有展示价值也必须在运行态归零。
|
||||
type RuleConfig struct {
|
||||
AppCode string
|
||||
WheelID string
|
||||
RuleVersion int64
|
||||
Enabled bool
|
||||
DrawPriceCoins int64
|
||||
TargetRTPPPM int64
|
||||
PoolRatePPM int64
|
||||
SettlementWindowDraws int64
|
||||
InitialPoolCoins int64
|
||||
PoolReserveCoins int64
|
||||
MaxSingleRTPPayout int64
|
||||
EffectiveFromMS int64
|
||||
CreatedByAdminID int64
|
||||
CreatedAtMS int64
|
||||
Tiers []Tier
|
||||
}
|
||||
|
||||
// Tier 是一个转盘奖档;RewardType 决定发放 owner 和 RTP 计值口径。
|
||||
type Tier struct {
|
||||
TierID string
|
||||
DisplayName string
|
||||
RewardType string
|
||||
RewardID string
|
||||
RewardCount int64
|
||||
RewardCoins int64
|
||||
RTPValueCoins int64
|
||||
WeightPPM int64
|
||||
Enabled bool
|
||||
MetadataJSON string
|
||||
}
|
||||
|
||||
type DrawCommand struct {
|
||||
CommandID string
|
||||
WheelID string
|
||||
UserID int64
|
||||
DeviceID string
|
||||
DrawCount int32
|
||||
CoinSpent int64
|
||||
PaidAtMS int64
|
||||
VisibleRegionID int64
|
||||
}
|
||||
|
||||
type DrawResult struct {
|
||||
DrawID string
|
||||
DrawIDs []string
|
||||
CommandID string
|
||||
WheelID string
|
||||
RuleVersion int64
|
||||
SelectedTierID string
|
||||
RewardType string
|
||||
RewardID string
|
||||
RewardCount int64
|
||||
RewardCoins int64
|
||||
RTPValueCoins int64
|
||||
RewardStatus string
|
||||
RTPWindowIndex int64
|
||||
ActualRTPPPM int64
|
||||
CreatedAtMS int64
|
||||
WalletTransactionID string
|
||||
CoinBalanceAfter int64
|
||||
MetadataJSON string
|
||||
}
|
||||
|
||||
type DrawSummary struct {
|
||||
WheelID string
|
||||
TotalDraws int64
|
||||
UniqueUsers int64
|
||||
TotalSpentCoins int64
|
||||
TotalRTPValueCoins int64
|
||||
ActualRTPPPM int64
|
||||
PendingDraws int64
|
||||
GrantedDraws int64
|
||||
FailedDraws int64
|
||||
}
|
||||
|
||||
type DrawQuery struct {
|
||||
WheelID string
|
||||
UserID int64
|
||||
Status string
|
||||
Page int32
|
||||
PageSize int32
|
||||
}
|
||||
@ -27,6 +27,7 @@ type Repository interface {
|
||||
FindCurrentAgencyOpeningCycle(ctx context.Context, nowMS int64) (domain.Cycle, bool, error)
|
||||
GetAgencyOpeningApplicationByOwner(ctx context.Context, ownerUserID int64) (domain.Application, bool, error)
|
||||
CreateAgencyOpeningApplication(ctx context.Context, cycle domain.Cycle, agency domain.AgencySnapshot, nowMS int64) (domain.Application, bool, error)
|
||||
ApproveAgencyOpeningApplication(ctx context.Context, applicationID string, operatorAdminID int64, nowMS int64) (domain.Application, error)
|
||||
ListAgencyOpeningApplications(ctx context.Context, query domain.ApplicationQuery) ([]domain.Application, int64, error)
|
||||
ConsumeAgencyOpeningGiftEvent(ctx context.Context, event domain.GiftEvent, nowMS int64) (domain.EventResult, error)
|
||||
ClaimDueAgencyOpeningCycles(ctx context.Context, workerID string, nowMS int64, lockTTL time.Duration, batchSize int32) ([]domain.Cycle, error)
|
||||
@ -163,6 +164,21 @@ func (s *Service) Apply(ctx context.Context, userID int64, commandID string) (do
|
||||
return s.repository.CreateAgencyOpeningApplication(ctx, qualification.Cycle, qualification.Agency, s.now().UTC().UnixMilli())
|
||||
}
|
||||
|
||||
func (s *Service) ApproveApplication(ctx context.Context, applicationID string, operatorAdminID int64) (domain.Application, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return domain.Application{}, err
|
||||
}
|
||||
applicationID = strings.TrimSpace(applicationID)
|
||||
if applicationID == "" {
|
||||
return domain.Application{}, xerr.New(xerr.InvalidArgument, "application_id is required")
|
||||
}
|
||||
if operatorAdminID <= 0 {
|
||||
return domain.Application{}, xerr.New(xerr.InvalidArgument, "operator_admin_id is required")
|
||||
}
|
||||
// 开业积分必须从后台同意这一刻重新开始计算,不能把用户申请后、审核前的房间礼物补进活动分。
|
||||
return s.repository.ApproveAgencyOpeningApplication(ctx, applicationID, operatorAdminID, s.now().UTC().UnixMilli())
|
||||
}
|
||||
|
||||
func (s *Service) ListApplications(ctx context.Context, query domain.ApplicationQuery) ([]domain.Application, int64, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return nil, 0, err
|
||||
|
||||
@ -141,6 +141,9 @@ func (r *agencyOpeningFakeRepo) GetAgencyOpeningApplicationByOwner(_ context.Con
|
||||
func (r *agencyOpeningFakeRepo) CreateAgencyOpeningApplication(context.Context, domain.Cycle, domain.AgencySnapshot, int64) (domain.Application, bool, error) {
|
||||
return domain.Application{}, false, nil
|
||||
}
|
||||
func (r *agencyOpeningFakeRepo) ApproveAgencyOpeningApplication(context.Context, string, int64, int64) (domain.Application, error) {
|
||||
return domain.Application{}, nil
|
||||
}
|
||||
func (r *agencyOpeningFakeRepo) ListAgencyOpeningApplications(context.Context, domain.ApplicationQuery) ([]domain.Application, int64, error) {
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
106
services/activity-service/internal/service/wheel/config.go
Normal file
106
services/activity-service/internal/service/wheel/config.go
Normal file
@ -0,0 +1,106 @@
|
||||
package wheel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"hyapp/pkg/xerr"
|
||||
lotteryengine "hyapp/services/activity-service/internal/domain/lotteryengine"
|
||||
domain "hyapp/services/activity-service/internal/domain/wheel"
|
||||
)
|
||||
|
||||
const defaultWheelID = "default"
|
||||
|
||||
func NormalizeWheelID(wheelID string) string {
|
||||
wheelID = strings.TrimSpace(wheelID)
|
||||
if wheelID == "" {
|
||||
return defaultWheelID
|
||||
}
|
||||
return wheelID
|
||||
}
|
||||
|
||||
// NormalizeRuleConfig 是转盘配置发布前的唯一收口。
|
||||
// 这里强制道具/装扮的 RTP 价值为 0,避免后台展示价值、运营估值或资源原价污染真实返奖率。
|
||||
func NormalizeRuleConfig(config domain.RuleConfig) domain.RuleConfig {
|
||||
config.AppCode = strings.TrimSpace(config.AppCode)
|
||||
config.WheelID = NormalizeWheelID(config.WheelID)
|
||||
normalized := make([]domain.Tier, 0, len(config.Tiers))
|
||||
for _, tier := range config.Tiers {
|
||||
tier.TierID = strings.TrimSpace(tier.TierID)
|
||||
tier.DisplayName = strings.TrimSpace(tier.DisplayName)
|
||||
tier.RewardType = lotteryengine.NormalizePrizeKind(tier.RewardType)
|
||||
tier.RewardID = strings.TrimSpace(tier.RewardID)
|
||||
tier.MetadataJSON = strings.TrimSpace(tier.MetadataJSON)
|
||||
if tier.MetadataJSON == "" {
|
||||
tier.MetadataJSON = "{}"
|
||||
}
|
||||
if tier.RewardCount <= 0 {
|
||||
tier.RewardCount = 1
|
||||
}
|
||||
tier.RTPValueCoins = lotteryengine.NormalizeRTPValueCoins(tier.RewardType, tier.RTPValueCoins)
|
||||
normalized = append(normalized, tier)
|
||||
}
|
||||
config.Tiers = normalized
|
||||
return config
|
||||
}
|
||||
|
||||
// ValidateRuleConfig 只验证运行所需的硬边界;概率是否满足产品预期由后台配置页负责展示和二次确认。
|
||||
func ValidateRuleConfig(config domain.RuleConfig) error {
|
||||
config = NormalizeRuleConfig(config)
|
||||
if config.WheelID == "" {
|
||||
return xerr.New(xerr.InvalidArgument, "wheel_id is required")
|
||||
}
|
||||
if config.DrawPriceCoins <= 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "draw_price_coins must be positive")
|
||||
}
|
||||
if config.TargetRTPPPM < 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "target_rtp_ppm must be non-negative")
|
||||
}
|
||||
if config.PoolRatePPM < 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "pool_rate_ppm must be non-negative")
|
||||
}
|
||||
if config.SettlementWindowDraws <= 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "settlement_window_draws must be positive")
|
||||
}
|
||||
if len(config.Tiers) == 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "wheel tiers are required")
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
var enabled bool
|
||||
for _, tier := range config.Tiers {
|
||||
if tier.TierID == "" {
|
||||
return xerr.New(xerr.InvalidArgument, "wheel tier_id is required")
|
||||
}
|
||||
if seen[tier.TierID] {
|
||||
return xerr.New(xerr.InvalidArgument, fmt.Sprintf("duplicate wheel tier_id: %s", tier.TierID))
|
||||
}
|
||||
seen[tier.TierID] = true
|
||||
if tier.WeightPPM < 0 {
|
||||
return xerr.New(xerr.InvalidArgument, fmt.Sprintf("wheel tier %s weight_ppm must be non-negative", tier.TierID))
|
||||
}
|
||||
switch tier.RewardType {
|
||||
case lotteryengine.PrizeKindCoin:
|
||||
if tier.RewardCoins < 0 {
|
||||
return xerr.New(xerr.InvalidArgument, fmt.Sprintf("wheel tier %s reward_coins must be non-negative", tier.TierID))
|
||||
}
|
||||
case lotteryengine.PrizeKindGift:
|
||||
if tier.RewardID == "" {
|
||||
return xerr.New(xerr.InvalidArgument, fmt.Sprintf("wheel tier %s gift reward_id is required", tier.TierID))
|
||||
}
|
||||
case lotteryengine.PrizeKindProp, lotteryengine.PrizeKindDress:
|
||||
if tier.RewardID == "" {
|
||||
return xerr.New(xerr.InvalidArgument, fmt.Sprintf("wheel tier %s prop reward_id is required", tier.TierID))
|
||||
}
|
||||
if tier.RTPValueCoins != 0 {
|
||||
return xerr.New(xerr.InvalidArgument, fmt.Sprintf("wheel tier %s prop rtp_value_coins must be zero", tier.TierID))
|
||||
}
|
||||
default:
|
||||
return xerr.New(xerr.InvalidArgument, fmt.Sprintf("unsupported wheel reward_type: %s", tier.RewardType))
|
||||
}
|
||||
enabled = enabled || tier.Enabled
|
||||
}
|
||||
if !enabled {
|
||||
return xerr.New(xerr.InvalidArgument, "wheel enabled tiers are required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package wheel
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
domain "hyapp/services/activity-service/internal/domain/wheel"
|
||||
)
|
||||
|
||||
func TestNormalizeRuleConfigForcesPropRTPValueToZero(t *testing.T) {
|
||||
config := NormalizeRuleConfig(domain.RuleConfig{
|
||||
WheelID: "classic",
|
||||
DrawPriceCoins: 100,
|
||||
SettlementWindowDraws: 1000,
|
||||
Tiers: []domain.Tier{
|
||||
{TierID: "dress", RewardType: "dress", RewardID: "frame_1", RTPValueCoins: 999999, WeightPPM: 1, Enabled: true},
|
||||
{TierID: "prop", RewardType: "item", RewardID: "car_1", RTPValueCoins: 888888, WeightPPM: 1, Enabled: true},
|
||||
{TierID: "coin", RewardType: "coin", RewardCoins: 100, RTPValueCoins: 100, WeightPPM: 1, Enabled: true},
|
||||
},
|
||||
})
|
||||
if config.Tiers[0].RTPValueCoins != 0 || config.Tiers[1].RTPValueCoins != 0 {
|
||||
t.Fatalf("prop and dress rtp values must be zero: %#v", config.Tiers)
|
||||
}
|
||||
if config.Tiers[2].RTPValueCoins != 100 {
|
||||
t.Fatalf("coin rtp value should be preserved: %#v", config.Tiers[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRuleConfigRejectsPropRTPValueAfterNormalizationByCallerMutation(t *testing.T) {
|
||||
config := NormalizeRuleConfig(domain.RuleConfig{
|
||||
WheelID: "classic",
|
||||
DrawPriceCoins: 100,
|
||||
SettlementWindowDraws: 1000,
|
||||
Tiers: []domain.Tier{
|
||||
{TierID: "prop", RewardType: "prop", RewardID: "car_1", WeightPPM: 1, Enabled: true},
|
||||
},
|
||||
})
|
||||
config.Tiers[0].RTPValueCoins = 100
|
||||
if err := ValidateRuleConfig(config); err != nil {
|
||||
t.Fatalf("ValidateRuleConfig should normalize prop rtp value before validation: %v", err)
|
||||
}
|
||||
}
|
||||
176
services/activity-service/internal/service/wheel/service.go
Normal file
176
services/activity-service/internal/service/wheel/service.go
Normal file
@ -0,0 +1,176 @@
|
||||
package wheel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
walletv1 "hyapp.local/api/proto/wallet/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/logx"
|
||||
"hyapp/pkg/xerr"
|
||||
domain "hyapp/services/activity-service/internal/domain/wheel"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
PublishWheelRuleConfig(ctx context.Context, config domain.RuleConfig, nowMS int64) (domain.RuleConfig, error)
|
||||
GetWheelRuleConfig(ctx context.Context, wheelID string) (domain.RuleConfig, bool, error)
|
||||
ExecuteWheelDraw(ctx context.Context, cmd domain.DrawCommand, nowMS int64) (domain.DrawResult, error)
|
||||
ListWheelDraws(ctx context.Context, query domain.DrawQuery) ([]domain.DrawResult, int64, error)
|
||||
GetWheelDrawSummary(ctx context.Context, query domain.DrawQuery) (domain.DrawSummary, error)
|
||||
MarkWheelDrawsGranted(ctx context.Context, appCode string, drawIDs []string, transactionID string, nowMS int64) error
|
||||
}
|
||||
|
||||
type WalletClient interface {
|
||||
CreditWheelReward(ctx context.Context, req *walletv1.CreditWheelRewardRequest, opts ...grpc.CallOption) (*walletv1.CreditWheelRewardResponse, error)
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
repository Repository
|
||||
wallet WalletClient
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
type Option func(*Service)
|
||||
|
||||
func WithWallet(client WalletClient) Option {
|
||||
return func(s *Service) {
|
||||
s.wallet = client
|
||||
}
|
||||
}
|
||||
|
||||
func New(repository Repository, options ...Option) *Service {
|
||||
service := &Service{repository: repository, now: time.Now}
|
||||
for _, option := range options {
|
||||
if option != nil {
|
||||
option(service)
|
||||
}
|
||||
}
|
||||
return service
|
||||
}
|
||||
|
||||
func (s *Service) SetClock(now func() time.Time) {
|
||||
if now != nil {
|
||||
s.now = now
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) Draw(ctx context.Context, cmd domain.DrawCommand) (domain.DrawResult, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
cmd.CommandID = strings.TrimSpace(cmd.CommandID)
|
||||
cmd.WheelID = NormalizeWheelID(cmd.WheelID)
|
||||
cmd.DeviceID = strings.TrimSpace(cmd.DeviceID)
|
||||
if cmd.DrawCount <= 0 {
|
||||
cmd.DrawCount = 1
|
||||
}
|
||||
if cmd.CommandID == "" || cmd.WheelID == "" || cmd.UserID <= 0 || cmd.DeviceID == "" || cmd.CoinSpent <= 0 {
|
||||
return domain.DrawResult{}, xerr.New(xerr.InvalidArgument, "wheel draw command is incomplete")
|
||||
}
|
||||
if cmd.PaidAtMS <= 0 {
|
||||
// paid_at_ms 来自钱包扣费事实;缺失时使用 UTC 服务端时间,保证 RTP 窗口和审计时间不受本地时区影响。
|
||||
cmd.PaidAtMS = s.now().UTC().UnixMilli()
|
||||
}
|
||||
result, err := s.repository.ExecuteWheelDraw(ctx, cmd, s.now().UTC().UnixMilli())
|
||||
if err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
return s.creditCoinRewardFastPath(ctx, cmd, result), nil
|
||||
}
|
||||
|
||||
func (s *Service) UpsertConfig(ctx context.Context, config domain.RuleConfig) (domain.RuleConfig, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
config = NormalizeRuleConfig(config)
|
||||
if err := ValidateRuleConfig(config); err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
return s.repository.PublishWheelRuleConfig(ctx, config, s.now().UTC().UnixMilli())
|
||||
}
|
||||
|
||||
func (s *Service) GetConfig(ctx context.Context, wheelID string) (domain.RuleConfig, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
config, exists, err := s.repository.GetWheelRuleConfig(ctx, NormalizeWheelID(wheelID))
|
||||
if err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
if !exists {
|
||||
return domain.RuleConfig{}, xerr.New(xerr.NotFound, "wheel config not found")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (s *Service) ListDraws(ctx context.Context, query domain.DrawQuery) ([]domain.DrawResult, int64, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return s.repository.ListWheelDraws(ctx, normalizeDrawQuery(query))
|
||||
}
|
||||
|
||||
func (s *Service) GetDrawSummary(ctx context.Context, query domain.DrawQuery) (domain.DrawSummary, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return domain.DrawSummary{}, err
|
||||
}
|
||||
return s.repository.GetWheelDrawSummary(ctx, normalizeDrawQuery(query))
|
||||
}
|
||||
|
||||
func (s *Service) creditCoinRewardFastPath(ctx context.Context, cmd domain.DrawCommand, result domain.DrawResult) domain.DrawResult {
|
||||
if result.RewardType != domain.RewardTypeCoin || result.RewardCoins <= 0 || result.RewardStatus == domain.StatusGranted || len(result.DrawIDs) != 1 {
|
||||
return result
|
||||
}
|
||||
if s.wallet == nil {
|
||||
logx.Warn(ctx, "wheel_reward_wallet_not_configured", slog.String("draw_id", result.DrawID))
|
||||
return result
|
||||
}
|
||||
resp, err := s.wallet.CreditWheelReward(appcode.WithContext(ctx, appcode.FromContext(ctx)), &walletv1.CreditWheelRewardRequest{
|
||||
CommandId: "wheel_reward:" + result.DrawID,
|
||||
AppCode: appcode.FromContext(ctx),
|
||||
TargetUserId: cmd.UserID,
|
||||
Amount: result.RewardCoins,
|
||||
DrawId: result.DrawID,
|
||||
WheelId: result.WheelID,
|
||||
SelectedTierId: result.SelectedTierID,
|
||||
Reason: "wheel_reward",
|
||||
VisibleRegionId: cmd.VisibleRegionID,
|
||||
})
|
||||
if err != nil {
|
||||
// 钱包不可用不能回滚已经确认的抽奖事实;pending 记录和 outbox 保留,后续补偿 worker 可以继续处理。
|
||||
logx.Error(ctx, "wheel_reward_fast_path_failed", err, slog.String("draw_id", result.DrawID), slog.String("command_id", result.CommandID))
|
||||
return result
|
||||
}
|
||||
result.RewardStatus = domain.StatusGranted
|
||||
result.WalletTransactionID = resp.GetTransactionId()
|
||||
result.CoinBalanceAfter = resp.GetBalance().GetAvailableAmount()
|
||||
if err := s.repository.MarkWheelDrawsGranted(appcode.WithContext(context.WithoutCancel(ctx), appcode.FromContext(ctx)), appcode.FromContext(ctx), result.DrawIDs, result.WalletTransactionID, s.now().UTC().UnixMilli()); err != nil {
|
||||
logx.Error(ctx, "wheel_reward_fast_path_mark_granted_failed", err, slog.String("draw_id", result.DrawID), slog.String("wallet_transaction_id", result.WalletTransactionID))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func normalizeDrawQuery(query domain.DrawQuery) domain.DrawQuery {
|
||||
query.WheelID = NormalizeWheelID(query.WheelID)
|
||||
query.Status = strings.TrimSpace(query.Status)
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 20
|
||||
}
|
||||
if query.PageSize > 100 {
|
||||
query.PageSize = 100
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
func (s *Service) requireRepository() error {
|
||||
if s == nil || s.repository == nil {
|
||||
return xerr.New(xerr.Unavailable, "wheel repository is not configured")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -44,7 +44,7 @@ func (r *Repository) ensureAgencyOpeningTables(ctx context.Context) error {
|
||||
agency_name VARCHAR(128) NOT NULL DEFAULT '' COMMENT '代理名称快照',
|
||||
host_count INT NOT NULL DEFAULT 0 COMMENT '申请时有效主播数快照',
|
||||
agency_created_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '代理创建时间快照',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'applied' COMMENT 'applied/pending/granted/failed',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'applied' COMMENT 'applied/approved/pending/granted/failed/expired',
|
||||
score_coin_amount BIGINT NOT NULL DEFAULT 0 COMMENT '历史字段名:周期内开业房间贡献值 HeatValue',
|
||||
reward_rank_no INT NOT NULL DEFAULT 0 COMMENT '结算命中的档位序号',
|
||||
reward_threshold_coin_spent BIGINT NOT NULL DEFAULT 0 COMMENT '结算命中的流水阈值',
|
||||
@ -53,6 +53,10 @@ func (r *Repository) ensureAgencyOpeningTables(ctx context.Context) error {
|
||||
wallet_transaction_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '钱包交易 ID',
|
||||
failure_reason VARCHAR(512) NOT NULL DEFAULT '' COMMENT '失败原因',
|
||||
applied_at_ms BIGINT NOT NULL COMMENT '申请时间',
|
||||
approved_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '后台同意时间',
|
||||
score_start_ms BIGINT NOT NULL DEFAULT 0 COMMENT '计分开始时间',
|
||||
score_end_ms BIGINT NOT NULL DEFAULT 0 COMMENT '计分截止时间',
|
||||
reviewed_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '审核管理员',
|
||||
granted_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '发奖时间',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
@ -105,6 +109,34 @@ func (r *Repository) ensureAgencyOpeningRewardTierColumns(ctx context.Context) e
|
||||
return err
|
||||
}
|
||||
}
|
||||
if exists, err := r.columnExists(ctx, "agency_opening_applications", "approved_at_ms"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := r.db.ExecContext(ctx, `ALTER TABLE agency_opening_applications ADD COLUMN approved_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '后台同意时间' AFTER applied_at_ms`); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if exists, err := r.columnExists(ctx, "agency_opening_applications", "score_start_ms"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := r.db.ExecContext(ctx, `ALTER TABLE agency_opening_applications ADD COLUMN score_start_ms BIGINT NOT NULL DEFAULT 0 COMMENT '计分开始时间' AFTER approved_at_ms`); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if exists, err := r.columnExists(ctx, "agency_opening_applications", "score_end_ms"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := r.db.ExecContext(ctx, `ALTER TABLE agency_opening_applications ADD COLUMN score_end_ms BIGINT NOT NULL DEFAULT 0 COMMENT '计分截止时间' AFTER score_start_ms`); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if exists, err := r.columnExists(ctx, "agency_opening_applications", "reviewed_by_admin_id"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := r.db.ExecContext(ctx, `ALTER TABLE agency_opening_applications ADD COLUMN reviewed_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '审核管理员' AFTER score_end_ms`); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -217,8 +217,8 @@ func (r *Repository) CreateAgencyOpeningApplication(ctx context.Context, cycle d
|
||||
INSERT IGNORE INTO agency_opening_applications (
|
||||
app_code, application_id, cycle_id, agency_id, agency_owner_user_id, agency_name, host_count, agency_created_at_ms,
|
||||
status, score_coin_amount, reward_rank_no, reward_threshold_coin_spent, reward_coin_amount, wallet_command_id, wallet_transaction_id, failure_reason,
|
||||
applied_at_ms, granted_at_ms, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, 0, 0, '', '', '', ?, 0, ?, ?)`,
|
||||
applied_at_ms, approved_at_ms, score_start_ms, score_end_ms, reviewed_by_admin_id, granted_at_ms, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, 0, 0, '', '', '', ?, 0, 0, 0, 0, 0, ?, ?)`,
|
||||
appcode.FromContext(ctx), applicationID, cycle.CycleID, agency.AgencyID, agency.OwnerUserID, agency.Name, agency.HostCount, agency.AgencyCreatedAtMS,
|
||||
domain.ApplicationStatusApplied, nowMS, nowMS, nowMS)
|
||||
if err != nil {
|
||||
@ -229,6 +229,71 @@ func (r *Repository) CreateAgencyOpeningApplication(ctx context.Context, cycle d
|
||||
return item, affected > 0 && ok, err
|
||||
}
|
||||
|
||||
func (r *Repository) ApproveAgencyOpeningApplication(ctx context.Context, applicationID string, operatorAdminID int64, nowMS int64) (domain.Application, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return domain.Application{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return domain.Application{}, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
var app domain.Application
|
||||
var cycleEndMS int64
|
||||
var cycleStatus string
|
||||
err = tx.QueryRowContext(ctx, agencyOpeningApplicationSelect()+`
|
||||
WHERE app_code = ? AND application_id = ?
|
||||
FOR UPDATE`, appcode.FromContext(ctx), strings.TrimSpace(applicationID)).Scan(
|
||||
&app.AppCode, &app.ApplicationID, &app.CycleID, &app.AgencyID, &app.AgencyOwnerUserID, &app.AgencyName,
|
||||
&app.HostCount, &app.AgencyCreatedAtMS, &app.Status, &app.ScoreCoinAmount, &app.RewardRankNo, &app.RewardThresholdCoin, &app.RewardCoinAmount,
|
||||
&app.WalletCommandID, &app.WalletTransactionID, &app.FailureReason, &app.AppliedAtMS, &app.ApprovedAtMS, &app.ScoreStartMS, &app.ScoreEndMS,
|
||||
&app.ReviewedByAdminID, &app.GrantedAtMS, &app.CreatedAtMS, &app.UpdatedAtMS)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return domain.Application{}, xerr.New(xerr.NotFound, "agency opening application not found")
|
||||
}
|
||||
return domain.Application{}, err
|
||||
}
|
||||
if err := tx.QueryRowContext(ctx, `
|
||||
SELECT status, end_ms
|
||||
FROM agency_opening_cycles
|
||||
WHERE app_code = ? AND cycle_id = ? AND activity_code = ?`, appcode.FromContext(ctx), app.CycleID, domain.ActivityCode).Scan(&cycleStatus, &cycleEndMS); err != nil {
|
||||
return domain.Application{}, err
|
||||
}
|
||||
if app.Status == domain.ApplicationStatusApproved {
|
||||
if err := tx.Commit(); err != nil {
|
||||
return domain.Application{}, err
|
||||
}
|
||||
return r.getAgencyOpeningApplication(ctx, app.ApplicationID)
|
||||
}
|
||||
if app.Status != domain.ApplicationStatusApplied {
|
||||
return domain.Application{}, xerr.New(xerr.Conflict, "application is not waiting for approval")
|
||||
}
|
||||
if cycleStatus != domain.StatusActive {
|
||||
return domain.Application{}, xerr.New(xerr.Conflict, "activity is not active")
|
||||
}
|
||||
scoreEndMS := nowMS + int64((24 * time.Hour).Milliseconds())
|
||||
if cycleEndMS > 0 && cycleEndMS < scoreEndMS {
|
||||
scoreEndMS = cycleEndMS
|
||||
}
|
||||
if scoreEndMS <= nowMS {
|
||||
return domain.Application{}, xerr.New(xerr.Conflict, "activity period is already ended")
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE agency_opening_applications
|
||||
SET status = ?, approved_at_ms = ?, score_start_ms = ?, score_end_ms = ?, reviewed_by_admin_id = ?, score_coin_amount = 0,
|
||||
failure_reason = '', updated_at_ms = ?
|
||||
WHERE app_code = ? AND application_id = ? AND status = ?`,
|
||||
domain.ApplicationStatusApproved, nowMS, nowMS, scoreEndMS, operatorAdminID, nowMS,
|
||||
appcode.FromContext(ctx), app.ApplicationID, domain.ApplicationStatusApplied); err != nil {
|
||||
return domain.Application{}, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return domain.Application{}, err
|
||||
}
|
||||
return r.getAgencyOpeningApplication(ctx, app.ApplicationID)
|
||||
}
|
||||
|
||||
func (r *Repository) ListAgencyOpeningApplications(ctx context.Context, query domain.ApplicationQuery) ([]domain.Application, int64, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return nil, 0, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
@ -274,17 +339,18 @@ func (r *Repository) ConsumeAgencyOpeningGiftEvent(ctx context.Context, event do
|
||||
err = tx.QueryRowContext(ctx, `
|
||||
SELECT app.app_code, app.application_id, app.cycle_id, app.agency_id, app.agency_owner_user_id, app.agency_name, app.host_count, app.agency_created_at_ms,
|
||||
app.status, app.score_coin_amount, app.reward_rank_no, app.reward_threshold_coin_spent, app.reward_coin_amount, app.wallet_command_id, app.wallet_transaction_id, app.failure_reason,
|
||||
app.applied_at_ms, app.granted_at_ms, app.created_at_ms, app.updated_at_ms
|
||||
app.applied_at_ms, app.approved_at_ms, app.score_start_ms, app.score_end_ms, app.reviewed_by_admin_id, app.granted_at_ms, app.created_at_ms, app.updated_at_ms
|
||||
FROM agency_opening_applications app
|
||||
INNER JOIN agency_opening_cycles cycle ON cycle.app_code = app.app_code AND cycle.cycle_id = app.cycle_id
|
||||
WHERE app.app_code = ? AND app.agency_owner_user_id = ? AND app.status IN (?, ?, ?) AND app.applied_at_ms <= ?
|
||||
WHERE app.app_code = ? AND app.agency_owner_user_id = ? AND app.status = ? AND app.score_start_ms <= ? AND app.score_end_ms > ?
|
||||
AND cycle.activity_code = ? AND cycle.status IN (?, ?) AND cycle.start_ms <= ? AND cycle.end_ms > ?
|
||||
ORDER BY app.applied_at_ms DESC
|
||||
LIMIT 1`, appcode.FromContext(ctx), event.RoomOwnerUserID, domain.ApplicationStatusApplied, domain.ApplicationStatusPending, domain.ApplicationStatusFailed, event.OccurredAtMS,
|
||||
LIMIT 1`, appcode.FromContext(ctx), event.RoomOwnerUserID, domain.ApplicationStatusApproved, event.OccurredAtMS, event.OccurredAtMS,
|
||||
domain.ActivityCode, domain.StatusActive, domain.StatusSettling, event.OccurredAtMS, event.OccurredAtMS).Scan(
|
||||
&app.AppCode, &app.ApplicationID, &app.CycleID, &app.AgencyID, &app.AgencyOwnerUserID, &app.AgencyName,
|
||||
&app.HostCount, &app.AgencyCreatedAtMS, &app.Status, &app.ScoreCoinAmount, &app.RewardRankNo, &app.RewardThresholdCoin, &app.RewardCoinAmount,
|
||||
&app.WalletCommandID, &app.WalletTransactionID, &app.FailureReason, &app.AppliedAtMS, &app.GrantedAtMS, &app.CreatedAtMS, &app.UpdatedAtMS)
|
||||
&app.WalletCommandID, &app.WalletTransactionID, &app.FailureReason, &app.AppliedAtMS, &app.ApprovedAtMS, &app.ScoreStartMS, &app.ScoreEndMS,
|
||||
&app.ReviewedByAdminID, &app.GrantedAtMS, &app.CreatedAtMS, &app.UpdatedAtMS)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return domain.EventResult{EventID: event.EventID, Status: domain.EventStatusSkipped}, tx.Commit()
|
||||
@ -370,10 +436,18 @@ func (r *Repository) PrepareAgencyOpeningSettlements(ctx context.Context, cycle
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
// 周期结算时仍未后台同意的申请没有有效 24 小时计分窗口,直接过期,不进入发奖队列。
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE agency_opening_applications
|
||||
SET status = ?, failure_reason = 'not approved before cycle ended', updated_at_ms = ?
|
||||
WHERE app_code = ? AND cycle_id = ? AND status = ?`,
|
||||
domain.ApplicationStatusExpired, nowMS, appcode.FromContext(ctx), cycle.CycleID, domain.ApplicationStatusApplied); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows, err := tx.QueryContext(ctx, agencyOpeningApplicationSelect()+`
|
||||
WHERE app_code = ? AND cycle_id = ? AND status IN (?, ?)
|
||||
ORDER BY score_coin_amount DESC, applied_at_ms ASC, agency_id ASC`,
|
||||
appcode.FromContext(ctx), cycle.CycleID, domain.ApplicationStatusApplied, domain.ApplicationStatusFailed)
|
||||
appcode.FromContext(ctx), cycle.CycleID, domain.ApplicationStatusApproved, domain.ApplicationStatusFailed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -405,7 +479,7 @@ func (r *Repository) PrepareAgencyOpeningSettlements(ctx context.Context, cycle
|
||||
WHERE app_code = ? AND application_id = ? AND status IN (?, ?)`,
|
||||
domain.ApplicationStatusGranted, domain.ApplicationStatusPending,
|
||||
reward.RankNo, reward.ThresholdCoinSpent, reward.RewardCoinAmount, walletCommandID, nowMS,
|
||||
appcode.FromContext(ctx), application.ApplicationID, domain.ApplicationStatusApplied, domain.ApplicationStatusFailed); err != nil {
|
||||
appcode.FromContext(ctx), application.ApplicationID, domain.ApplicationStatusApproved, domain.ApplicationStatusFailed); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -578,7 +652,7 @@ func agencyOpeningApplicationWhere(ctx context.Context, query domain.Application
|
||||
func agencyOpeningApplicationSelect() string {
|
||||
return `SELECT app_code, application_id, cycle_id, agency_id, agency_owner_user_id, agency_name, host_count, agency_created_at_ms,
|
||||
status, score_coin_amount, reward_rank_no, reward_threshold_coin_spent, reward_coin_amount, wallet_command_id, wallet_transaction_id, failure_reason,
|
||||
applied_at_ms, granted_at_ms, created_at_ms, updated_at_ms FROM agency_opening_applications`
|
||||
applied_at_ms, approved_at_ms, score_start_ms, score_end_ms, reviewed_by_admin_id, granted_at_ms, created_at_ms, updated_at_ms FROM agency_opening_applications`
|
||||
}
|
||||
|
||||
func scanAgencyOpeningCycle(row interface{ Scan(...any) error }) (domain.Cycle, error) {
|
||||
@ -593,7 +667,8 @@ func scanAgencyOpeningApplication(row interface{ Scan(...any) error }) (domain.A
|
||||
var item domain.Application
|
||||
err := row.Scan(&item.AppCode, &item.ApplicationID, &item.CycleID, &item.AgencyID, &item.AgencyOwnerUserID, &item.AgencyName,
|
||||
&item.HostCount, &item.AgencyCreatedAtMS, &item.Status, &item.ScoreCoinAmount, &item.RewardRankNo, &item.RewardThresholdCoin, &item.RewardCoinAmount,
|
||||
&item.WalletCommandID, &item.WalletTransactionID, &item.FailureReason, &item.AppliedAtMS, &item.GrantedAtMS, &item.CreatedAtMS, &item.UpdatedAtMS)
|
||||
&item.WalletCommandID, &item.WalletTransactionID, &item.FailureReason, &item.AppliedAtMS, &item.ApprovedAtMS, &item.ScoreStartMS, &item.ScoreEndMS,
|
||||
&item.ReviewedByAdminID, &item.GrantedAtMS, &item.CreatedAtMS, &item.UpdatedAtMS)
|
||||
return item, err
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,114 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"hyapp/internal/testutil/mysqlschema"
|
||||
"hyapp/pkg/appcode"
|
||||
domain "hyapp/services/activity-service/internal/domain/agencyopening"
|
||||
)
|
||||
|
||||
func TestAgencyOpeningScoresOnlyAfterApprovalWithinWindow(t *testing.T) {
|
||||
schema := mysqlschema.New(t, mysqlschema.Config{
|
||||
EnvVar: "ACTIVITY_SERVICE_MYSQL_TEST_DSN",
|
||||
InitDBPath: mysqlschema.InitDBPath(t, mysqlschema.CallerFile(t, 1), "..", "..", "..", "deploy", "mysql", "initdb", "001_activity_service.sql"),
|
||||
DatabasePrefix: "hyapp_activity_agency_opening_test",
|
||||
})
|
||||
repository, err := Open(context.Background(), schema.DSN)
|
||||
if err != nil {
|
||||
t.Fatalf("open repository: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = repository.Close() })
|
||||
|
||||
ctx := appcode.WithContext(context.Background(), "lalu")
|
||||
const (
|
||||
cycleID = "cycle-window"
|
||||
applicationID = "application-window"
|
||||
ownerUserID = int64(42001)
|
||||
nowMS = int64(10_000)
|
||||
)
|
||||
_, err = repository.db.ExecContext(ctx, `
|
||||
INSERT INTO agency_opening_cycles (
|
||||
app_code, cycle_id, activity_code, title, status, start_ms, end_ms, min_host_count, max_agency_age_days,
|
||||
created_by_admin_id, updated_by_admin_id, settled_at_ms, locked_by, lock_until_ms, created_at_ms, updated_at_ms
|
||||
) VALUES ('lalu', ?, ?, 'window test', ?, 1, ?, 10, 30, 1, 1, 0, '', 0, ?, ?)`,
|
||||
cycleID, domain.ActivityCode, domain.StatusActive, nowMS+int64((48*60*60*1000)), nowMS, nowMS,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("seed cycle: %v", err)
|
||||
}
|
||||
_, err = repository.db.ExecContext(ctx, `
|
||||
INSERT INTO agency_opening_applications (
|
||||
app_code, application_id, cycle_id, agency_id, agency_owner_user_id, agency_name, host_count, agency_created_at_ms,
|
||||
status, score_coin_amount, reward_rank_no, reward_threshold_coin_spent, reward_coin_amount,
|
||||
wallet_command_id, wallet_transaction_id, failure_reason, applied_at_ms, approved_at_ms,
|
||||
score_start_ms, score_end_ms, reviewed_by_admin_id, granted_at_ms, created_at_ms, updated_at_ms
|
||||
) VALUES ('lalu', ?, ?, 8001, ?, 'Window Agency', 12, 1, ?, 0, 0, 0, 0, '', '', '', ?, 0, 0, 0, 0, 0, ?, ?)`,
|
||||
applicationID, cycleID, ownerUserID, domain.ApplicationStatusApplied, nowMS-1000, nowMS, nowMS,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("seed application: %v", err)
|
||||
}
|
||||
|
||||
beforeApproval, err := repository.ConsumeAgencyOpeningGiftEvent(ctx, domain.GiftEvent{
|
||||
EventID: "gift-before-approval",
|
||||
RoomOwnerUserID: ownerUserID,
|
||||
TargetUserID: 99,
|
||||
CoinSpent: 700,
|
||||
OccurredAtMS: nowMS + 100,
|
||||
}, nowMS+100)
|
||||
if err != nil {
|
||||
t.Fatalf("consume before approval: %v", err)
|
||||
}
|
||||
if beforeApproval.Status != domain.EventStatusSkipped {
|
||||
t.Fatalf("event before approval must be skipped, got %s", beforeApproval.Status)
|
||||
}
|
||||
|
||||
approved, err := repository.ApproveAgencyOpeningApplication(ctx, applicationID, 77, nowMS+200)
|
||||
if err != nil {
|
||||
t.Fatalf("approve application: %v", err)
|
||||
}
|
||||
wantScoreEnd := nowMS + 200 + int64((24 * 60 * 60 * 1000))
|
||||
if approved.Status != domain.ApplicationStatusApproved || approved.ScoreStartMS != nowMS+200 || approved.ScoreEndMS != wantScoreEnd || approved.ReviewedByAdminID != 77 {
|
||||
t.Fatalf("unexpected approved application: %+v", approved)
|
||||
}
|
||||
|
||||
insideWindow, err := repository.ConsumeAgencyOpeningGiftEvent(ctx, domain.GiftEvent{
|
||||
EventID: "gift-inside-window",
|
||||
RoomOwnerUserID: ownerUserID,
|
||||
TargetUserID: 100,
|
||||
CoinSpent: 900,
|
||||
OccurredAtMS: nowMS + 300,
|
||||
}, nowMS+300)
|
||||
if err != nil {
|
||||
t.Fatalf("consume inside window: %v", err)
|
||||
}
|
||||
if insideWindow.Status != domain.EventStatusConsumed {
|
||||
t.Fatalf("event inside approved window must be consumed, got %s", insideWindow.Status)
|
||||
}
|
||||
|
||||
afterWindow, err := repository.ConsumeAgencyOpeningGiftEvent(ctx, domain.GiftEvent{
|
||||
EventID: "gift-after-window",
|
||||
RoomOwnerUserID: ownerUserID,
|
||||
TargetUserID: 101,
|
||||
CoinSpent: 1200,
|
||||
OccurredAtMS: wantScoreEnd,
|
||||
}, wantScoreEnd)
|
||||
if err != nil {
|
||||
t.Fatalf("consume after window: %v", err)
|
||||
}
|
||||
if afterWindow.Status != domain.EventStatusSkipped {
|
||||
t.Fatalf("event at score_end must be skipped, got %s", afterWindow.Status)
|
||||
}
|
||||
|
||||
var score int64
|
||||
if err := repository.db.QueryRowContext(ctx, `
|
||||
SELECT score_coin_amount FROM agency_opening_applications
|
||||
WHERE app_code = 'lalu' AND application_id = ?`, applicationID).Scan(&score); err != nil {
|
||||
t.Fatalf("read final score: %v", err)
|
||||
}
|
||||
if score != 900 {
|
||||
t.Fatalf("only the inside-window event should score, got %d", score)
|
||||
}
|
||||
}
|
||||
@ -2,14 +2,12 @@ package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha1"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -17,6 +15,7 @@ import (
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/idgen"
|
||||
"hyapp/pkg/xerr"
|
||||
lotteryengine "hyapp/services/activity-service/internal/domain/lotteryengine"
|
||||
domain "hyapp/services/activity-service/internal/domain/luckygift"
|
||||
)
|
||||
|
||||
@ -2684,7 +2683,6 @@ func (r *Repository) selectLuckyCandidate(config domain.Config, pool string, pla
|
||||
limited := map[string]bool{}
|
||||
|
||||
baseCandidates := make([]luckyCandidate, 0, len(config.Tiers))
|
||||
var totalWeight int64
|
||||
for _, tier := range config.Tiers {
|
||||
// 体验池决定当前用户可见奖档;权重必须保持后台配置,RTP 缺口只进入监控口径,不能反向改本次概率。
|
||||
if tier.Pool != pool || !tier.Enabled {
|
||||
@ -2715,26 +2713,34 @@ func (r *Repository) selectLuckyCandidate(config domain.Config, pool string, pla
|
||||
})
|
||||
}
|
||||
// 正常运行只使用后台配置概率;奖池和风控只删除“本事务不能支付”的候选,不插值、不补缺口。
|
||||
candidates := luckyConfiguredWeightCandidates(baseCandidates)
|
||||
for _, candidate := range candidates {
|
||||
totalWeight += candidate.Weight
|
||||
}
|
||||
if len(candidates) == 0 {
|
||||
if len(baseCandidates) == 0 {
|
||||
// 全部正奖档都被奖池或风控剪掉时,本次只能落 0 倍;不能强行透支,也不能生成修正档改变概率。
|
||||
return luckyCandidate{TierID: "no_payable_tier", Source: domain.SourceBaseRTP, Pool: pool}, limited, nil
|
||||
}
|
||||
// 使用 crypto/rand 生成随机落点;候选集合已经全部可支付,随机后不再做业务降级。
|
||||
index, err := luckySecureIndex(totalWeight)
|
||||
engineCandidates := make([]lotteryengine.Candidate, 0, len(baseCandidates))
|
||||
candidateByID := make(map[string]luckyCandidate, len(baseCandidates))
|
||||
for _, candidate := range baseCandidates {
|
||||
engineCandidates = append(engineCandidates, lotteryengine.Candidate{
|
||||
ID: candidate.TierID,
|
||||
Weight: candidate.Weight,
|
||||
PrizeKind: lotteryengine.PrizeKindCoin,
|
||||
RTPValueCoins: candidate.BaseReward,
|
||||
})
|
||||
candidateByID[candidate.TierID] = candidate
|
||||
}
|
||||
// 使用通用引擎生成随机落点;候选集合已经全部可支付,随机后不再做业务降级。
|
||||
selected, err := lotteryengine.SelectWeighted(engineCandidates)
|
||||
if err != nil {
|
||||
return luckyCandidate{}, limited, err
|
||||
}
|
||||
for _, candidate := range candidates {
|
||||
if index < candidate.Weight {
|
||||
return candidate, limited, nil
|
||||
if candidate, ok := candidateByID[selected.ID]; ok {
|
||||
if candidate.Weight <= 0 {
|
||||
// 通用引擎会把全 0 权重脏数据退化为等权;这里同步返回权重快照,方便后台审计看到实际兜底口径。
|
||||
candidate.Weight = selected.Weight
|
||||
}
|
||||
index -= candidate.Weight
|
||||
return candidate, limited, nil
|
||||
}
|
||||
return candidates[len(candidates)-1], limited, nil
|
||||
return luckyCandidate{}, limited, xerr.New(xerr.Internal, "lottery engine selected unknown lucky tier")
|
||||
}
|
||||
|
||||
func (r *Repository) getLuckyDrawByCommand(ctx context.Context, tx *sql.Tx, appCode, commandID string, forUpdate bool) (domain.DrawResult, bool, error) {
|
||||
@ -2817,23 +2823,26 @@ func luckyEquivalentDraws(cumulativeWagerCoins int64, referencePrice int64) int6
|
||||
}
|
||||
|
||||
func luckyConfiguredWeightCandidates(candidates []luckyCandidate) []luckyCandidate {
|
||||
out := make([]luckyCandidate, 0, len(candidates))
|
||||
var totalWeight int64
|
||||
engineCandidates := make([]lotteryengine.Candidate, 0, len(candidates))
|
||||
byID := make(map[string]luckyCandidate, len(candidates))
|
||||
for _, candidate := range candidates {
|
||||
if candidate.Weight <= 0 {
|
||||
continue
|
||||
}
|
||||
totalWeight += candidate.Weight
|
||||
out = append(out, candidate)
|
||||
engineCandidates = append(engineCandidates, lotteryengine.Candidate{
|
||||
ID: candidate.TierID,
|
||||
Weight: candidate.Weight,
|
||||
PrizeKind: lotteryengine.PrizeKindCoin,
|
||||
RTPValueCoins: candidate.BaseReward,
|
||||
})
|
||||
byID[candidate.TierID] = candidate
|
||||
}
|
||||
if totalWeight > 0 {
|
||||
return out
|
||||
normalized, err := lotteryengine.NormalizeCandidates(engineCandidates)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
// 老数据或脏配置可能没有权重;为了让抽奖继续暴露结果而不是空候选,退化成等权随机。
|
||||
out = candidates[:0]
|
||||
for _, candidate := range candidates {
|
||||
candidate.Weight = 1
|
||||
out = append(out, candidate)
|
||||
out := make([]luckyCandidate, 0, len(normalized))
|
||||
for _, candidate := range normalized {
|
||||
item := byID[candidate.ID]
|
||||
item.Weight = candidate.Weight
|
||||
out = append(out, item)
|
||||
}
|
||||
return out
|
||||
}
|
||||
@ -2959,17 +2968,6 @@ func luckyRTPPPM(wager, payout int64) int64 {
|
||||
return payout * luckyPPMScale / wager
|
||||
}
|
||||
|
||||
func luckySecureIndex(totalWeight int64) (int64, error) {
|
||||
if totalWeight <= 0 {
|
||||
return 0, xerr.New(xerr.InvalidArgument, "candidate weight is empty")
|
||||
}
|
||||
n, err := crand.Int(crand.Reader, big.NewInt(totalWeight))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return n.Int64(), nil
|
||||
}
|
||||
|
||||
func luckySQLPlaceholders(count int) string {
|
||||
// database/sql 不支持把 slice 直接绑定到 IN (?),这里生成受控占位符而不是拼接业务值。
|
||||
if count <= 0 {
|
||||
|
||||
@ -78,6 +78,9 @@ func (r *Repository) Migrate(ctx context.Context) error {
|
||||
if err := r.ensureDefaultLuckyGiftRules(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureWheelTables(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureRoomTurnoverRewardTables(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -0,0 +1,817 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/idgen"
|
||||
"hyapp/pkg/xerr"
|
||||
lotteryengine "hyapp/services/activity-service/internal/domain/lotteryengine"
|
||||
domain "hyapp/services/activity-service/internal/domain/wheel"
|
||||
)
|
||||
|
||||
const wheelPPMScale int64 = 1_000_000
|
||||
|
||||
type wheelRTPWindow struct {
|
||||
WheelID string
|
||||
WindowIndex int64
|
||||
TargetRTPPPM int64
|
||||
ControlDraws int64
|
||||
PaidDraws int64
|
||||
WagerCoins int64
|
||||
TargetPayout int64
|
||||
ActualRTPValue int64
|
||||
CarryPPM int64
|
||||
Status string
|
||||
}
|
||||
|
||||
type wheelPool struct {
|
||||
WheelID string
|
||||
Balance int64
|
||||
ReserveFloor int64
|
||||
TotalIn int64
|
||||
TotalOut int64
|
||||
}
|
||||
|
||||
type wheelCandidate struct {
|
||||
Tier domain.Tier
|
||||
}
|
||||
|
||||
// PublishWheelRuleConfig 新增转盘不可变配置版本;历史 draw record 永远引用旧版本,避免后台改配置后审计口径漂移。
|
||||
func (r *Repository) PublishWheelRuleConfig(ctx context.Context, config domain.RuleConfig, nowMS int64) (domain.RuleConfig, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return domain.RuleConfig{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
appCode := appcode.FromContext(ctx)
|
||||
config.AppCode = appCode
|
||||
config.WheelID = normalizeWheelID(config.WheelID)
|
||||
config.Tiers = normalizeWheelTiers(config.Tiers)
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
var latest sql.NullInt64
|
||||
if err := tx.QueryRowContext(ctx, `
|
||||
SELECT MAX(rule_version)
|
||||
FROM wheel_rule_versions
|
||||
WHERE app_code = ? AND wheel_id = ?
|
||||
FOR UPDATE`,
|
||||
appCode, config.WheelID,
|
||||
).Scan(&latest); err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
if latest.Valid {
|
||||
config.RuleVersion = latest.Int64 + 1
|
||||
} else {
|
||||
config.RuleVersion = 1
|
||||
}
|
||||
if config.EffectiveFromMS <= 0 {
|
||||
config.EffectiveFromMS = nowMS
|
||||
}
|
||||
config.CreatedAtMS = nowMS
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO wheel_rule_versions (
|
||||
app_code, wheel_id, rule_version, enabled, draw_price_coins, target_rtp_ppm, pool_rate_ppm,
|
||||
settlement_window_draws, initial_pool_coins, pool_reserve_coins, max_single_rtp_payout,
|
||||
effective_from_ms, created_by_admin_id, created_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
appCode, config.WheelID, config.RuleVersion, config.Enabled, config.DrawPriceCoins, config.TargetRTPPPM, config.PoolRatePPM,
|
||||
config.SettlementWindowDraws, config.InitialPoolCoins, config.PoolReserveCoins, config.MaxSingleRTPPayout,
|
||||
config.EffectiveFromMS, config.CreatedByAdminID, nowMS,
|
||||
); err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
for _, tier := range config.Tiers {
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO wheel_prize_tiers (
|
||||
app_code, wheel_id, rule_version, tier_id, display_name, reward_type, reward_id, reward_count,
|
||||
reward_coins, rtp_value_coins, weight_ppm, enabled, metadata_json
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
appCode, config.WheelID, config.RuleVersion, tier.TierID, tier.DisplayName, tier.RewardType, tier.RewardID, tier.RewardCount,
|
||||
tier.RewardCoins, tier.RTPValueCoins, tier.WeightPPM, tier.Enabled, wheelMetadataJSON(tier.MetadataJSON),
|
||||
); err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return domain.RuleConfig{}, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetWheelRuleConfig(ctx context.Context, wheelID string) (domain.RuleConfig, bool, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return domain.RuleConfig{}, false, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
return r.getWheelRuleConfig(ctx, r.db, appcode.FromContext(ctx), normalizeWheelID(wheelID), false)
|
||||
}
|
||||
|
||||
// ExecuteWheelDraw 是转盘线上主事务:扣费事实已发生,事务内只做命中奖档、RTP 观察、奖池扣减和发放 outbox。
|
||||
func (r *Repository) ExecuteWheelDraw(ctx context.Context, cmd domain.DrawCommand, nowMS int64) (domain.DrawResult, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return domain.DrawResult{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
cmd.WheelID = normalizeWheelID(cmd.WheelID)
|
||||
if cmd.DrawCount <= 0 {
|
||||
cmd.DrawCount = 1
|
||||
}
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
appCode := appcode.FromContext(ctx)
|
||||
existing, complete, err := r.collectWheelDrawsByCommand(ctx, tx, appCode, cmd.CommandID, cmd.DrawCount)
|
||||
if err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
if complete {
|
||||
return aggregateWheelDrawResults(cmd, existing), nil
|
||||
}
|
||||
if len(existing) > 0 {
|
||||
return domain.DrawResult{}, xerr.New(xerr.Conflict, "partial wheel draw command exists")
|
||||
}
|
||||
config, exists, err := r.getWheelRuleConfig(ctx, tx, appCode, cmd.WheelID, true)
|
||||
if err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
if !exists || !config.Enabled {
|
||||
return domain.DrawResult{}, xerr.New(xerr.Conflict, "wheel is disabled")
|
||||
}
|
||||
if cmd.CoinSpent <= 0 || cmd.UserID <= 0 || strings.TrimSpace(cmd.CommandID) == "" || strings.TrimSpace(cmd.DeviceID) == "" {
|
||||
return domain.DrawResult{}, xerr.New(xerr.InvalidArgument, "wheel draw command is incomplete")
|
||||
}
|
||||
expectedSpent := config.DrawPriceCoins * int64(cmd.DrawCount)
|
||||
if cmd.CoinSpent != expectedSpent {
|
||||
return domain.DrawResult{}, xerr.New(xerr.InvalidArgument, "wheel draw coin_spent does not match current price")
|
||||
}
|
||||
if cmd.PaidAtMS <= 0 {
|
||||
cmd.PaidAtMS = nowMS
|
||||
}
|
||||
window, err := r.getOpenWheelRTPWindow(ctx, tx, appCode, config, nowMS)
|
||||
if err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
pool, err := r.getOrCreateWheelPool(ctx, tx, appCode, config, nowMS)
|
||||
if err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
results := make([]domain.DrawResult, 0, cmd.DrawCount)
|
||||
var totalPoolIn, totalPoolOut int64
|
||||
for i := int32(1); i <= cmd.DrawCount; i++ {
|
||||
unitSpent := luckyDrawUnitSpend(cmd.CoinSpent, cmd.DrawCount, i)
|
||||
totalPoolIn += unitSpent * config.PoolRatePPM / wheelPPMScale
|
||||
pool.Balance += unitSpent * config.PoolRatePPM / wheelPPMScale
|
||||
subCommand := wheelSubCommandID(cmd.CommandID, i, cmd.DrawCount)
|
||||
result, poolOut, err := r.executeSingleWheelDraw(ctx, tx, appCode, cmd, subCommand, unitSpent, config, &window, &pool, nowMS)
|
||||
if err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
totalPoolOut += poolOut
|
||||
results = append(results, result)
|
||||
}
|
||||
if err := r.persistWheelPoolDelta(ctx, tx, appCode, config.WheelID, totalPoolIn, totalPoolOut, nowMS); err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
if err := r.updateWheelStats(ctx, tx, appCode, config.WheelID, cmd.UserID, cmd.CoinSpent, results, nowMS); err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return domain.DrawResult{}, err
|
||||
}
|
||||
return aggregateWheelDrawResults(cmd, results), nil
|
||||
}
|
||||
|
||||
func (r *Repository) ListWheelDraws(ctx context.Context, query domain.DrawQuery) ([]domain.DrawResult, int64, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return nil, 0, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
whereSQL, args := wheelDrawWhereClause(appcode.FromContext(ctx), query)
|
||||
var total int64
|
||||
if err := r.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM wheel_draw_records WHERE `+whereSQL, args...).Scan(&total); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
page, pageSize := normalizeWheelPage(query.Page, query.PageSize)
|
||||
args = append(args, int(pageSize), int((page-1)*pageSize))
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT draw_id, command_id, wheel_id, rule_version, selected_tier_id, reward_type, reward_id,
|
||||
reward_count, reward_coins, rtp_value_coins, reward_status, reward_transaction_id,
|
||||
rtp_window_index, created_at_ms, COALESCE(CAST(prize_metadata_json AS CHAR), '{}')
|
||||
FROM wheel_draw_records
|
||||
WHERE `+whereSQL+`
|
||||
ORDER BY created_at_ms DESC, draw_id DESC
|
||||
LIMIT ? OFFSET ?`, args...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := make([]domain.DrawResult, 0, pageSize)
|
||||
for rows.Next() {
|
||||
var item domain.DrawResult
|
||||
if err := rows.Scan(&item.DrawID, &item.CommandID, &item.WheelID, &item.RuleVersion, &item.SelectedTierID, &item.RewardType, &item.RewardID,
|
||||
&item.RewardCount, &item.RewardCoins, &item.RTPValueCoins, &item.RewardStatus, &item.WalletTransactionID,
|
||||
&item.RTPWindowIndex, &item.CreatedAtMS, &item.MetadataJSON); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
item.DrawIDs = []string{item.DrawID}
|
||||
items = append(items, item)
|
||||
}
|
||||
return items, total, rows.Err()
|
||||
}
|
||||
|
||||
func (r *Repository) GetWheelDrawSummary(ctx context.Context, query domain.DrawQuery) (domain.DrawSummary, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return domain.DrawSummary{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
if query.UserID <= 0 && strings.TrimSpace(query.Status) == "" {
|
||||
return r.getWheelDrawSummaryFromStats(ctx, query)
|
||||
}
|
||||
return r.getWheelDrawSummaryFromRecords(ctx, query)
|
||||
}
|
||||
|
||||
func (r *Repository) getWheelDrawSummaryFromRecords(ctx context.Context, query domain.DrawQuery) (domain.DrawSummary, error) {
|
||||
whereSQL, args := wheelDrawWhereClause(appcode.FromContext(ctx), query)
|
||||
var summary domain.DrawSummary
|
||||
summary.WheelID = normalizeWheelID(query.WheelID)
|
||||
if err := r.db.QueryRowContext(ctx, `
|
||||
SELECT
|
||||
COUNT(*),
|
||||
COUNT(DISTINCT user_id),
|
||||
COALESCE(SUM(coin_spent), 0),
|
||||
COALESCE(SUM(rtp_value_coins), 0),
|
||||
COALESCE(SUM(CASE WHEN reward_status = 'pending' THEN 1 ELSE 0 END), 0),
|
||||
COALESCE(SUM(CASE WHEN reward_status = 'granted' THEN 1 ELSE 0 END), 0),
|
||||
COALESCE(SUM(CASE WHEN reward_status = 'failed' THEN 1 ELSE 0 END), 0)
|
||||
FROM wheel_draw_records
|
||||
WHERE `+whereSQL, args...).Scan(
|
||||
&summary.TotalDraws,
|
||||
&summary.UniqueUsers,
|
||||
&summary.TotalSpentCoins,
|
||||
&summary.TotalRTPValueCoins,
|
||||
&summary.PendingDraws,
|
||||
&summary.GrantedDraws,
|
||||
&summary.FailedDraws,
|
||||
); err != nil {
|
||||
return domain.DrawSummary{}, err
|
||||
}
|
||||
summary.ActualRTPPPM = wheelRTPPPM(summary.TotalSpentCoins, summary.TotalRTPValueCoins)
|
||||
return summary, nil
|
||||
}
|
||||
|
||||
func (r *Repository) getWheelDrawSummaryFromStats(ctx context.Context, query domain.DrawQuery) (domain.DrawSummary, error) {
|
||||
var summary domain.DrawSummary
|
||||
summary.WheelID = normalizeWheelID(query.WheelID)
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT total_draws, unique_users, total_spent_coins, total_rtp_value_coins,
|
||||
pending_draws, granted_draws, failed_draws
|
||||
FROM wheel_draw_stats
|
||||
WHERE app_code = ? AND wheel_id = ?`,
|
||||
appcode.FromContext(ctx), summary.WheelID,
|
||||
).Scan(
|
||||
&summary.TotalDraws,
|
||||
&summary.UniqueUsers,
|
||||
&summary.TotalSpentCoins,
|
||||
&summary.TotalRTPValueCoins,
|
||||
&summary.PendingDraws,
|
||||
&summary.GrantedDraws,
|
||||
&summary.FailedDraws,
|
||||
)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return summary, nil
|
||||
}
|
||||
if err != nil {
|
||||
return domain.DrawSummary{}, err
|
||||
}
|
||||
summary.ActualRTPPPM = wheelRTPPPM(summary.TotalSpentCoins, summary.TotalRTPValueCoins)
|
||||
return summary, nil
|
||||
}
|
||||
|
||||
func (r *Repository) MarkWheelDrawsGranted(ctx context.Context, appCode string, drawIDs []string, transactionID string, nowMS int64) error {
|
||||
if r == nil || r.db == nil {
|
||||
return xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
appCode = appcode.Normalize(appCode)
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
for _, drawID := range drawIDs {
|
||||
drawID = strings.TrimSpace(drawID)
|
||||
if drawID == "" {
|
||||
continue
|
||||
}
|
||||
var wheelID, oldStatus string
|
||||
if err := tx.QueryRowContext(ctx, `
|
||||
SELECT wheel_id, reward_status
|
||||
FROM wheel_draw_records
|
||||
WHERE app_code = ? AND draw_id = ?
|
||||
FOR UPDATE`,
|
||||
appCode, drawID,
|
||||
).Scan(&wheelID, &oldStatus); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
if oldStatus != domain.StatusGranted {
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE wheel_draw_records
|
||||
SET reward_status = 'granted', reward_transaction_id = ?, reward_failure_reason = '', updated_at_ms = ?
|
||||
WHERE app_code = ? AND draw_id = ? AND reward_status <> 'granted'`,
|
||||
transactionID, nowMS, appCode, drawID,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
// 转盘统计是 draw 事务内即时累加的,后续发奖状态变化必须同步搬移计数,避免后台看到永久 pending。
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE wheel_draw_stats
|
||||
SET pending_draws = CASE WHEN pending_draws > 0 THEN pending_draws - 1 ELSE 0 END,
|
||||
granted_draws = granted_draws + 1,
|
||||
updated_at_ms = ?
|
||||
WHERE app_code = ? AND wheel_id = ?`,
|
||||
nowMS, appCode, wheelID,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE activity_outbox
|
||||
SET status = 'delivered', locked_by = '', lock_until_ms = 0, last_error = '', updated_at_ms = ?
|
||||
WHERE app_code = ? AND outbox_id = ?`,
|
||||
nowMS, appCode, "wheel_reward_"+drawID,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (r *Repository) executeSingleWheelDraw(ctx context.Context, tx *sql.Tx, appCode string, cmd domain.DrawCommand, commandID string, unitSpent int64, config domain.RuleConfig, window *wheelRTPWindow, pool *wheelPool, nowMS int64) (domain.DrawResult, int64, error) {
|
||||
candidates, limited := wheelPayableCandidates(config, pool)
|
||||
if len(candidates) == 0 {
|
||||
return domain.DrawResult{}, 0, xerr.New(xerr.Conflict, "wheel has no payable tier")
|
||||
}
|
||||
engineCandidates := make([]lotteryengine.Candidate, 0, len(candidates))
|
||||
byID := make(map[string]domain.Tier, len(candidates))
|
||||
for _, candidate := range candidates {
|
||||
engineCandidates = append(engineCandidates, lotteryengine.Candidate{
|
||||
ID: candidate.Tier.TierID,
|
||||
Weight: candidate.Tier.WeightPPM,
|
||||
PrizeKind: candidate.Tier.RewardType,
|
||||
RTPValueCoins: candidate.Tier.RTPValueCoins,
|
||||
})
|
||||
byID[candidate.Tier.TierID] = candidate.Tier
|
||||
}
|
||||
selected, err := lotteryengine.SelectWeighted(engineCandidates)
|
||||
if err != nil {
|
||||
return domain.DrawResult{}, 0, err
|
||||
}
|
||||
tier := byID[selected.ID]
|
||||
tier.RTPValueCoins = selected.RTPValueCoins
|
||||
pool.Balance -= tier.RTPValueCoins
|
||||
pool.TotalOut += tier.RTPValueCoins
|
||||
window.PaidDraws++
|
||||
window.WagerCoins += unitSpent
|
||||
window.TargetPayout = window.WagerCoins * window.TargetRTPPPM / wheelPPMScale
|
||||
window.ActualRTPValue += tier.RTPValueCoins
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE wheel_rtp_windows
|
||||
SET paid_draws = ?, wager_coins = ?, target_payout_coins = ?, actual_rtp_value_coins = ?,
|
||||
carry_ppm = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND wheel_id = ? AND window_index = ?`,
|
||||
window.PaidDraws, window.WagerCoins, window.TargetPayout, window.ActualRTPValue,
|
||||
window.CarryPPM, nowMS, appCode, config.WheelID, window.WindowIndex,
|
||||
); err != nil {
|
||||
return domain.DrawResult{}, 0, err
|
||||
}
|
||||
drawID := idgen.New("wheel_draw")
|
||||
status := domain.StatusGranted
|
||||
if wheelDrawNeedsFulfillment(tier) {
|
||||
status = domain.StatusPending
|
||||
}
|
||||
candidateJSON, _ := json.Marshal(map[string]any{"selected": tier.TierID, "limited": limited})
|
||||
rtpJSON, _ := json.Marshal(map[string]any{"window_index": window.WindowIndex, "wager_coins": window.WagerCoins, "actual_rtp_value_coins": window.ActualRTPValue})
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO wheel_draw_records (
|
||||
app_code, draw_id, command_id, user_id, device_id, visible_region_id, wheel_id, coin_spent,
|
||||
rule_version, rtp_window_index, selected_tier_id, reward_type, reward_id, reward_count,
|
||||
reward_coins, rtp_value_coins, candidate_tiers_json, rtp_snapshot_json, prize_metadata_json,
|
||||
reward_status, paid_at_ms, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
appCode, drawID, commandID, cmd.UserID, cmd.DeviceID, cmd.VisibleRegionID, config.WheelID, unitSpent,
|
||||
config.RuleVersion, window.WindowIndex, tier.TierID, tier.RewardType, tier.RewardID, tier.RewardCount,
|
||||
tier.RewardCoins, tier.RTPValueCoins, string(candidateJSON), string(rtpJSON), wheelMetadataJSON(tier.MetadataJSON),
|
||||
status, cmd.PaidAtMS, nowMS, nowMS,
|
||||
); err != nil {
|
||||
return domain.DrawResult{}, 0, err
|
||||
}
|
||||
if status == domain.StatusPending {
|
||||
if err := r.insertWheelRewardOutbox(ctx, tx, appCode, drawID, commandID, cmd, tier, nowMS); err != nil {
|
||||
return domain.DrawResult{}, 0, err
|
||||
}
|
||||
}
|
||||
return domain.DrawResult{
|
||||
DrawID: drawID,
|
||||
CommandID: commandID,
|
||||
WheelID: config.WheelID,
|
||||
RuleVersion: config.RuleVersion,
|
||||
SelectedTierID: tier.TierID,
|
||||
RewardType: tier.RewardType,
|
||||
RewardID: tier.RewardID,
|
||||
RewardCount: tier.RewardCount,
|
||||
RewardCoins: tier.RewardCoins,
|
||||
RTPValueCoins: tier.RTPValueCoins,
|
||||
RewardStatus: status,
|
||||
RTPWindowIndex: window.WindowIndex,
|
||||
ActualRTPPPM: wheelRTPPPM(window.WagerCoins, window.ActualRTPValue),
|
||||
CreatedAtMS: nowMS,
|
||||
MetadataJSON: wheelMetadataJSON(tier.MetadataJSON),
|
||||
}, tier.RTPValueCoins, nil
|
||||
}
|
||||
|
||||
func (r *Repository) getWheelRuleConfig(ctx context.Context, queryer interface {
|
||||
QueryRowContext(context.Context, string, ...any) *sql.Row
|
||||
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
|
||||
}, appCode, wheelID string, forUpdate bool) (domain.RuleConfig, bool, error) {
|
||||
lockSQL := ""
|
||||
if forUpdate {
|
||||
lockSQL = " FOR UPDATE"
|
||||
}
|
||||
row := queryer.QueryRowContext(ctx, `
|
||||
SELECT app_code, wheel_id, rule_version, enabled, draw_price_coins, target_rtp_ppm, pool_rate_ppm,
|
||||
settlement_window_draws, initial_pool_coins, pool_reserve_coins, max_single_rtp_payout,
|
||||
effective_from_ms, created_by_admin_id, created_at_ms
|
||||
FROM wheel_rule_versions
|
||||
WHERE app_code = ? AND wheel_id = ? AND enabled = 1
|
||||
ORDER BY rule_version DESC
|
||||
LIMIT 1`+lockSQL,
|
||||
appCode, wheelID,
|
||||
)
|
||||
var config domain.RuleConfig
|
||||
if err := row.Scan(&config.AppCode, &config.WheelID, &config.RuleVersion, &config.Enabled, &config.DrawPriceCoins, &config.TargetRTPPPM, &config.PoolRatePPM,
|
||||
&config.SettlementWindowDraws, &config.InitialPoolCoins, &config.PoolReserveCoins, &config.MaxSingleRTPPayout,
|
||||
&config.EffectiveFromMS, &config.CreatedByAdminID, &config.CreatedAtMS); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return domain.RuleConfig{}, false, nil
|
||||
}
|
||||
return domain.RuleConfig{}, false, err
|
||||
}
|
||||
rows, err := queryer.QueryContext(ctx, `
|
||||
SELECT tier_id, display_name, reward_type, reward_id, reward_count, reward_coins, rtp_value_coins, weight_ppm, enabled,
|
||||
COALESCE(CAST(metadata_json AS CHAR), '{}')
|
||||
FROM wheel_prize_tiers
|
||||
WHERE app_code = ? AND wheel_id = ? AND rule_version = ?
|
||||
ORDER BY tier_id`,
|
||||
appCode, config.WheelID, config.RuleVersion,
|
||||
)
|
||||
if err != nil {
|
||||
return domain.RuleConfig{}, false, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var tier domain.Tier
|
||||
if err := rows.Scan(&tier.TierID, &tier.DisplayName, &tier.RewardType, &tier.RewardID, &tier.RewardCount, &tier.RewardCoins, &tier.RTPValueCoins, &tier.WeightPPM, &tier.Enabled, &tier.MetadataJSON); err != nil {
|
||||
return domain.RuleConfig{}, false, err
|
||||
}
|
||||
config.Tiers = append(config.Tiers, tier)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return domain.RuleConfig{}, false, err
|
||||
}
|
||||
return config, true, nil
|
||||
}
|
||||
|
||||
func (r *Repository) getOpenWheelRTPWindow(ctx context.Context, tx *sql.Tx, appCode string, config domain.RuleConfig, nowMS int64) (wheelRTPWindow, error) {
|
||||
window, exists, err := r.getLatestWheelRTPWindow(ctx, tx, appCode, config.WheelID, true)
|
||||
if err != nil {
|
||||
return wheelRTPWindow{}, err
|
||||
}
|
||||
if !exists {
|
||||
return r.createWheelRTPWindow(ctx, tx, appCode, config.WheelID, 1, 0, config.SettlementWindowDraws, config.TargetRTPPPM, nowMS)
|
||||
}
|
||||
if window.Status == "open" && window.PaidDraws < window.ControlDraws {
|
||||
return window, nil
|
||||
}
|
||||
if window.Status == "open" {
|
||||
if _, err := tx.ExecContext(ctx, `UPDATE wheel_rtp_windows SET status = 'closed', updated_at_ms = ? WHERE app_code = ? AND wheel_id = ? AND window_index = ?`, nowMS, appCode, config.WheelID, window.WindowIndex); err != nil {
|
||||
return wheelRTPWindow{}, err
|
||||
}
|
||||
}
|
||||
return r.createWheelRTPWindow(ctx, tx, appCode, config.WheelID, window.WindowIndex+1, window.CarryPPM, config.SettlementWindowDraws, config.TargetRTPPPM, nowMS)
|
||||
}
|
||||
|
||||
func (r *Repository) getLatestWheelRTPWindow(ctx context.Context, tx *sql.Tx, appCode, wheelID string, forUpdate bool) (wheelRTPWindow, bool, error) {
|
||||
lockSQL := ""
|
||||
if forUpdate {
|
||||
lockSQL = " FOR UPDATE"
|
||||
}
|
||||
row := tx.QueryRowContext(ctx, `
|
||||
SELECT wheel_id, window_index, target_rtp_ppm, control_window_draws, paid_draws, wager_coins,
|
||||
target_payout_coins, actual_rtp_value_coins, carry_ppm, status
|
||||
FROM wheel_rtp_windows
|
||||
WHERE app_code = ? AND wheel_id = ?
|
||||
ORDER BY window_index DESC LIMIT 1`+lockSQL,
|
||||
appCode, wheelID,
|
||||
)
|
||||
var window wheelRTPWindow
|
||||
if err := row.Scan(&window.WheelID, &window.WindowIndex, &window.TargetRTPPPM, &window.ControlDraws, &window.PaidDraws, &window.WagerCoins,
|
||||
&window.TargetPayout, &window.ActualRTPValue, &window.CarryPPM, &window.Status); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return wheelRTPWindow{}, false, nil
|
||||
}
|
||||
return wheelRTPWindow{}, false, err
|
||||
}
|
||||
return window, true, nil
|
||||
}
|
||||
|
||||
func (r *Repository) createWheelRTPWindow(ctx context.Context, tx *sql.Tx, appCode, wheelID string, index, carry, windowDraws, targetPPM, nowMS int64) (wheelRTPWindow, error) {
|
||||
if windowDraws <= 0 {
|
||||
windowDraws = 1
|
||||
}
|
||||
window := wheelRTPWindow{WheelID: wheelID, WindowIndex: index, TargetRTPPPM: targetPPM, ControlDraws: windowDraws, CarryPPM: carry, Status: "open"}
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO wheel_rtp_windows (
|
||||
app_code, wheel_id, window_index, target_rtp_ppm, control_window_draws,
|
||||
paid_draws, wager_coins, target_payout_coins, actual_rtp_value_coins, carry_ppm, status, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, 0, 0, 0, 0, ?, 'open', ?, ?)`,
|
||||
appCode, wheelID, index, targetPPM, windowDraws, carry, nowMS, nowMS,
|
||||
); err != nil {
|
||||
return wheelRTPWindow{}, err
|
||||
}
|
||||
return window, nil
|
||||
}
|
||||
|
||||
func (r *Repository) getOrCreateWheelPool(ctx context.Context, tx *sql.Tx, appCode string, config domain.RuleConfig, nowMS int64) (wheelPool, error) {
|
||||
row := tx.QueryRowContext(ctx, `SELECT wheel_id, balance, reserve_floor, total_in, total_out FROM wheel_pools WHERE app_code = ? AND wheel_id = ? FOR UPDATE`, appCode, config.WheelID)
|
||||
var pool wheelPool
|
||||
if err := row.Scan(&pool.WheelID, &pool.Balance, &pool.ReserveFloor, &pool.TotalIn, &pool.TotalOut); err != nil {
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
return wheelPool{}, err
|
||||
}
|
||||
pool = wheelPool{WheelID: config.WheelID, Balance: config.InitialPoolCoins, ReserveFloor: config.PoolReserveCoins}
|
||||
if _, err := tx.ExecContext(ctx, `INSERT INTO wheel_pools (app_code, wheel_id, balance, reserve_floor, total_in, total_out, created_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, 0, 0, ?, ?)`,
|
||||
appCode, pool.WheelID, pool.Balance, pool.ReserveFloor, nowMS, nowMS); err != nil {
|
||||
return wheelPool{}, err
|
||||
}
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (r *Repository) persistWheelPoolDelta(ctx context.Context, tx *sql.Tx, appCode, wheelID string, in, out, nowMS int64) error {
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
UPDATE wheel_pools
|
||||
SET balance = balance + ? - ?, total_in = total_in + ?, total_out = total_out + ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND wheel_id = ?`,
|
||||
in, out, in, out, nowMS, appCode, wheelID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func wheelPayableCandidates(config domain.RuleConfig, pool *wheelPool) ([]wheelCandidate, map[string]bool) {
|
||||
limited := map[string]bool{}
|
||||
capacity := pool.Balance - pool.ReserveFloor
|
||||
if capacity < 0 {
|
||||
capacity = 0
|
||||
}
|
||||
if config.MaxSingleRTPPayout > 0 && config.MaxSingleRTPPayout < capacity {
|
||||
capacity = config.MaxSingleRTPPayout
|
||||
}
|
||||
candidates := make([]wheelCandidate, 0, len(config.Tiers))
|
||||
for _, tier := range config.Tiers {
|
||||
if !tier.Enabled {
|
||||
continue
|
||||
}
|
||||
tier.RewardType = lotteryengine.NormalizePrizeKind(tier.RewardType)
|
||||
tier.RTPValueCoins = lotteryengine.NormalizeRTPValueCoins(tier.RewardType, tier.RTPValueCoins)
|
||||
if tier.RTPValueCoins > capacity {
|
||||
limited["pool_cap"] = true
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, wheelCandidate{Tier: tier})
|
||||
}
|
||||
return candidates, limited
|
||||
}
|
||||
|
||||
func (r *Repository) updateWheelStats(ctx context.Context, tx *sql.Tx, appCode, wheelID string, userID int64, totalSpent int64, results []domain.DrawResult, nowMS int64) error {
|
||||
var spent, rtpValue, pending, granted, failed int64
|
||||
spent = totalSpent
|
||||
for _, result := range results {
|
||||
rtpValue += result.RTPValueCoins
|
||||
switch result.RewardStatus {
|
||||
case domain.StatusPending:
|
||||
pending++
|
||||
case domain.StatusFailed:
|
||||
failed++
|
||||
default:
|
||||
granted++
|
||||
}
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, `INSERT IGNORE INTO wheel_draw_stat_users (app_code, wheel_id, user_id, created_at_ms) VALUES (?, ?, ?, ?)`, appCode, wheelID, userID, nowMS); err != nil {
|
||||
return err
|
||||
}
|
||||
var uniqueDelta int64
|
||||
if err := tx.QueryRowContext(ctx, `SELECT COUNT(*) FROM wheel_draw_stat_users WHERE app_code = ? AND wheel_id = ?`, appCode, wheelID).Scan(&uniqueDelta); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO wheel_draw_stats (
|
||||
app_code, wheel_id, total_draws, unique_users, total_spent_coins, total_rtp_value_coins,
|
||||
pending_draws, granted_draws, failed_draws, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
total_draws = total_draws + VALUES(total_draws),
|
||||
unique_users = ?,
|
||||
total_spent_coins = total_spent_coins + VALUES(total_spent_coins),
|
||||
total_rtp_value_coins = total_rtp_value_coins + VALUES(total_rtp_value_coins),
|
||||
pending_draws = pending_draws + VALUES(pending_draws),
|
||||
granted_draws = granted_draws + VALUES(granted_draws),
|
||||
failed_draws = failed_draws + VALUES(failed_draws),
|
||||
updated_at_ms = VALUES(updated_at_ms)`,
|
||||
appCode, wheelID, int64(len(results)), uniqueDelta, spent, rtpValue, pending, granted, failed, nowMS, nowMS, uniqueDelta,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) insertWheelRewardOutbox(ctx context.Context, tx *sql.Tx, appCode, drawID, commandID string, cmd domain.DrawCommand, tier domain.Tier, nowMS int64) error {
|
||||
payload, _ := json.Marshal(map[string]any{
|
||||
"app_code": appCode,
|
||||
"draw_id": drawID,
|
||||
"command_id": commandID,
|
||||
"user_id": cmd.UserID,
|
||||
"wheel_id": cmd.WheelID,
|
||||
"selected_tier_id": tier.TierID,
|
||||
"reward_type": tier.RewardType,
|
||||
"reward_id": tier.RewardID,
|
||||
"reward_count": tier.RewardCount,
|
||||
"reward_coins": tier.RewardCoins,
|
||||
"visible_region_id": cmd.VisibleRegionID,
|
||||
"created_at_ms": nowMS,
|
||||
})
|
||||
return r.insertLuckyDrawOutbox(ctx, tx, appCode, "wheel_reward_"+drawID, domain.EventTypeWheelRewardSettlement, payload, nowMS)
|
||||
}
|
||||
|
||||
func (r *Repository) collectWheelDrawsByCommand(ctx context.Context, tx *sql.Tx, appCode, commandID string, drawCount int32) ([]domain.DrawResult, bool, error) {
|
||||
if drawCount <= 0 {
|
||||
drawCount = 1
|
||||
}
|
||||
results := make([]domain.DrawResult, 0, drawCount)
|
||||
for i := int32(1); i <= drawCount; i++ {
|
||||
sub := wheelSubCommandID(commandID, i, drawCount)
|
||||
row := tx.QueryRowContext(ctx, `
|
||||
SELECT draw_id, command_id, wheel_id, rule_version, selected_tier_id, reward_type, reward_id, reward_count,
|
||||
reward_coins, rtp_value_coins, reward_status, reward_transaction_id, rtp_window_index, created_at_ms,
|
||||
COALESCE(CAST(prize_metadata_json AS CHAR), '{}')
|
||||
FROM wheel_draw_records
|
||||
WHERE app_code = ? AND command_id = ?`,
|
||||
appCode, sub,
|
||||
)
|
||||
var result domain.DrawResult
|
||||
if err := row.Scan(&result.DrawID, &result.CommandID, &result.WheelID, &result.RuleVersion, &result.SelectedTierID, &result.RewardType, &result.RewardID, &result.RewardCount,
|
||||
&result.RewardCoins, &result.RTPValueCoins, &result.RewardStatus, &result.WalletTransactionID, &result.RTPWindowIndex, &result.CreatedAtMS, &result.MetadataJSON); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
continue
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
return results, int32(len(results)) == drawCount, nil
|
||||
}
|
||||
|
||||
func aggregateWheelDrawResults(cmd domain.DrawCommand, results []domain.DrawResult) domain.DrawResult {
|
||||
if len(results) == 0 {
|
||||
return domain.DrawResult{}
|
||||
}
|
||||
aggregate := results[0]
|
||||
aggregate.CommandID = cmd.CommandID
|
||||
aggregate.DrawIDs = make([]string, 0, len(results))
|
||||
if len(results) == 1 {
|
||||
aggregate.DrawIDs = []string{aggregate.DrawID}
|
||||
return aggregate
|
||||
}
|
||||
aggregate.SelectedTierID = "batch"
|
||||
aggregate.RewardType = "batch"
|
||||
aggregate.RewardID = ""
|
||||
aggregate.RewardCount = 0
|
||||
aggregate.RewardCoins = 0
|
||||
aggregate.RTPValueCoins = 0
|
||||
aggregate.RewardStatus = domain.StatusGranted
|
||||
for _, result := range results {
|
||||
aggregate.DrawIDs = append(aggregate.DrawIDs, result.DrawID)
|
||||
aggregate.RewardCoins += result.RewardCoins
|
||||
aggregate.RTPValueCoins += result.RTPValueCoins
|
||||
if result.RewardStatus == domain.StatusPending {
|
||||
aggregate.RewardStatus = domain.StatusPending
|
||||
} else if aggregate.RewardStatus != domain.StatusPending && result.RewardStatus == domain.StatusFailed {
|
||||
aggregate.RewardStatus = domain.StatusFailed
|
||||
}
|
||||
}
|
||||
return aggregate
|
||||
}
|
||||
|
||||
func wheelSubCommandID(commandID string, drawIndex int32, drawCount int32) string {
|
||||
if drawCount <= 1 {
|
||||
return strings.TrimSpace(commandID)
|
||||
}
|
||||
suffix := fmt.Sprintf("#%06d", drawIndex)
|
||||
const maxCommandIDLength = 128
|
||||
commandID = strings.TrimSpace(commandID)
|
||||
if len(commandID)+len(suffix) <= maxCommandIDLength {
|
||||
return commandID + suffix
|
||||
}
|
||||
sum := sha1.Sum([]byte(commandID))
|
||||
hash := hex.EncodeToString(sum[:])[:10]
|
||||
hashSuffix := "#" + hash + suffix
|
||||
headLen := maxCommandIDLength - len(hashSuffix)
|
||||
if headLen < 0 {
|
||||
headLen = 0
|
||||
}
|
||||
if len(commandID) > headLen {
|
||||
commandID = commandID[:headLen]
|
||||
}
|
||||
return commandID + hashSuffix
|
||||
}
|
||||
|
||||
func normalizeWheelID(wheelID string) string {
|
||||
wheelID = strings.TrimSpace(wheelID)
|
||||
if wheelID == "" {
|
||||
return "default"
|
||||
}
|
||||
return wheelID
|
||||
}
|
||||
|
||||
func normalizeWheelTiers(tiers []domain.Tier) []domain.Tier {
|
||||
out := make([]domain.Tier, 0, len(tiers))
|
||||
for _, tier := range tiers {
|
||||
tier.TierID = strings.TrimSpace(tier.TierID)
|
||||
tier.RewardType = lotteryengine.NormalizePrizeKind(tier.RewardType)
|
||||
tier.RTPValueCoins = lotteryengine.NormalizeRTPValueCoins(tier.RewardType, tier.RTPValueCoins)
|
||||
tier.MetadataJSON = wheelMetadataJSON(tier.MetadataJSON)
|
||||
if tier.RewardCount <= 0 {
|
||||
tier.RewardCount = 1
|
||||
}
|
||||
out = append(out, tier)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func wheelDrawNeedsFulfillment(tier domain.Tier) bool {
|
||||
return tier.RewardCoins > 0 || strings.TrimSpace(tier.RewardID) != ""
|
||||
}
|
||||
|
||||
func wheelMetadataJSON(raw string) string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" || !json.Valid([]byte(raw)) {
|
||||
return "{}"
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
func wheelRTPPPM(wager, payout int64) int64 {
|
||||
if wager <= 0 {
|
||||
return 0
|
||||
}
|
||||
return payout * wheelPPMScale / wager
|
||||
}
|
||||
|
||||
func wheelDrawWhereClause(appCode string, query domain.DrawQuery) (string, []any) {
|
||||
where := []string{"app_code = ?"}
|
||||
args := []any{appCode}
|
||||
if query.WheelID != "" {
|
||||
where = append(where, "wheel_id = ?")
|
||||
args = append(args, normalizeWheelID(query.WheelID))
|
||||
}
|
||||
if query.UserID > 0 {
|
||||
where = append(where, "user_id = ?")
|
||||
args = append(args, query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
where = append(where, "reward_status = ?")
|
||||
args = append(args, strings.TrimSpace(query.Status))
|
||||
}
|
||||
return strings.Join(where, " AND "), args
|
||||
}
|
||||
|
||||
func normalizeWheelPage(page int32, pageSize int32) (int32, int32) {
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
if pageSize > 100 {
|
||||
pageSize = 100
|
||||
}
|
||||
return page, pageSize
|
||||
}
|
||||
139
services/activity-service/internal/storage/mysql/wheel_schema.go
Normal file
139
services/activity-service/internal/storage/mysql/wheel_schema.go
Normal file
@ -0,0 +1,139 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"hyapp/pkg/xerr"
|
||||
)
|
||||
|
||||
func (r *Repository) ensureWheelTables(ctx context.Context) error {
|
||||
if r == nil || r.db == nil {
|
||||
return xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
statements := []string{
|
||||
`CREATE TABLE IF NOT EXISTS wheel_rule_versions (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
rule_version BIGINT NOT NULL COMMENT '不可变规则版本',
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否启用',
|
||||
draw_price_coins BIGINT NOT NULL COMMENT '单抽价格,金币',
|
||||
target_rtp_ppm BIGINT NOT NULL COMMENT '金币和礼物 RTP 目标,ppm',
|
||||
pool_rate_ppm BIGINT NOT NULL COMMENT '每笔消耗进入转盘基础奖池比例,ppm',
|
||||
settlement_window_draws BIGINT NOT NULL COMMENT 'RTP 观察窗口抽数',
|
||||
initial_pool_coins BIGINT NOT NULL DEFAULT 0 COMMENT '初始奖池水位',
|
||||
pool_reserve_coins BIGINT NOT NULL DEFAULT 0 COMMENT '奖池安全水位',
|
||||
max_single_rtp_payout BIGINT NOT NULL DEFAULT 0 COMMENT '单次计入 RTP 的最大返奖',
|
||||
effective_from_ms BIGINT NOT NULL COMMENT '生效时间,UTC epoch ms',
|
||||
created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '发布人',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id, rule_version),
|
||||
KEY idx_wheel_rule_versions_latest (app_code, wheel_id, rule_version),
|
||||
KEY idx_wheel_rule_versions_enabled (app_code, enabled, created_at_ms)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘规则版本表'`,
|
||||
`CREATE TABLE IF NOT EXISTS wheel_prize_tiers (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
rule_version BIGINT NOT NULL COMMENT '规则版本',
|
||||
tier_id VARCHAR(96) NOT NULL COMMENT '奖档 ID',
|
||||
display_name VARCHAR(128) NOT NULL DEFAULT '' COMMENT '展示名称快照',
|
||||
reward_type VARCHAR(32) NOT NULL COMMENT 'coin/gift/prop/dress',
|
||||
reward_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '礼物或道具资源 ID',
|
||||
reward_count BIGINT NOT NULL DEFAULT 1 COMMENT '奖励数量',
|
||||
reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '金币奖励金额',
|
||||
rtp_value_coins BIGINT NOT NULL DEFAULT 0 COMMENT '计入 RTP 的奖励价值;道具装扮强制为 0',
|
||||
weight_ppm BIGINT NOT NULL COMMENT '随机权重,ppm 口径',
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
|
||||
metadata_json JSON NOT NULL COMMENT '奖品展示和发放扩展快照',
|
||||
PRIMARY KEY (app_code, wheel_id, rule_version, tier_id),
|
||||
KEY idx_wheel_prize_tiers_rule (app_code, wheel_id, rule_version)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘奖档表'`,
|
||||
`CREATE TABLE IF NOT EXISTS wheel_rtp_windows (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
window_index BIGINT NOT NULL COMMENT 'RTP 窗口序号',
|
||||
target_rtp_ppm BIGINT NOT NULL COMMENT '窗口目标 RTP',
|
||||
control_window_draws BIGINT NOT NULL COMMENT '窗口抽数',
|
||||
paid_draws BIGINT NOT NULL DEFAULT 0 COMMENT '已抽次数',
|
||||
wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '消耗金币',
|
||||
target_payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '目标返奖',
|
||||
actual_rtp_value_coins BIGINT NOT NULL DEFAULT 0 COMMENT '实际计入 RTP 的返奖',
|
||||
carry_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '整数除法余数',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'open' COMMENT 'open/closed',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id, window_index),
|
||||
KEY idx_wheel_rtp_windows_open (app_code, wheel_id, status, window_index)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘 RTP 观察窗口'`,
|
||||
`CREATE TABLE IF NOT EXISTS wheel_pools (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
balance BIGINT NOT NULL DEFAULT 0 COMMENT '当前可用水位',
|
||||
reserve_floor BIGINT NOT NULL DEFAULT 0 COMMENT '安全水位',
|
||||
total_in BIGINT NOT NULL DEFAULT 0 COMMENT '累计入池',
|
||||
total_out BIGINT NOT NULL DEFAULT 0 COMMENT '累计 RTP 价值支出',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘基础奖池'`,
|
||||
`CREATE TABLE IF NOT EXISTS wheel_draw_records (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
draw_id VARCHAR(128) NOT NULL COMMENT '抽奖 ID',
|
||||
command_id VARCHAR(128) NOT NULL COMMENT '幂等命令 ID',
|
||||
user_id BIGINT NOT NULL COMMENT '用户 ID',
|
||||
device_id VARCHAR(128) NOT NULL COMMENT '设备 ID',
|
||||
visible_region_id BIGINT NOT NULL DEFAULT 0 COMMENT '可见区域 ID',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
coin_spent BIGINT NOT NULL COMMENT '消耗金币',
|
||||
rule_version BIGINT NOT NULL COMMENT '规则版本',
|
||||
rtp_window_index BIGINT NOT NULL COMMENT 'RTP 窗口',
|
||||
selected_tier_id VARCHAR(96) NOT NULL COMMENT '命中奖档',
|
||||
reward_type VARCHAR(32) NOT NULL COMMENT 'coin/gift/prop/dress',
|
||||
reward_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '礼物或道具资源 ID',
|
||||
reward_count BIGINT NOT NULL DEFAULT 0 COMMENT '奖励数量',
|
||||
reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '金币奖励金额',
|
||||
rtp_value_coins BIGINT NOT NULL DEFAULT 0 COMMENT '计入 RTP 的奖励价值',
|
||||
candidate_tiers_json JSON NOT NULL COMMENT '候选过滤快照',
|
||||
rtp_snapshot_json JSON NOT NULL COMMENT 'RTP 快照',
|
||||
prize_metadata_json JSON NOT NULL COMMENT '奖品扩展快照',
|
||||
reward_status VARCHAR(32) NOT NULL COMMENT 'pending/granted/failed',
|
||||
reward_transaction_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '钱包或资产发放交易 ID',
|
||||
reward_failure_reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '发放失败原因',
|
||||
paid_at_ms BIGINT NOT NULL COMMENT '扣费时间,UTC epoch ms',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, draw_id),
|
||||
UNIQUE KEY uk_wheel_draw_command (app_code, command_id),
|
||||
KEY idx_wheel_draw_wheel (app_code, wheel_id, created_at_ms),
|
||||
KEY idx_wheel_draw_user (app_code, user_id, created_at_ms),
|
||||
KEY idx_wheel_draw_status (app_code, reward_status, updated_at_ms),
|
||||
KEY idx_wheel_draw_created (app_code, created_at_ms, draw_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘抽奖事实'`,
|
||||
`CREATE TABLE IF NOT EXISTS wheel_draw_stats (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
total_draws BIGINT NOT NULL DEFAULT 0 COMMENT '抽奖次数',
|
||||
unique_users BIGINT NOT NULL DEFAULT 0 COMMENT '参与用户数',
|
||||
total_spent_coins BIGINT NOT NULL DEFAULT 0 COMMENT '消耗金币',
|
||||
total_rtp_value_coins BIGINT NOT NULL DEFAULT 0 COMMENT '计入 RTP 的返奖价值',
|
||||
pending_draws BIGINT NOT NULL DEFAULT 0 COMMENT '待发放数量',
|
||||
granted_draws BIGINT NOT NULL DEFAULT 0 COMMENT '已发放数量',
|
||||
failed_draws BIGINT NOT NULL DEFAULT 0 COMMENT '发放失败数量',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘后台汇总统计'`,
|
||||
`CREATE TABLE IF NOT EXISTS wheel_draw_stat_users (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
|
||||
wheel_id VARCHAR(96) NOT NULL COMMENT '转盘 ID',
|
||||
user_id BIGINT NOT NULL COMMENT '用户 ID',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, wheel_id, user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转盘统计用户去重'`,
|
||||
}
|
||||
for _, statement := range statements {
|
||||
if _, err := r.db.ExecContext(ctx, statement); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -0,0 +1,216 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
grpcpkg "google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
"google.golang.org/protobuf/proto"
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
roomeventsv1 "hyapp.local/api/proto/events/room/v1"
|
||||
roomv1 "hyapp.local/api/proto/room/v1"
|
||||
agencydomain "hyapp/services/activity-service/internal/domain/agencyopening"
|
||||
agencyservice "hyapp/services/activity-service/internal/service/agencyopening"
|
||||
broadcastservice "hyapp/services/activity-service/internal/service/broadcast"
|
||||
"hyapp/services/activity-service/internal/testutil/mysqltest"
|
||||
)
|
||||
|
||||
func TestAgencyOpeningGRPCInterfaceFlow(t *testing.T) {
|
||||
repository := mysqltest.NewRepository(t)
|
||||
now := time.Now().UTC()
|
||||
ownerUserID := int64(42001)
|
||||
agencySvc := agencyservice.New(repository, nil, fakeAgencyOpeningFlowSource{
|
||||
snapshot: agencydomain.AgencySnapshot{
|
||||
AgencyID: 8001,
|
||||
OwnerUserID: ownerUserID,
|
||||
Name: "Window Agency",
|
||||
HostCount: 12,
|
||||
AgencyCreatedAtMS: now.Add(-time.Hour).UnixMilli(),
|
||||
Status: "active",
|
||||
},
|
||||
}, &fakeAgencyOpeningFlowRoom{ownerUserID: ownerUserID})
|
||||
conn := newAgencyOpeningFlowGRPCConn(t, agencySvc, repository)
|
||||
|
||||
adminClient := activityv1.NewAdminAgencyOpeningServiceClient(conn)
|
||||
appClient := activityv1.NewAgencyOpeningServiceClient(conn)
|
||||
roomEventClient := activityv1.NewRoomEventConsumerServiceClient(conn)
|
||||
ctx := context.Background()
|
||||
|
||||
createdCycle, err := adminClient.CreateAgencyOpeningCycle(ctx, &activityv1.UpsertAgencyOpeningCycleRequest{
|
||||
Meta: agencyOpeningFlowMeta("agency-opening-cycle-create"),
|
||||
Cycle: &activityv1.AgencyOpeningCycle{
|
||||
Title: "Agency Opening Interface Flow",
|
||||
Status: "active",
|
||||
StartMs: now.Add(-time.Minute).UnixMilli(),
|
||||
EndMs: now.Add(48 * time.Hour).UnixMilli(),
|
||||
MinHostCount: 10,
|
||||
MaxAgencyAgeDays: 30,
|
||||
Rewards: []*activityv1.AgencyOpeningReward{{
|
||||
RankNo: 1,
|
||||
ThresholdCoinSpent: 500,
|
||||
RewardCoinAmount: 50,
|
||||
}},
|
||||
},
|
||||
OperatorAdminId: 7,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create agency opening cycle failed: %v", err)
|
||||
}
|
||||
if !createdCycle.GetCreated() || createdCycle.GetCycle().GetCycleId() == "" {
|
||||
t.Fatalf("create cycle response mismatch: %+v", createdCycle)
|
||||
}
|
||||
|
||||
beforeApply, err := appClient.GetAgencyOpeningStatus(ctx, &activityv1.GetAgencyOpeningStatusRequest{
|
||||
Meta: agencyOpeningFlowMeta("agency-opening-status-before-apply"),
|
||||
UserId: ownerUserID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("get status before apply failed: %v", err)
|
||||
}
|
||||
if beforeApply.GetJoined() || !beforeApply.GetEligible() {
|
||||
t.Fatalf("owner should be eligible before apply: %+v", beforeApply)
|
||||
}
|
||||
|
||||
applied, err := appClient.ApplyAgencyOpening(ctx, &activityv1.ApplyAgencyOpeningRequest{
|
||||
Meta: agencyOpeningFlowMeta("agency-opening-apply"),
|
||||
UserId: ownerUserID,
|
||||
CommandId: "cmd-agency-opening-flow-apply",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("apply agency opening failed: %v", err)
|
||||
}
|
||||
if !applied.GetCreated() || applied.GetApplication().GetStatus() != agencydomain.ApplicationStatusApplied || applied.GetApplication().GetScoreStartMs() != 0 {
|
||||
t.Fatalf("apply response mismatch: %+v", applied)
|
||||
}
|
||||
|
||||
consumeAgencyOpeningFlowGift(t, ctx, roomEventClient, "gift-before-approval", "room-flow-1", ownerUserID, now.UnixMilli(), 700)
|
||||
|
||||
approved, err := adminClient.ReviewAgencyOpeningApplication(ctx, &activityv1.ReviewAgencyOpeningApplicationRequest{
|
||||
Meta: agencyOpeningFlowMeta("agency-opening-approve"),
|
||||
ApplicationId: applied.GetApplication().GetApplicationId(),
|
||||
Action: "approve",
|
||||
OperatorAdminId: 7,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("approve agency opening failed: %v", err)
|
||||
}
|
||||
if approved.GetApplication().GetStatus() != agencydomain.ApplicationStatusApproved ||
|
||||
approved.GetApplication().GetScoreStartMs() != approved.GetApplication().GetApprovedAtMs() ||
|
||||
approved.GetApplication().GetScoreEndMs() <= approved.GetApplication().GetScoreStartMs() {
|
||||
t.Fatalf("approve response should open a scoring window: %+v", approved)
|
||||
}
|
||||
|
||||
insideWindowMS := approved.GetApplication().GetScoreStartMs() + int64(time.Second.Milliseconds())
|
||||
consumeAgencyOpeningFlowGift(t, ctx, roomEventClient, "gift-inside-window", "room-flow-1", ownerUserID, insideWindowMS, 900)
|
||||
|
||||
afterInside, err := appClient.GetAgencyOpeningStatus(ctx, &activityv1.GetAgencyOpeningStatusRequest{
|
||||
Meta: agencyOpeningFlowMeta("agency-opening-status-after-inside"),
|
||||
UserId: ownerUserID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("get status after inside-window gift failed: %v", err)
|
||||
}
|
||||
if afterInside.GetApplication().GetScoreCoinAmount() != 900 ||
|
||||
afterInside.GetApplication().GetScoreEndMs() != approved.GetApplication().GetScoreEndMs() {
|
||||
t.Fatalf("inside-window gift should be counted once: %+v", afterInside.GetApplication())
|
||||
}
|
||||
|
||||
consumeAgencyOpeningFlowGift(t, ctx, roomEventClient, "gift-at-window-end", "room-flow-1", ownerUserID, approved.GetApplication().GetScoreEndMs(), 1200)
|
||||
|
||||
afterWindow, err := appClient.GetAgencyOpeningStatus(ctx, &activityv1.GetAgencyOpeningStatusRequest{
|
||||
Meta: agencyOpeningFlowMeta("agency-opening-status-after-window"),
|
||||
UserId: ownerUserID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("get status after window-end gift failed: %v", err)
|
||||
}
|
||||
if afterWindow.GetApplication().GetScoreCoinAmount() != 900 {
|
||||
t.Fatalf("window-end gift must not be counted: %+v", afterWindow.GetApplication())
|
||||
}
|
||||
}
|
||||
|
||||
func newAgencyOpeningFlowGRPCConn(t *testing.T, agencySvc *agencyservice.Service, repository *mysqltest.Repository) *grpcpkg.ClientConn {
|
||||
t.Helper()
|
||||
|
||||
listener := bufconn.Listen(1024 * 1024)
|
||||
server := grpcpkg.NewServer()
|
||||
activityv1.RegisterAgencyOpeningServiceServer(server, NewAgencyOpeningServer(agencySvc))
|
||||
activityv1.RegisterAdminAgencyOpeningServiceServer(server, NewAdminAgencyOpeningServer(agencySvc))
|
||||
broadcastSvc := broadcastservice.New(broadcastservice.Config{SuperGiftMinValue: 1_000_000_000}, repository, nil, nil)
|
||||
activityv1.RegisterRoomEventConsumerServiceServer(server, NewBroadcastServer(broadcastSvc, nil, nil, nil, nil, agencySvc))
|
||||
go func() {
|
||||
_ = server.Serve(listener)
|
||||
}()
|
||||
t.Cleanup(func() {
|
||||
server.Stop()
|
||||
_ = listener.Close()
|
||||
})
|
||||
|
||||
conn, err := grpcpkg.NewClient("passthrough:///agency-opening-flow-bufconn",
|
||||
grpcpkg.WithContextDialer(func(context.Context, string) (net.Conn, error) {
|
||||
return listener.Dial()
|
||||
}),
|
||||
grpcpkg.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("dial agency opening flow grpc failed: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = conn.Close() })
|
||||
return conn
|
||||
}
|
||||
|
||||
func consumeAgencyOpeningFlowGift(t *testing.T, ctx context.Context, client activityv1.RoomEventConsumerServiceClient, eventID string, roomID string, ownerUserID int64, occurredAtMS int64, giftValue int64) {
|
||||
t.Helper()
|
||||
|
||||
body, err := proto.Marshal(&roomeventsv1.RoomGiftSent{
|
||||
SenderUserId: 10001,
|
||||
TargetUserId: ownerUserID,
|
||||
GiftValue: giftValue,
|
||||
CoinSpent: giftValue,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal room gift event failed: %v", err)
|
||||
}
|
||||
if _, err := client.ConsumeRoomEvent(ctx, &activityv1.ConsumeRoomEventRequest{
|
||||
Meta: agencyOpeningFlowMeta("consume-" + eventID),
|
||||
Envelope: &roomeventsv1.EventEnvelope{
|
||||
EventId: eventID,
|
||||
RoomId: roomID,
|
||||
EventType: "RoomGiftSent",
|
||||
OccurredAtMs: occurredAtMS,
|
||||
AppCode: "lalu",
|
||||
Body: body,
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatalf("consume room event %s failed: %v", eventID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func agencyOpeningFlowMeta(requestID string) *activityv1.RequestMeta {
|
||||
return &activityv1.RequestMeta{
|
||||
RequestId: requestID,
|
||||
Caller: "agency-opening-interface-flow-test",
|
||||
AppCode: "lalu",
|
||||
SentAtMs: time.Now().UTC().UnixMilli(),
|
||||
}
|
||||
}
|
||||
|
||||
type fakeAgencyOpeningFlowSource struct {
|
||||
snapshot agencydomain.AgencySnapshot
|
||||
}
|
||||
|
||||
func (f fakeAgencyOpeningFlowSource) ResolveOwnerAgency(context.Context, int64) (agencydomain.AgencySnapshot, bool, error) {
|
||||
return f.snapshot, true, nil
|
||||
}
|
||||
|
||||
type fakeAgencyOpeningFlowRoom struct {
|
||||
ownerUserID int64
|
||||
}
|
||||
|
||||
func (r *fakeAgencyOpeningFlowRoom) AdminGetRoom(context.Context, *roomv1.AdminGetRoomRequest, ...grpcpkg.CallOption) (*roomv1.AdminGetRoomResponse, error) {
|
||||
return &roomv1.AdminGetRoomResponse{Room: &roomv1.AdminRoomListItem{OwnerUserId: r.ownerUserID}}, nil
|
||||
}
|
||||
@ -122,6 +122,18 @@ func (s *AdminAgencyOpeningServer) ListAgencyOpeningApplications(ctx context.Con
|
||||
return agencyOpeningApplicationsResponse(items, total), nil
|
||||
}
|
||||
|
||||
func (s *AdminAgencyOpeningServer) ReviewAgencyOpeningApplication(ctx context.Context, req *activityv1.ReviewAgencyOpeningApplicationRequest) (*activityv1.ReviewAgencyOpeningApplicationResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
if req.GetAction() != "approve" {
|
||||
return nil, xerr.ToGRPCError(xerr.New(xerr.InvalidArgument, "review action is invalid"))
|
||||
}
|
||||
item, err := s.svc.ApproveApplication(ctx, req.GetApplicationId(), req.GetOperatorAdminId())
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &activityv1.ReviewAgencyOpeningApplicationResponse{Application: agencyOpeningApplicationToProto(item)}, nil
|
||||
}
|
||||
|
||||
func agencyOpeningCycleFromProto(item *activityv1.AgencyOpeningCycle) domain.Cycle {
|
||||
if item == nil {
|
||||
return domain.Cycle{}
|
||||
@ -200,6 +212,10 @@ func agencyOpeningApplicationToProto(item domain.Application) *activityv1.Agency
|
||||
WalletTransactionId: item.WalletTransactionID,
|
||||
FailureReason: item.FailureReason,
|
||||
AppliedAtMs: item.AppliedAtMS,
|
||||
ApprovedAtMs: item.ApprovedAtMS,
|
||||
ScoreStartMs: item.ScoreStartMS,
|
||||
ScoreEndMs: item.ScoreEndMS,
|
||||
ReviewedByAdminId: item.ReviewedByAdminID,
|
||||
GrantedAtMs: item.GrantedAtMS,
|
||||
UpdatedAtMs: item.UpdatedAtMS,
|
||||
}
|
||||
|
||||
@ -0,0 +1,212 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/xerr"
|
||||
domain "hyapp/services/activity-service/internal/domain/wheel"
|
||||
service "hyapp/services/activity-service/internal/service/wheel"
|
||||
)
|
||||
|
||||
type WheelServer struct {
|
||||
activityv1.UnimplementedWheelServiceServer
|
||||
|
||||
svc *service.Service
|
||||
}
|
||||
|
||||
func NewWheelServer(svc *service.Service) *WheelServer {
|
||||
return &WheelServer{svc: svc}
|
||||
}
|
||||
|
||||
func (s *WheelServer) ExecuteWheelDraw(ctx context.Context, req *activityv1.ExecuteWheelDrawRequest) (*activityv1.ExecuteWheelDrawResponse, error) {
|
||||
meta := req.GetWheel()
|
||||
ctx = appcode.WithContext(ctx, meta.GetMeta().GetAppCode())
|
||||
result, err := s.svc.Draw(ctx, domain.DrawCommand{
|
||||
CommandID: meta.GetCommandId(),
|
||||
WheelID: meta.GetWheelId(),
|
||||
UserID: meta.GetUserId(),
|
||||
DeviceID: meta.GetDeviceId(),
|
||||
DrawCount: meta.GetDrawCount(),
|
||||
CoinSpent: meta.GetCoinSpent(),
|
||||
PaidAtMS: meta.GetPaidAtMs(),
|
||||
VisibleRegionID: meta.GetVisibleRegionId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &activityv1.ExecuteWheelDrawResponse{Result: wheelDrawResultToProto(result)}, nil
|
||||
}
|
||||
|
||||
type AdminWheelServer struct {
|
||||
activityv1.UnimplementedAdminWheelServiceServer
|
||||
|
||||
svc *service.Service
|
||||
}
|
||||
|
||||
func NewAdminWheelServer(svc *service.Service) *AdminWheelServer {
|
||||
return &AdminWheelServer{svc: svc}
|
||||
}
|
||||
|
||||
func (s *AdminWheelServer) GetWheelConfig(ctx context.Context, req *activityv1.GetWheelConfigRequest) (*activityv1.GetWheelConfigResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
config, err := s.svc.GetConfig(ctx, req.GetWheelId())
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &activityv1.GetWheelConfigResponse{Config: wheelRuleConfigToProto(config)}, nil
|
||||
}
|
||||
|
||||
func (s *AdminWheelServer) UpsertWheelConfig(ctx context.Context, req *activityv1.UpsertWheelConfigRequest) (*activityv1.UpsertWheelConfigResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
config := wheelRuleConfigFromProto(req.GetConfig())
|
||||
config.CreatedByAdminID = req.GetOperatorAdminId()
|
||||
updated, err := s.svc.UpsertConfig(ctx, config)
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &activityv1.UpsertWheelConfigResponse{Config: wheelRuleConfigToProto(updated)}, nil
|
||||
}
|
||||
|
||||
func (s *AdminWheelServer) ListWheelDraws(ctx context.Context, req *activityv1.ListWheelDrawsRequest) (*activityv1.ListWheelDrawsResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
draws, total, err := s.svc.ListDraws(ctx, domain.DrawQuery{
|
||||
WheelID: req.GetWheelId(),
|
||||
UserID: req.GetUserId(),
|
||||
Status: req.GetStatus(),
|
||||
Page: req.GetPage(),
|
||||
PageSize: req.GetPageSize(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
resp := &activityv1.ListWheelDrawsResponse{Draws: make([]*activityv1.WheelDrawResult, 0, len(draws)), Total: total}
|
||||
for _, draw := range draws {
|
||||
resp.Draws = append(resp.Draws, wheelDrawResultToProto(draw))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *AdminWheelServer) GetWheelDrawSummary(ctx context.Context, req *activityv1.GetWheelDrawSummaryRequest) (*activityv1.GetWheelDrawSummaryResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||||
summary, err := s.svc.GetDrawSummary(ctx, domain.DrawQuery{
|
||||
WheelID: req.GetWheelId(),
|
||||
UserID: req.GetUserId(),
|
||||
Status: req.GetStatus(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &activityv1.GetWheelDrawSummaryResponse{Summary: wheelDrawSummaryToProto(summary)}, nil
|
||||
}
|
||||
|
||||
func wheelRuleConfigFromProto(config *activityv1.WheelRuleConfig) domain.RuleConfig {
|
||||
if config == nil {
|
||||
return domain.RuleConfig{}
|
||||
}
|
||||
tiers := make([]domain.Tier, 0, len(config.GetTiers()))
|
||||
for _, tier := range config.GetTiers() {
|
||||
tiers = append(tiers, domain.Tier{
|
||||
TierID: tier.GetTierId(),
|
||||
DisplayName: tier.GetDisplayName(),
|
||||
RewardType: tier.GetRewardType(),
|
||||
RewardID: tier.GetRewardId(),
|
||||
RewardCount: tier.GetRewardCount(),
|
||||
RewardCoins: tier.GetRewardCoins(),
|
||||
RTPValueCoins: tier.GetRtpValueCoins(),
|
||||
WeightPPM: tier.GetWeightPpm(),
|
||||
Enabled: tier.GetEnabled(),
|
||||
MetadataJSON: tier.GetMetadataJson(),
|
||||
})
|
||||
}
|
||||
return domain.RuleConfig{
|
||||
AppCode: config.GetAppCode(),
|
||||
WheelID: config.GetWheelId(),
|
||||
RuleVersion: config.GetRuleVersion(),
|
||||
Enabled: config.GetEnabled(),
|
||||
DrawPriceCoins: config.GetDrawPriceCoins(),
|
||||
TargetRTPPPM: config.GetTargetRtpPpm(),
|
||||
PoolRatePPM: config.GetPoolRatePpm(),
|
||||
SettlementWindowDraws: config.GetSettlementWindowDraws(),
|
||||
InitialPoolCoins: config.GetInitialPoolCoins(),
|
||||
PoolReserveCoins: config.GetPoolReserveCoins(),
|
||||
MaxSingleRTPPayout: config.GetMaxSingleRtpPayout(),
|
||||
EffectiveFromMS: config.GetEffectiveFromMs(),
|
||||
CreatedByAdminID: config.GetCreatedByAdminId(),
|
||||
CreatedAtMS: config.GetCreatedAtMs(),
|
||||
Tiers: tiers,
|
||||
}
|
||||
}
|
||||
|
||||
func wheelRuleConfigToProto(config domain.RuleConfig) *activityv1.WheelRuleConfig {
|
||||
tiers := make([]*activityv1.WheelPrizeTier, 0, len(config.Tiers))
|
||||
for _, tier := range config.Tiers {
|
||||
tiers = append(tiers, &activityv1.WheelPrizeTier{
|
||||
TierId: tier.TierID,
|
||||
DisplayName: tier.DisplayName,
|
||||
RewardType: tier.RewardType,
|
||||
RewardId: tier.RewardID,
|
||||
RewardCount: tier.RewardCount,
|
||||
RewardCoins: tier.RewardCoins,
|
||||
RtpValueCoins: tier.RTPValueCoins,
|
||||
WeightPpm: tier.WeightPPM,
|
||||
Enabled: tier.Enabled,
|
||||
MetadataJson: tier.MetadataJSON,
|
||||
})
|
||||
}
|
||||
return &activityv1.WheelRuleConfig{
|
||||
AppCode: config.AppCode,
|
||||
WheelId: config.WheelID,
|
||||
RuleVersion: config.RuleVersion,
|
||||
Enabled: config.Enabled,
|
||||
DrawPriceCoins: config.DrawPriceCoins,
|
||||
TargetRtpPpm: config.TargetRTPPPM,
|
||||
PoolRatePpm: config.PoolRatePPM,
|
||||
SettlementWindowDraws: config.SettlementWindowDraws,
|
||||
InitialPoolCoins: config.InitialPoolCoins,
|
||||
PoolReserveCoins: config.PoolReserveCoins,
|
||||
MaxSingleRtpPayout: config.MaxSingleRTPPayout,
|
||||
EffectiveFromMs: config.EffectiveFromMS,
|
||||
CreatedByAdminId: config.CreatedByAdminID,
|
||||
CreatedAtMs: config.CreatedAtMS,
|
||||
Tiers: tiers,
|
||||
}
|
||||
}
|
||||
|
||||
func wheelDrawResultToProto(result domain.DrawResult) *activityv1.WheelDrawResult {
|
||||
return &activityv1.WheelDrawResult{
|
||||
DrawId: result.DrawID,
|
||||
DrawIds: result.DrawIDs,
|
||||
CommandId: result.CommandID,
|
||||
WheelId: result.WheelID,
|
||||
RuleVersion: result.RuleVersion,
|
||||
SelectedTierId: result.SelectedTierID,
|
||||
RewardType: result.RewardType,
|
||||
RewardId: result.RewardID,
|
||||
RewardCount: result.RewardCount,
|
||||
RewardCoins: result.RewardCoins,
|
||||
RtpValueCoins: result.RTPValueCoins,
|
||||
RewardStatus: result.RewardStatus,
|
||||
RtpWindowIndex: result.RTPWindowIndex,
|
||||
ActualRtpPpm: result.ActualRTPPPM,
|
||||
CreatedAtMs: result.CreatedAtMS,
|
||||
WalletTransactionId: result.WalletTransactionID,
|
||||
CoinBalanceAfter: result.CoinBalanceAfter,
|
||||
MetadataJson: result.MetadataJSON,
|
||||
}
|
||||
}
|
||||
|
||||
func wheelDrawSummaryToProto(summary domain.DrawSummary) *activityv1.WheelDrawSummary {
|
||||
return &activityv1.WheelDrawSummary{
|
||||
WheelId: summary.WheelID,
|
||||
TotalDraws: summary.TotalDraws,
|
||||
UniqueUsers: summary.UniqueUsers,
|
||||
TotalSpentCoins: summary.TotalSpentCoins,
|
||||
TotalRtpValueCoins: summary.TotalRTPValueCoins,
|
||||
ActualRtpPpm: summary.ActualRTPPPM,
|
||||
PendingDraws: summary.PendingDraws,
|
||||
GrantedDraws: summary.GrantedDraws,
|
||||
FailedDraws: summary.FailedDraws,
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -51,6 +51,12 @@ grpc_client:
|
||||
app_config:
|
||||
# App 运行时配置由后台 APP配置写入 hyapp_admin,gateway 只读下发给 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"
|
||||
|
||||
@ -55,6 +55,12 @@ grpc_client:
|
||||
app_config:
|
||||
# App 运行时配置由后台 APP配置写入 hyapp_admin,gateway 只读下发给 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"
|
||||
|
||||
@ -51,6 +51,12 @@ grpc_client:
|
||||
app_config:
|
||||
# App 运行时配置由后台 APP配置写入 hyapp_admin,gateway 只读下发给 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 UserSig;SDKAppID 和密钥必须与 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"
|
||||
|
||||
@ -110,6 +110,7 @@ func New(cfg config.Config) (*App, error) {
|
||||
var weeklyStarClient client.WeeklyStarClient = client.NewGRPCWeeklyStarClient(activityConn)
|
||||
var cpWeeklyRankClient client.CPWeeklyRankClient = client.NewGRPCCPWeeklyRankClient(activityConn)
|
||||
var agencyOpeningClient client.AgencyOpeningClient = client.NewGRPCAgencyOpeningClient(activityConn)
|
||||
var wheelClient client.WheelClient = client.NewGRPCWheelClient(activityConn)
|
||||
var broadcastClient client.BroadcastClient = client.NewGRPCBroadcastClient(activityConn)
|
||||
var gameClient client.GameClient = client.NewGRPCGameClient(gameConn)
|
||||
var statisticsClient client.StatisticsClient = client.NewHTTPStatisticsClient(cfg.Statistics.BaseURL, cfg.Statistics.Timeout)
|
||||
@ -184,6 +185,7 @@ func New(cfg config.Config) (*App, error) {
|
||||
handler.SetWeeklyStarClient(weeklyStarClient)
|
||||
handler.SetCPWeeklyRankClient(cpWeeklyRankClient)
|
||||
handler.SetAgencyOpeningClient(agencyOpeningClient)
|
||||
handler.SetWheelClient(wheelClient)
|
||||
handler.SetBroadcastClient(broadcastClient)
|
||||
handler.SetGameClient(gameClient)
|
||||
handler.SetStatisticsClient(statisticsClient)
|
||||
@ -345,7 +347,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) {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ type WalletClient interface {
|
||||
GetMyVip(ctx context.Context, req *walletv1.GetMyVipRequest) (*walletv1.GetMyVipResponse, error)
|
||||
PurchaseVip(ctx context.Context, req *walletv1.PurchaseVipRequest) (*walletv1.PurchaseVipResponse, error)
|
||||
DebitCPBreakupFee(ctx context.Context, req *walletv1.DebitCPBreakupFeeRequest) (*walletv1.DebitCPBreakupFeeResponse, error)
|
||||
DebitWheelDraw(ctx context.Context, req *walletv1.DebitWheelDrawRequest) (*walletv1.DebitWheelDrawResponse, error)
|
||||
GrantVip(ctx context.Context, req *walletv1.GrantVipRequest) (*walletv1.GrantVipResponse, error)
|
||||
TransferCoinFromSeller(ctx context.Context, req *walletv1.TransferCoinFromSellerRequest) (*walletv1.TransferCoinFromSellerResponse, error)
|
||||
ListCoinSellerSalaryExchangeRateTiers(ctx context.Context, req *walletv1.ListCoinSellerSalaryExchangeRateTiersRequest) (*walletv1.ListCoinSellerSalaryExchangeRateTiersResponse, error)
|
||||
@ -138,6 +139,10 @@ func (c *grpcWalletClient) DebitCPBreakupFee(ctx context.Context, req *walletv1.
|
||||
return c.client.DebitCPBreakupFee(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) DebitWheelDraw(ctx context.Context, req *walletv1.DebitWheelDrawRequest) (*walletv1.DebitWheelDrawResponse, error) {
|
||||
return c.client.DebitWheelDraw(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) GrantVip(ctx context.Context, req *walletv1.GrantVipRequest) (*walletv1.GrantVipResponse, error) {
|
||||
return c.client.GrantVip(ctx, req)
|
||||
}
|
||||
|
||||
40
services/gateway-service/internal/client/wheel_client.go
Normal file
40
services/gateway-service/internal/client/wheel_client.go
Normal file
@ -0,0 +1,40 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// WheelClient abstracts gateway access to activity-service wheel config and draw execution.
|
||||
type WheelClient interface {
|
||||
ExecuteWheelDraw(ctx context.Context, req *activityv1.ExecuteWheelDrawRequest) (*activityv1.ExecuteWheelDrawResponse, error)
|
||||
GetWheelConfig(ctx context.Context, req *activityv1.GetWheelConfigRequest) (*activityv1.GetWheelConfigResponse, error)
|
||||
ListWheelDraws(ctx context.Context, req *activityv1.ListWheelDrawsRequest) (*activityv1.ListWheelDrawsResponse, error)
|
||||
}
|
||||
|
||||
type grpcWheelClient struct {
|
||||
wheel activityv1.WheelServiceClient
|
||||
admin activityv1.AdminWheelServiceClient
|
||||
}
|
||||
|
||||
func NewGRPCWheelClient(conn *grpc.ClientConn) WheelClient {
|
||||
return &grpcWheelClient{
|
||||
wheel: activityv1.NewWheelServiceClient(conn),
|
||||
admin: activityv1.NewAdminWheelServiceClient(conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *grpcWheelClient) ExecuteWheelDraw(ctx context.Context, req *activityv1.ExecuteWheelDrawRequest) (*activityv1.ExecuteWheelDrawResponse, error) {
|
||||
return c.wheel.ExecuteWheelDraw(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWheelClient) GetWheelConfig(ctx context.Context, req *activityv1.GetWheelConfigRequest) (*activityv1.GetWheelConfigResponse, error) {
|
||||
return c.admin.GetWheelConfig(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWheelClient) ListWheelDraws(ctx context.Context, req *activityv1.ListWheelDrawsRequest) (*activityv1.ListWheelDrawsResponse, error) {
|
||||
return c.admin.ListWheelDraws(ctx, req)
|
||||
}
|
||||
@ -115,6 +115,16 @@ type LoginRiskFastGuardConfig struct {
|
||||
type AppConfigConfig struct {
|
||||
// MySQLDSN 指向后台管理库 hyapp_admin;gateway 只读 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)
|
||||
|
||||
@ -65,6 +65,7 @@ type agencyOpeningRecordData struct {
|
||||
CreatedAt string `json:"created_at,omitempty"`
|
||||
OpeningRevenue string `json:"opening_revenue,omitempty"`
|
||||
Reward int64 `json:"reward"`
|
||||
ScoreEndMS int64 `json:"score_end_ms,omitempty"`
|
||||
}
|
||||
|
||||
type agencyOpeningApplicationData struct {
|
||||
@ -84,6 +85,10 @@ type agencyOpeningApplicationData struct {
|
||||
WalletTransactionID string `json:"wallet_transaction_id,omitempty"`
|
||||
FailureReason string `json:"failure_reason,omitempty"`
|
||||
AppliedAtMS int64 `json:"applied_at_ms"`
|
||||
ApprovedAtMS int64 `json:"approved_at_ms,omitempty"`
|
||||
ScoreStartMS int64 `json:"score_start_ms,omitempty"`
|
||||
ScoreEndMS int64 `json:"score_end_ms,omitempty"`
|
||||
ReviewedByAdminID int64 `json:"reviewed_by_admin_id,omitempty"`
|
||||
GrantedAtMS int64 `json:"granted_at_ms,omitempty"`
|
||||
UpdatedAtMS int64 `json:"updated_at_ms,omitempty"`
|
||||
}
|
||||
@ -221,11 +226,8 @@ func agencyOpeningQualificationFromProto(status *activityv1.GetAgencyOpeningStat
|
||||
agencyName = application.GetAgencyName()
|
||||
}
|
||||
}
|
||||
openingStatus := "Not Joined"
|
||||
if status.GetJoined() {
|
||||
openingStatus = "Joined"
|
||||
}
|
||||
if !status.GetEnabled() {
|
||||
openingStatus := agencyOpeningStatusLabel(application)
|
||||
if !status.GetEnabled() && !status.GetJoined() {
|
||||
openingStatus = "Disabled"
|
||||
}
|
||||
return agencyOpeningQualificationData{
|
||||
@ -266,6 +268,7 @@ func agencyOpeningRecordFromProto(application *activityv1.AgencyOpeningApplicati
|
||||
CreatedAt: agencyOpeningDate(application.GetAgencyCreatedAtMs()),
|
||||
OpeningRevenue: fmt.Sprintf("%d", application.GetScoreCoinAmount()),
|
||||
Reward: application.GetRewardCoinAmount(),
|
||||
ScoreEndMS: application.GetScoreEndMs(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,11 +301,37 @@ func agencyOpeningApplicationFromProto(item *activityv1.AgencyOpeningApplication
|
||||
WalletTransactionID: item.GetWalletTransactionId(),
|
||||
FailureReason: item.GetFailureReason(),
|
||||
AppliedAtMS: item.GetAppliedAtMs(),
|
||||
ApprovedAtMS: item.GetApprovedAtMs(),
|
||||
ScoreStartMS: item.GetScoreStartMs(),
|
||||
ScoreEndMS: item.GetScoreEndMs(),
|
||||
ReviewedByAdminID: item.GetReviewedByAdminId(),
|
||||
GrantedAtMS: item.GetGrantedAtMs(),
|
||||
UpdatedAtMS: item.GetUpdatedAtMs(),
|
||||
}
|
||||
}
|
||||
|
||||
func agencyOpeningStatusLabel(application *activityv1.AgencyOpeningApplication) string {
|
||||
if application == nil {
|
||||
return "Not Joined"
|
||||
}
|
||||
switch application.GetStatus() {
|
||||
case "applied":
|
||||
return "Pending Review"
|
||||
case "approved":
|
||||
return "Approved"
|
||||
case "pending":
|
||||
return "Pending Reward"
|
||||
case "granted":
|
||||
return "Rewarded"
|
||||
case "failed":
|
||||
return "Reward Failed"
|
||||
case "expired":
|
||||
return "Expired"
|
||||
default:
|
||||
return "Joined"
|
||||
}
|
||||
}
|
||||
|
||||
func formatAgencyOpeningCoinLabel(value int64) string {
|
||||
if value <= 0 {
|
||||
return "0"
|
||||
@ -322,7 +351,8 @@ func agencyOpeningRules(cycle *activityv1.AgencyOpeningCycle) []string {
|
||||
}
|
||||
return []string{
|
||||
fmt.Sprintf("Agency must have more than %d hosts before applying.", cycle.GetMinHostCount()),
|
||||
"Opening revenue comes from the applicant user's room gift COIN revenue during the configured period.",
|
||||
"Opening revenue starts from admin approval and only counts the applicant user's room gift COIN revenue within the next 24 hours.",
|
||||
"If the 24-hour scoring window passes the activity end time, the activity end time is used as the cutoff.",
|
||||
"Reward tier is matched by opening revenue after the period ends; it is not based on Top ranking.",
|
||||
"Rewards are granted automatically after the period ends.",
|
||||
}
|
||||
|
||||
@ -0,0 +1,215 @@
|
||||
package activityapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/services/gateway-service/internal/auth"
|
||||
)
|
||||
|
||||
func TestGetAgencyOpeningStatusReturnsReviewWindowFields(t *testing.T) {
|
||||
client := &fakeAgencyOpeningClient{statusResp: agencyOpeningApprovedStatusResponse()}
|
||||
handler := New(Config{AgencyOpening: client})
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/activities/agency-opening-event", nil)
|
||||
request = request.WithContext(auth.WithUserID(appcode.WithContext(request.Context(), "lalu"), 42001))
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
handler.getAgencyOpeningStatus(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if client.lastStatus == nil || client.lastStatus.GetUserId() != 42001 || client.lastStatus.GetMeta().GetAppCode() != "lalu" {
|
||||
t.Fatalf("status request mismatch: %+v", client.lastStatus)
|
||||
}
|
||||
|
||||
var envelope struct {
|
||||
Code string `json:"code"`
|
||||
Data struct {
|
||||
Joined bool `json:"joined"`
|
||||
Qualification struct {
|
||||
OpeningStatus string `json:"opening_status"`
|
||||
} `json:"qualification"`
|
||||
Application struct {
|
||||
Status string `json:"status"`
|
||||
ApprovedAtMS int64 `json:"approved_at_ms"`
|
||||
ScoreStartMS int64 `json:"score_start_ms"`
|
||||
ScoreEndMS int64 `json:"score_end_ms"`
|
||||
ReviewedByAdminID int64 `json:"reviewed_by_admin_id"`
|
||||
} `json:"application"`
|
||||
Rules []string `json:"rules"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(recorder.Body.Bytes(), &envelope); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if envelope.Code != "OK" || !envelope.Data.Joined || envelope.Data.Qualification.OpeningStatus != "Approved" {
|
||||
t.Fatalf("status envelope mismatch: %+v", envelope)
|
||||
}
|
||||
if envelope.Data.Application.Status != "approved" ||
|
||||
envelope.Data.Application.ApprovedAtMS != 2000 ||
|
||||
envelope.Data.Application.ScoreStartMS != 2000 ||
|
||||
envelope.Data.Application.ScoreEndMS != 2000+24*60*60*1000 ||
|
||||
envelope.Data.Application.ReviewedByAdminID != 7 {
|
||||
t.Fatalf("application fields mismatch: %+v", envelope.Data.Application)
|
||||
}
|
||||
if len(envelope.Data.Rules) < 2 || !strings.Contains(envelope.Data.Rules[1], "24 hours") {
|
||||
t.Fatalf("rules should explain 24-hour scoring window: %+v", envelope.Data.Rules)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyAgencyOpeningReturnsPendingReviewStatus(t *testing.T) {
|
||||
client := &fakeAgencyOpeningClient{
|
||||
applyResp: agencyOpeningApplyResponse(),
|
||||
statusResp: agencyOpeningAppliedStatusResponse(),
|
||||
}
|
||||
handler := New(Config{AgencyOpening: client})
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/activities/agency-opening-event/apply", strings.NewReader(`{"command_id":"cmd-apply-1"}`))
|
||||
request = request.WithContext(auth.WithUserID(appcode.WithContext(request.Context(), "lalu"), 42001))
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
handler.applyAgencyOpening(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if client.lastApply == nil || client.lastApply.GetUserId() != 42001 || client.lastApply.GetCommandId() != "cmd-apply-1" {
|
||||
t.Fatalf("apply request mismatch: %+v", client.lastApply)
|
||||
}
|
||||
|
||||
var envelope struct {
|
||||
Code string `json:"code"`
|
||||
Data struct {
|
||||
Joined bool `json:"joined"`
|
||||
Qualification struct {
|
||||
OpeningStatus string `json:"opening_status"`
|
||||
} `json:"qualification"`
|
||||
Application struct {
|
||||
Status string `json:"status"`
|
||||
AppliedAtMS int64 `json:"applied_at_ms"`
|
||||
ScoreStartMS int64 `json:"score_start_ms"`
|
||||
} `json:"application"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(recorder.Body.Bytes(), &envelope); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if envelope.Code != "OK" || !envelope.Data.Joined || envelope.Data.Qualification.OpeningStatus != "Pending Review" {
|
||||
t.Fatalf("apply response should show pending review: %+v", envelope)
|
||||
}
|
||||
if envelope.Data.Application.Status != "applied" || envelope.Data.Application.AppliedAtMS != 1000 || envelope.Data.Application.ScoreStartMS != 0 {
|
||||
t.Fatalf("apply application fields mismatch: %+v", envelope.Data.Application)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeAgencyOpeningClient struct {
|
||||
statusResp *activityv1.GetAgencyOpeningStatusResponse
|
||||
applyResp *activityv1.ApplyAgencyOpeningResponse
|
||||
|
||||
lastStatus *activityv1.GetAgencyOpeningStatusRequest
|
||||
lastApply *activityv1.ApplyAgencyOpeningRequest
|
||||
}
|
||||
|
||||
func (f *fakeAgencyOpeningClient) GetAgencyOpeningStatus(_ context.Context, req *activityv1.GetAgencyOpeningStatusRequest) (*activityv1.GetAgencyOpeningStatusResponse, error) {
|
||||
f.lastStatus = req
|
||||
if f.statusResp != nil {
|
||||
return f.statusResp, nil
|
||||
}
|
||||
return &activityv1.GetAgencyOpeningStatusResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeAgencyOpeningClient) ApplyAgencyOpening(_ context.Context, req *activityv1.ApplyAgencyOpeningRequest) (*activityv1.ApplyAgencyOpeningResponse, error) {
|
||||
f.lastApply = req
|
||||
if f.applyResp != nil {
|
||||
return f.applyResp, nil
|
||||
}
|
||||
return &activityv1.ApplyAgencyOpeningResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeAgencyOpeningClient) ListAgencyOpeningLeaderboard(context.Context, *activityv1.ListAgencyOpeningApplicationsRequest) (*activityv1.ListAgencyOpeningApplicationsResponse, error) {
|
||||
return &activityv1.ListAgencyOpeningApplicationsResponse{}, nil
|
||||
}
|
||||
|
||||
func agencyOpeningApplyResponse() *activityv1.ApplyAgencyOpeningResponse {
|
||||
return &activityv1.ApplyAgencyOpeningResponse{
|
||||
Created: true,
|
||||
Application: &activityv1.AgencyOpeningApplication{
|
||||
ApplicationId: "application-1",
|
||||
CycleId: "cycle-1",
|
||||
AgencyId: 8001,
|
||||
AgencyOwnerUserId: 42001,
|
||||
AgencyName: "Window Agency",
|
||||
HostCount: 12,
|
||||
Status: "applied",
|
||||
AppliedAtMs: 1000,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func agencyOpeningAppliedStatusResponse() *activityv1.GetAgencyOpeningStatusResponse {
|
||||
resp := agencyOpeningBaseStatusResponse()
|
||||
resp.Joined = true
|
||||
resp.Eligible = false
|
||||
resp.Application = agencyOpeningApplyResponse().GetApplication()
|
||||
return resp
|
||||
}
|
||||
|
||||
func agencyOpeningApprovedStatusResponse() *activityv1.GetAgencyOpeningStatusResponse {
|
||||
resp := agencyOpeningBaseStatusResponse()
|
||||
resp.Joined = true
|
||||
resp.Eligible = false
|
||||
resp.Application = &activityv1.AgencyOpeningApplication{
|
||||
ApplicationId: "application-1",
|
||||
CycleId: "cycle-1",
|
||||
AgencyId: 8001,
|
||||
AgencyOwnerUserId: 42001,
|
||||
AgencyName: "Window Agency",
|
||||
HostCount: 12,
|
||||
Status: "approved",
|
||||
ScoreCoinAmount: 900,
|
||||
RewardThresholdCoinSpent: 500,
|
||||
RewardCoinAmount: 50,
|
||||
AppliedAtMs: 1000,
|
||||
ApprovedAtMs: 2000,
|
||||
ScoreStartMs: 2000,
|
||||
ScoreEndMs: 2000 + int64((24 * 60 * 60 * 1000)),
|
||||
ReviewedByAdminId: 7,
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
func agencyOpeningBaseStatusResponse() *activityv1.GetAgencyOpeningStatusResponse {
|
||||
return &activityv1.GetAgencyOpeningStatusResponse{
|
||||
ServerTimeMs: 3000,
|
||||
Enabled: true,
|
||||
Eligible: true,
|
||||
Joined: false,
|
||||
Cycle: &activityv1.AgencyOpeningCycle{
|
||||
CycleId: "cycle-1",
|
||||
Title: "Agency Opening",
|
||||
Status: "active",
|
||||
StartMs: 1,
|
||||
EndMs: 2000 + int64((48 * 60 * 60 * 1000)),
|
||||
MinHostCount: 10,
|
||||
Rewards: []*activityv1.AgencyOpeningReward{{
|
||||
RankNo: 1,
|
||||
ThresholdCoinSpent: 500,
|
||||
RewardCoinAmount: 50,
|
||||
}},
|
||||
},
|
||||
Agency: &activityv1.AgencyOpeningAgencySnapshot{
|
||||
AgencyId: 8001,
|
||||
OwnerUserId: 42001,
|
||||
Name: "Window Agency",
|
||||
HostCount: 12,
|
||||
AgencyCreatedAtMs: 1,
|
||||
Status: "active",
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -27,6 +27,7 @@ type Handler struct {
|
||||
weeklyStar client.WeeklyStarClient
|
||||
cpWeeklyRank client.CPWeeklyRankClient
|
||||
agencyOpening client.AgencyOpeningClient
|
||||
wheel client.WheelClient
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@ -47,6 +48,7 @@ type Config struct {
|
||||
WeeklyStar client.WeeklyStarClient
|
||||
CPWeeklyRank client.CPWeeklyRankClient
|
||||
AgencyOpening client.AgencyOpeningClient
|
||||
Wheel client.WheelClient
|
||||
}
|
||||
|
||||
func New(config Config) *Handler {
|
||||
@ -68,6 +70,7 @@ func New(config Config) *Handler {
|
||||
weeklyStar: config.WeeklyStar,
|
||||
cpWeeklyRank: config.CPWeeklyRank,
|
||||
agencyOpening: config.AgencyOpening,
|
||||
wheel: config.Wheel,
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,6 +96,10 @@ func (h *Handler) TaskHandlers() httproutes.TaskHandlers {
|
||||
GetAgencyOpeningStatus: h.getAgencyOpeningStatus,
|
||||
ApplyAgencyOpening: h.applyAgencyOpening,
|
||||
ListAgencyOpeningLeaderboard: h.listAgencyOpeningLeaderboard,
|
||||
GetWheelConfig: h.getWheelConfig,
|
||||
DrawWheel: h.drawWheel,
|
||||
ListWheelHistory: h.listWheelHistory,
|
||||
ListWheelHints: h.listWheelHints,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,349 @@
|
||||
package activityapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
walletv1 "hyapp.local/api/proto/wallet/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/idgen"
|
||||
"hyapp/services/gateway-service/internal/auth"
|
||||
"hyapp/services/gateway-service/internal/transport/http/httpkit"
|
||||
)
|
||||
|
||||
type wheelDrawBody struct {
|
||||
Amount int64 `json:"amount"`
|
||||
CommandID string `json:"command_id"`
|
||||
RoomID string `json:"roomId"`
|
||||
Times int32 `json:"times"`
|
||||
}
|
||||
|
||||
type wheelConfigData struct {
|
||||
WheelID string `json:"wheel_id"`
|
||||
Enabled bool `json:"enabled"`
|
||||
DrawPriceCoins int64 `json:"draw_price_coins"`
|
||||
Rewards []wheelPrizeData `json:"rewards"`
|
||||
}
|
||||
|
||||
type wheelPrizeData struct {
|
||||
TierID string `json:"tier_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
RewardType string `json:"reward_type"`
|
||||
RewardID string `json:"reward_id"`
|
||||
RewardCount int64 `json:"reward_count"`
|
||||
RewardCoins int64 `json:"reward_coins"`
|
||||
Enabled bool `json:"enabled"`
|
||||
MetadataJSON string `json:"metadata_json"`
|
||||
PreviewURL string `json:"preview_url"`
|
||||
AnimationURL string `json:"animation_url"`
|
||||
Value int64 `json:"value"`
|
||||
}
|
||||
|
||||
type wheelDrawData struct {
|
||||
DrawID string `json:"draw_id"`
|
||||
DrawIDs []string `json:"draw_ids"`
|
||||
CommandID string `json:"command_id"`
|
||||
WheelID string `json:"wheel_id"`
|
||||
SelectedTierID string `json:"selected_tier_id"`
|
||||
RewardType string `json:"reward_type"`
|
||||
RewardID string `json:"reward_id"`
|
||||
RewardCount int64 `json:"reward_count"`
|
||||
RewardCoins int64 `json:"reward_coins"`
|
||||
RewardStatus string `json:"reward_status"`
|
||||
WalletTransactionID string `json:"wallet_transaction_id"`
|
||||
CoinBalanceAfter int64 `json:"coin_balance_after"`
|
||||
MetadataJSON string `json:"metadata_json"`
|
||||
RewardValue int64 `json:"rewardValue"`
|
||||
Rewards []wheelPrizeData `json:"rewards"`
|
||||
}
|
||||
|
||||
// getWheelConfig 返回 H5 渲染所需的当前奖池配置;只暴露资源图字段,不暴露后台 RTP 控制窗口。
|
||||
func (h *Handler) getWheelConfig(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.wheel == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
resp, err := h.wheel.GetWheelConfig(request.Context(), &activityv1.GetWheelConfigRequest{
|
||||
Meta: httpkit.ActivityMeta(request),
|
||||
WheelId: wheelIDFromRequest(request),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, wheelConfigFromProto(resp.GetConfig()))
|
||||
}
|
||||
|
||||
// drawWheel 先完成钱包扣费,再把扣费事实传给 activity-service 抽奖;任何一步失败都直接返回错误,不伪造中奖。
|
||||
func (h *Handler) drawWheel(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.wheel == nil || h.walletClient == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
var body wheelDrawBody
|
||||
if err := httpkit.DecodeJSON(request.Body, &body); err != nil && !errors.Is(err, io.EOF) {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidJSON, "invalid request body")
|
||||
return
|
||||
}
|
||||
wheelID := wheelIDFromRequest(request)
|
||||
times := body.Times
|
||||
if times <= 0 {
|
||||
times = 1
|
||||
}
|
||||
configResp, err := h.wheel.GetWheelConfig(request.Context(), &activityv1.GetWheelConfigRequest{
|
||||
Meta: httpkit.ActivityMeta(request),
|
||||
WheelId: wheelID,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
config := configResp.GetConfig()
|
||||
if config == nil || !config.GetEnabled() {
|
||||
httpkit.WriteError(writer, request, http.StatusConflict, httpkit.CodeInvalidArgument, "wheel disabled")
|
||||
return
|
||||
}
|
||||
expectedAmount := config.GetDrawPriceCoins() * int64(times)
|
||||
if body.Amount > 0 && body.Amount != expectedAmount {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "draw amount mismatch")
|
||||
return
|
||||
}
|
||||
commandID := strings.TrimSpace(body.CommandID)
|
||||
if commandID == "" {
|
||||
commandID = idgen.New("wheel")
|
||||
}
|
||||
debitResp, err := h.walletClient.DebitWheelDraw(request.Context(), &walletv1.DebitWheelDrawRequest{
|
||||
CommandId: commandID,
|
||||
AppCode: appcode.FromContext(request.Context()),
|
||||
UserId: auth.UserIDFromContext(request.Context()),
|
||||
WheelId: wheelID,
|
||||
DrawCount: times,
|
||||
Amount: expectedAmount,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
drawResp, err := h.wheel.ExecuteWheelDraw(request.Context(), &activityv1.ExecuteWheelDrawRequest{
|
||||
Wheel: &activityv1.WheelDrawMeta{
|
||||
Meta: httpkit.ActivityMeta(request),
|
||||
CommandId: commandID,
|
||||
WheelId: wheelID,
|
||||
UserId: auth.UserIDFromContext(request.Context()),
|
||||
DeviceId: wheelDeviceID(request),
|
||||
DrawCount: times,
|
||||
CoinSpent: debitResp.GetCoinSpent(),
|
||||
PaidAtMs: time.Now().UTC().UnixMilli(),
|
||||
VisibleRegionId: 0,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
data := wheelDrawFromProto(drawResp.GetResult())
|
||||
data.WalletTransactionID = debitResp.GetTransactionId()
|
||||
data.CoinBalanceAfter = debitResp.GetCoinBalanceAfter()
|
||||
httpkit.WriteOK(writer, request, data)
|
||||
}
|
||||
|
||||
// listWheelHistory 返回当前用户的转盘抽奖记录;读侧复用 activity-service 明细,避免 H5 直接拼后台接口。
|
||||
func (h *Handler) listWheelHistory(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.wheel == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
resp, err := h.wheel.ListWheelDraws(request.Context(), &activityv1.ListWheelDrawsRequest{
|
||||
Meta: httpkit.ActivityMeta(request),
|
||||
WheelId: wheelIDFromRequest(request),
|
||||
UserId: auth.UserIDFromContext(request.Context()),
|
||||
Page: int32(queryInt(request, "pageNo", 1)),
|
||||
PageSize: int32(queryInt(request, "pageSize", 20)),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
records := make([]map[string]any, 0, len(resp.GetDraws()))
|
||||
for _, item := range resp.GetDraws() {
|
||||
draw := wheelDrawFromProto(item)
|
||||
records = append(records, map[string]any{
|
||||
"createdTime": item.GetCreatedAtMs(),
|
||||
"drawTimes": len(item.GetDrawIds()),
|
||||
"rewardValue": draw.RewardValue,
|
||||
"rewards": draw.Rewards,
|
||||
})
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{"records": records, "total": resp.GetTotal()})
|
||||
}
|
||||
|
||||
// listWheelHints 返回最近中奖提示;昵称不在 activity-service 明细里,这里用用户 ID 占位,后续可接 user profile 批量补齐。
|
||||
func (h *Handler) listWheelHints(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.wheel == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
resp, err := h.wheel.ListWheelDraws(request.Context(), &activityv1.ListWheelDrawsRequest{
|
||||
Meta: httpkit.ActivityMeta(request),
|
||||
WheelId: wheelIDFromRequest(request),
|
||||
Status: "granted",
|
||||
Page: 1,
|
||||
PageSize: 20,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
values := make([]map[string]any, 0, len(resp.GetDraws()))
|
||||
for _, item := range resp.GetDraws() {
|
||||
reward := wheelPrizeFromDraw(item)
|
||||
values = append(values, map[string]any{
|
||||
"avatar": reward.PreviewURL,
|
||||
"nickname": fmt.Sprintf("Winner %d", len(values)+1),
|
||||
"value": reward.DisplayName,
|
||||
})
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{"values": values})
|
||||
}
|
||||
|
||||
func wheelIDFromRequest(request *http.Request) string {
|
||||
value := strings.TrimSpace(request.PathValue("wheel_id"))
|
||||
if value == "" {
|
||||
return "classic"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func wheelDeviceID(request *http.Request) string {
|
||||
for _, value := range []string{
|
||||
httpkit.FirstQueryOrHeader(request, "device_id", "X-Device-ID", "X-Hyapp-Device-ID"),
|
||||
auth.SessionIDFromContext(request.Context()),
|
||||
} {
|
||||
if strings.TrimSpace(value) != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return "h5"
|
||||
}
|
||||
|
||||
func wheelConfigFromProto(config *activityv1.WheelRuleConfig) wheelConfigData {
|
||||
if config == nil {
|
||||
return wheelConfigData{Rewards: []wheelPrizeData{}}
|
||||
}
|
||||
rewards := make([]wheelPrizeData, 0, len(config.GetTiers()))
|
||||
for _, tier := range config.GetTiers() {
|
||||
rewards = append(rewards, wheelPrizeFromTier(tier))
|
||||
}
|
||||
return wheelConfigData{
|
||||
WheelID: config.GetWheelId(),
|
||||
Enabled: config.GetEnabled(),
|
||||
DrawPriceCoins: config.GetDrawPriceCoins(),
|
||||
Rewards: rewards,
|
||||
}
|
||||
}
|
||||
|
||||
func wheelPrizeFromTier(tier *activityv1.WheelPrizeTier) wheelPrizeData {
|
||||
if tier == nil {
|
||||
return wheelPrizeData{}
|
||||
}
|
||||
previewURL, animationURL := wheelAssetURLs(tier.GetRewardType(), tier.GetMetadataJson())
|
||||
return wheelPrizeData{
|
||||
TierID: tier.GetTierId(),
|
||||
DisplayName: tier.GetDisplayName(),
|
||||
RewardType: tier.GetRewardType(),
|
||||
RewardID: tier.GetRewardId(),
|
||||
RewardCount: tier.GetRewardCount(),
|
||||
RewardCoins: tier.GetRewardCoins(),
|
||||
Enabled: tier.GetEnabled(),
|
||||
MetadataJSON: tier.GetMetadataJson(),
|
||||
PreviewURL: previewURL,
|
||||
AnimationURL: animationURL,
|
||||
Value: wheelPrizeDisplayValue(tier.GetRewardCoins(), tier.GetRtpValueCoins(), tier.GetRewardCount()),
|
||||
}
|
||||
}
|
||||
|
||||
func wheelDrawFromProto(item *activityv1.WheelDrawResult) wheelDrawData {
|
||||
if item == nil {
|
||||
return wheelDrawData{Rewards: []wheelPrizeData{}}
|
||||
}
|
||||
reward := wheelPrizeFromDraw(item)
|
||||
return wheelDrawData{
|
||||
DrawID: item.GetDrawId(),
|
||||
DrawIDs: item.GetDrawIds(),
|
||||
CommandID: item.GetCommandId(),
|
||||
WheelID: item.GetWheelId(),
|
||||
SelectedTierID: item.GetSelectedTierId(),
|
||||
RewardType: item.GetRewardType(),
|
||||
RewardID: item.GetRewardId(),
|
||||
RewardCount: item.GetRewardCount(),
|
||||
RewardCoins: item.GetRewardCoins(),
|
||||
RewardStatus: item.GetRewardStatus(),
|
||||
WalletTransactionID: item.GetWalletTransactionId(),
|
||||
CoinBalanceAfter: item.GetCoinBalanceAfter(),
|
||||
MetadataJSON: item.GetMetadataJson(),
|
||||
RewardValue: reward.Value,
|
||||
Rewards: []wheelPrizeData{reward},
|
||||
}
|
||||
}
|
||||
|
||||
func wheelPrizeFromDraw(item *activityv1.WheelDrawResult) wheelPrizeData {
|
||||
if item == nil {
|
||||
return wheelPrizeData{}
|
||||
}
|
||||
previewURL, animationURL := wheelAssetURLs(item.GetRewardType(), item.GetMetadataJson())
|
||||
return wheelPrizeData{
|
||||
TierID: item.GetSelectedTierId(),
|
||||
DisplayName: item.GetSelectedTierId(),
|
||||
RewardType: item.GetRewardType(),
|
||||
RewardID: item.GetRewardId(),
|
||||
RewardCount: item.GetRewardCount(),
|
||||
RewardCoins: item.GetRewardCoins(),
|
||||
MetadataJSON: item.GetMetadataJson(),
|
||||
PreviewURL: previewURL,
|
||||
AnimationURL: animationURL,
|
||||
Value: wheelPrizeDisplayValue(item.GetRewardCoins(), item.GetRtpValueCoins(), item.GetRewardCount()),
|
||||
}
|
||||
}
|
||||
|
||||
func wheelPrizeDisplayValue(rewardCoins int64, internalValueCoins int64, rewardCount int64) int64 {
|
||||
// H5 只需要一个展示值,不能把后台 RTP 字段原样暴露出去;金币奖品展示金币数,礼物可展示内部估值。
|
||||
// 道具和装扮不计入 RTP 时内部估值会是 0,这时回退奖励数量,避免页面拿到 value=0 后看起来像奖品没有价值。
|
||||
if rewardCoins > 0 {
|
||||
return rewardCoins
|
||||
}
|
||||
if internalValueCoins > 0 {
|
||||
return internalValueCoins
|
||||
}
|
||||
if rewardCount > 0 {
|
||||
return rewardCount
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func wheelAssetURLs(rewardType string, metadataJSON string) (string, string) {
|
||||
var metadata map[string]any
|
||||
if err := json.NewDecoder(strings.NewReader(strings.TrimSpace(metadataJSON))).Decode(&metadata); err != nil && err != io.EOF {
|
||||
return "", ""
|
||||
}
|
||||
preview := firstMetadataString(metadata, "preview_url", "previewUrl", "asset_url", "assetUrl")
|
||||
if strings.EqualFold(strings.TrimSpace(rewardType), "coin") {
|
||||
return preview, ""
|
||||
}
|
||||
animation := firstMetadataString(metadata, "animation_url", "animationUrl")
|
||||
return preview, animation
|
||||
}
|
||||
|
||||
func firstMetadataString(metadata map[string]any, keys ...string) string {
|
||||
for _, key := range keys {
|
||||
if value, ok := metadata[key].(string); ok && strings.TrimSpace(value) != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user