package service import ( "context" "encoding/json" "fmt" v1 "github.com/go-nunu/nunu-layout-advanced/api/v1" "github.com/go-nunu/nunu-layout-advanced/internal/model" "maps" "sort" "strconv" "strings" "github.com/spf13/cast" ) type FormatterService interface { FormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, output map[string]v1.SendGameShieldBackend, keyCounter int) (string, error) FormatPort(ctx context.Context, req interface{}) []int OldFormat(ctx context.Context, req *[]model.GameShieldBackend) (map[string]v1.SendGameShieldBackend, error) TidyFormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, keyCounter int) (map[string]v1.SendGameShieldBackend, error) Sort(ctx context.Context, mapData map[string]v1.SendGameShieldBackend) (map[string]v1.SendGameShieldBackend, error) } func NewFormatterService( service *Service, gameShieldPublicIpService GameShieldPublicIpService, ) FormatterService { return &formatterService{ Service: service, gameShieldPublicIpService: gameShieldPublicIpService, } } type formatterService struct { *Service gameShieldPublicIpService GameShieldPublicIpService } func (service *formatterService) FormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, oldFormat map[string]v1.SendGameShieldBackend, keyCounter int) (string, error) { formData, err := service.TidyFormatBackendData(ctx, req, keyCounter) for _, v := range formData { v.Type = "" } if err != nil { return "", err } maps.Copy(formData, oldFormat) sortedOutput, err := service.Sort(ctx, formData) if err != nil { return "", err } jsonBytes, err := json.MarshalIndent(sortedOutput, "", " ") if err != nil { return "", err } return string(jsonBytes), nil } func (service *formatterService) FormatPort(ctx context.Context, req interface{}) []int { if req == nil { return []int{} } reqStr := cast.ToString(req) if reqStr == "" { return []int{} } reqStr = strings.ReplaceAll(reqStr, ",", ",") // 分割字符串并转换为整数 var res []int for _, v := range strings.Split(reqStr, ",") { // 去除空格 v = strings.TrimSpace(v) if v != "" { port := cast.ToInt(v) res = append(res, port) } } return res } func (service *formatterService) OldFormat(ctx context.Context, req *[]model.GameShieldBackend) (map[string]v1.SendGameShieldBackend, error) { res := make(map[string]v1.SendGameShieldBackend) var UdpSessionTimeout string for _, v := range *req { addr := fmt.Sprintf("%s:%s", v.SourceMachineIP, v.ConnectPort) sdkPort, err := strconv.Atoi(v.SdkPort) if err != nil { return nil, err } if v.Protocol == "udp" { UdpSessionTimeout = "300s" } else { UdpSessionTimeout = "" } keyName := fmt.Sprintf("key%d", v.KeySort) if v.Type != "pc" { v.SdkIp = "" } res[keyName] = v1.SendGameShieldBackend{ Addr: []string{addr}, Protocol: v.Protocol, ProxyAddr: v.ProxyAddr, SdkPort: sdkPort, UdpSessionTimeout: UdpSessionTimeout, SdkIp: v.SdkIp, } } return res, nil } func (service *formatterService) TidyFormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, keyCounter int) (map[string]v1.SendGameShieldBackend, error) { output := make(map[string]v1.SendGameShieldBackend) userIp, err := service.gameShieldPublicIpService.GetUserIp(ctx, req.Uid) if err != nil { return nil, err } for _, item := range req.Items { // 提取必要字段 sourceIP := item.SourceMachineIP // 假设结构体中有这个字段 if sourceIP == "" { return nil, fmt.Errorf("没有有效源IP的配置") // 跳过没有有效源IP的配置 } protocol := item.Protocol // 假设结构体中有这个字段 if protocol == "" { return nil, fmt.Errorf("没有有效协议的配置") // 跳过没有有效协议的配置 } // 获取端口数组 conPorts := service.FormatPort(ctx, item.ConnectPort) sdkPorts := service.FormatPort(ctx, item.SdkPort) // 处理每一对端口 for i := 0; i < len(conPorts); i++ { keyCounter++ key := fmt.Sprintf("key%d", keyCounter) // 使用数组中的具体端口 addr := fmt.Sprintf("%s:%d", sourceIP, conPorts[i]) itemMap := v1.SendGameShieldBackend{ Addr: []string{addr}, Protocol: protocol, } //// 设置主机名(如果存在) //if item.Host != "" { // itemMap["host"] = item.Host //} // 根据协议设置不同属性 if protocol != "udp" { if item.Checked == "agent" { itemMap.AgentAddr = fmt.Sprintf("%s:%s", sourceIP, "23350") } itemMap.ProxyAddr = userIp + ":32353" } else { itemMap.ProxyAddr = "" itemMap.UdpSessionTimeout = "300s" } itemMap.Type = item.Type if item.Type != "pc" { itemMap.SdkIp = "" } else { itemMap.SdkIp = item.SdkIp } if item.MaxBandwidth == "1" { itemMap.MaxBandwidth = "50m" } else { itemMap.MaxBandwidth = "" } // 设置SDK端口 - 使用数组中的具体端口 if len(sdkPorts) != 0 { if sdkPorts[i] <= 1024 { if item.Type == "mobile" { return nil, fmt.Errorf("移动端不支持SSH端口") } } itemMap.SdkPort = sdkPorts[i] } output[key] = itemMap } } return output, nil } func (service *formatterService) Sort(ctx context.Context, mapData map[string]v1.SendGameShieldBackend) (map[string]v1.SendGameShieldBackend, error) { var keys []int for key := range mapData { intKey, err := strconv.Atoi(strings.TrimPrefix(key, "key")) if err != nil { return nil, err } keys = append(keys, intKey) } // 2. 排序键 sort.Ints(keys) // 3. 创建一个新的 output 切片或 map 来存储排序后的值 sortedOutput := make(map[string]v1.SendGameShieldBackend) // 4. 按排序后的键遍历 map,并存储对应的值到 sortedOutput for _, key := range keys { sortedOutput["key"+strconv.Itoa(key)] = mapData["key"+strconv.Itoa(key)] } return sortedOutput, nil }