package service import ( "context" "fmt" "slices" "hyapp/pkg/appcode" "hyapp/pkg/xerr" ) const defaultRoomSeatCount int32 = 15 var roomSeatCountCandidates = []int32{10, 15, 20, 25, 30} func defaultRoomSeatConfig(appCode string) RoomSeatConfig { allowed := append([]int32(nil), roomSeatCountCandidates...) return RoomSeatConfig{ AppCode: appcode.Normalize(appCode), AllowedSeatCounts: allowed, DefaultSeatCount: defaultRoomSeatCount, } } func (s *Service) resolveRoomSeatCount(ctx context.Context, requested int32) (int32, error) { if requested < 0 { // 负数没有业务语义,不能让它落到默认值分支掩盖客户端错误。 return 0, xerr.New(xerr.InvalidArgument, "seat_count is invalid") } config, err := s.currentRoomSeatConfig(ctx) if err != nil { return 0, err } if requested == 0 { return config.DefaultSeatCount, nil } if !seatCountAllowed(config.AllowedSeatCounts, requested) { return 0, xerr.New(xerr.InvalidArgument, fmt.Sprintf("seat_count must be one of %v", config.AllowedSeatCounts)) } return requested, nil } func (s *Service) validateRoomSeatCount(ctx context.Context, requested int32) (int32, error) { if requested <= 0 { return 0, xerr.New(xerr.InvalidArgument, "seat_count is invalid") } config, err := s.currentRoomSeatConfig(ctx) if err != nil { return 0, err } if !seatCountAllowed(config.AllowedSeatCounts, requested) { return 0, xerr.New(xerr.InvalidArgument, fmt.Sprintf("seat_count must be one of %v", config.AllowedSeatCounts)) } return requested, nil } func (s *Service) currentRoomSeatConfig(ctx context.Context) (RoomSeatConfig, error) { config, exists, err := s.repository.GetRoomSeatConfig(ctx) if err != nil { return RoomSeatConfig{}, err } if !exists { // 本地新库会通过 initdb/Migrate 写默认行;该兜底保护测试或手动库缺行时仍能按产品默认创建房间。 return defaultRoomSeatConfig(appcode.FromContext(ctx)), nil } normalized, err := normalizeRoomSeatConfig(config) if err != nil { return RoomSeatConfig{}, xerr.New(xerr.Unavailable, "room seat config is invalid") } return normalized, nil } func normalizeRoomSeatConfig(config RoomSeatConfig) (RoomSeatConfig, error) { seen := make(map[int32]bool, len(config.AllowedSeatCounts)) allowed := make([]int32, 0, len(config.AllowedSeatCounts)) for _, value := range config.AllowedSeatCounts { if seen[value] { continue } if !seatCountAllowed(roomSeatCountCandidates, value) { return RoomSeatConfig{}, fmt.Errorf("seat count candidate is invalid: %d", value) } seen[value] = true allowed = append(allowed, value) } slices.Sort(allowed) if len(allowed) == 0 { return RoomSeatConfig{}, fmt.Errorf("allowed seat counts are empty") } if !seatCountAllowed(allowed, config.DefaultSeatCount) { return RoomSeatConfig{}, fmt.Errorf("default seat count is not allowed: %d", config.DefaultSeatCount) } config.AllowedSeatCounts = allowed config.AppCode = appcode.Normalize(config.AppCode) return config, nil } func seatCountAllowed(values []int32, target int32) bool { return slices.Contains(values, target) }