104 lines
3.1 KiB
Go
104 lines
3.1 KiB
Go
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)
|
|
}
|