|
@@ -1,219 +0,0 @@
|
|
|
-package service
|
|
|
-
|
|
|
-import (
|
|
|
- "context"
|
|
|
- "fmt"
|
|
|
- "github.com/go-nunu/nunu-layout-advanced/internal/repository"
|
|
|
- "github.com/sourcegraph/conc/pool"
|
|
|
- "math/rand"
|
|
|
- "strconv"
|
|
|
- "strings"
|
|
|
- "sync"
|
|
|
- "time"
|
|
|
-)
|
|
|
-
|
|
|
-type GenerateIpService interface {
|
|
|
- GenerateMultipleLoopbackIps(ctx context.Context, count ...int) ([]string, error)
|
|
|
-}
|
|
|
-
|
|
|
-func NewGenerateIpService(
|
|
|
- service *Service,
|
|
|
- gameShieldRepository repository.GameShieldRepository,
|
|
|
-) GenerateIpService {
|
|
|
- return &generateIpService{
|
|
|
- Service: service,
|
|
|
- gameShieldRepository: gameShieldRepository,
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-type generateIpService struct {
|
|
|
- *Service
|
|
|
- gameShieldRepository repository.GameShieldRepository
|
|
|
-}
|
|
|
-
|
|
|
-// GenerateMultipleLoopbackIps 生成多个唯一127.0.0.0/8范围IP地址
|
|
|
-// count 指定需要生成的IP地址数量,默认为10
|
|
|
-// 返回生成的唯一IP地址数组和可能的错误
|
|
|
-func (s *generateIpService) GenerateMultipleLoopbackIps(ctx context.Context, count ...int) ([]string, error) {
|
|
|
- requiredCount := 10
|
|
|
- if len(count) > 0 && count[0] > 0 {
|
|
|
- requiredCount = count[0]
|
|
|
- }
|
|
|
-
|
|
|
- maxAttempts := 1000 // 最大尝试次数
|
|
|
- attempts := 0
|
|
|
-
|
|
|
- // 使用互斥锁保护结果集
|
|
|
- var mu sync.Mutex
|
|
|
- collected := make([]string, 0, requiredCount)
|
|
|
- checkedSegments := make(map[string]struct{}, maxAttempts)
|
|
|
-
|
|
|
- // 使用一个固定的随机源以提高性能
|
|
|
- rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
|
-
|
|
|
- for len(collected) < requiredCount && attempts < maxAttempts {
|
|
|
- // 随机生成多个x/z段组合,批量处理
|
|
|
- candidates := make([]struct{ x, z int }, 0, 5)
|
|
|
- for i := 0; i < 5 && len(candidates) < 5; i++ {
|
|
|
- x := rnd.Intn(256)
|
|
|
- z := rnd.Intn(256)
|
|
|
- segmentKey := fmt.Sprintf("%d-%d", x, z)
|
|
|
-
|
|
|
- // 跳过已检查过的段
|
|
|
- mu.Lock()
|
|
|
- _, exists := checkedSegments[segmentKey]
|
|
|
- if !exists {
|
|
|
- checkedSegments[segmentKey] = struct{}{}
|
|
|
- mu.Unlock()
|
|
|
- candidates = append(candidates, struct{ x, z int }{x, z})
|
|
|
- } else {
|
|
|
- mu.Unlock()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 使用conc/pool包并发处理候选IP段
|
|
|
- // 创建一个工作池,限制并发数为4,并收集错误
|
|
|
- p := pool.New().WithMaxGoroutines(4).WithErrors()
|
|
|
-
|
|
|
- // 存储结果
|
|
|
- var results [][]string
|
|
|
-
|
|
|
- // 对每个候选项并发处理
|
|
|
- for _, candidate := range candidates {
|
|
|
- // 创建副本避免闭包捕获循环变量
|
|
|
- candidate := candidate
|
|
|
-
|
|
|
- p.Go(func() error {
|
|
|
- if ctx.Err() != nil {
|
|
|
- return ctx.Err()
|
|
|
- }
|
|
|
-
|
|
|
- x, z := candidate.x, candidate.z
|
|
|
- prefix := fmt.Sprintf("127.%d.%d.", x, z)
|
|
|
-
|
|
|
- // 查询数据库中该前缀已存在的IP
|
|
|
- existingIps, err := s.gameShieldRepository.GetGameShieldExistingIps(ctx, prefix)
|
|
|
- if err != nil {
|
|
|
- // 返回错误以便收集
|
|
|
- return fmt.Errorf("获取IP %s 前缀已存在的记录失败: %w", prefix, err)
|
|
|
- }
|
|
|
-
|
|
|
- // 使用map标记已存在的第四段
|
|
|
- existingFourth := make(map[int]bool, len(existingIps))
|
|
|
- for _, ip := range existingIps {
|
|
|
- parts := strings.Split(ip, ".")
|
|
|
- if len(parts) == 4 {
|
|
|
- fourth, err := strconv.Atoi(parts[3])
|
|
|
- if err == nil {
|
|
|
- // 排除127.0.0.1的情况
|
|
|
- if x == 0 && z == 0 && fourth == 1 {
|
|
|
- continue
|
|
|
- }
|
|
|
- existingFourth[fourth] = true
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 快速估算可用数量
|
|
|
- availableCount := 256 - len(existingFourth)
|
|
|
- // 排除127.0.0.1的特殊情况
|
|
|
- if x == 0 && z == 0 && !existingFourth[1] {
|
|
|
- availableCount--
|
|
|
- }
|
|
|
-
|
|
|
- // 如果可用数量太少,可以跳过
|
|
|
- if availableCount <= 0 {
|
|
|
- return nil
|
|
|
- }
|
|
|
-
|
|
|
- // 预分配足够大的切片避免多次扩容
|
|
|
- available := make([]string, 0, availableCount)
|
|
|
-
|
|
|
- // 如果可用数量很多,可以只收集部分,避免不必要的工作
|
|
|
- collectLimit := min(availableCount, requiredCount*2)
|
|
|
- collectCount := 0
|
|
|
-
|
|
|
- // 随机选择起始点,避免每次都从0开始
|
|
|
- startPoint := rnd.Intn(256)
|
|
|
- for i := 0; i < 256 && collectCount < collectLimit; i++ {
|
|
|
- fourth := (startPoint + i) % 256
|
|
|
-
|
|
|
- if existingFourth[fourth] {
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- // 确保不生成127.0.0.1
|
|
|
- if x == 0 && z == 0 && fourth == 1 {
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- available = append(available, fmt.Sprintf("127.%d.%d.%d", x, z, fourth))
|
|
|
- collectCount++
|
|
|
- }
|
|
|
-
|
|
|
- // 随机打乱结果
|
|
|
- for i := len(available) - 1; i > 0; i-- {
|
|
|
- j := rnd.Intn(i + 1)
|
|
|
- available[i], available[j] = available[j], available[i]
|
|
|
- }
|
|
|
-
|
|
|
- // 将结果添加到结果集
|
|
|
- mu.Lock()
|
|
|
- results = append(results, available)
|
|
|
- mu.Unlock()
|
|
|
-
|
|
|
- return nil
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- // 等待所有goroutine完成并检查错误
|
|
|
- if err := p.Wait(); err != nil {
|
|
|
- // 这里可以选择记录错误但继续尝试,或者直接返回错误
|
|
|
- // 我们选择只有当收集的IP不足时才返回错误
|
|
|
- if len(collected) < requiredCount {
|
|
|
- // 如果已经是最后一次尝试且收集的IP不足,返回错误
|
|
|
- if attempts >= maxAttempts-1 {
|
|
|
- return nil, fmt.Errorf("生成IP地址失败: %w", err)
|
|
|
- }
|
|
|
- // 否则继续尝试下一批候选IP段
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 收集结果
|
|
|
- for _, ips := range results {
|
|
|
- mu.Lock()
|
|
|
- for _, ip := range ips {
|
|
|
- if len(collected) >= requiredCount {
|
|
|
- break
|
|
|
- }
|
|
|
- collected = append(collected, ip)
|
|
|
- }
|
|
|
- mu.Unlock()
|
|
|
- }
|
|
|
-
|
|
|
- attempts++
|
|
|
-
|
|
|
- // 如果已经收集足够的IP,跳出循环
|
|
|
- mu.Lock()
|
|
|
- hasEnough := len(collected) >= requiredCount
|
|
|
- mu.Unlock()
|
|
|
- if hasEnough {
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- mu.Lock()
|
|
|
- defer mu.Unlock()
|
|
|
-
|
|
|
- if len(collected) < requiredCount {
|
|
|
- return nil, fmt.Errorf("无法生成足够的唯一IP地址,地址池可能已耗尽,仅生成了%d个", len(collected))
|
|
|
- }
|
|
|
-
|
|
|
- // 最终随机排序
|
|
|
- for i := len(collected) - 1; i > 0; i-- {
|
|
|
- j := rand.Intn(i + 1)
|
|
|
- collected[i], collected[j] = collected[j], collected[i]
|
|
|
- }
|
|
|
-
|
|
|
- return collected[:requiredCount], nil
|
|
|
-}
|