package server import ( "context" "encoding/json" "fmt" "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/model/server" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" ) type MigrateServerNodeLogic struct { logger.Logger ctx context.Context svcCtx *svc.ServiceContext } // NewMigrateServerNodeLogic Migrate server and node data to new database func NewMigrateServerNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MigrateServerNodeLogic { return &MigrateServerNodeLogic{ Logger: logger.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *MigrateServerNodeLogic) MigrateServerNode() (resp *types.MigrateServerNodeResponse, err error) { tx := l.svcCtx.DB.WithContext(l.ctx).Begin() var oldServers []*server.Server var newServers []*node.Server var newNodes []*node.Node err = tx.Model(&server.Server{}).Find(&oldServers).Error if err != nil { l.Errorw("[MigrateServerNode] Query Old Server List Error: ", logger.Field("error", err.Error())) return &types.MigrateServerNodeResponse{ Succee: 0, Fail: 0, Message: fmt.Sprintf("Query Old Server List Error: %s", err.Error()), }, nil } for _, oldServer := range oldServers { data, err := l.adapterServer(oldServer) if err != nil { l.Errorw("[MigrateServerNode] Adapter Server Error: ", logger.Field("error", err.Error())) if resp == nil { resp = &types.MigrateServerNodeResponse{} } resp.Fail++ if resp.Message == "" { resp.Message = fmt.Sprintf("Adapter Server Error: %s", err.Error()) } else { resp.Message = fmt.Sprintf("%s; Adapter Server Error: %s", resp.Message, err.Error()) } continue } newServers = append(newServers, data) newNode, err := l.adapterNode(oldServer) if err != nil { l.Errorw("[MigrateServerNode] Adapter Node Error: ", logger.Field("error", err.Error())) if resp == nil { resp = &types.MigrateServerNodeResponse{} } resp.Fail++ if resp.Message == "" { resp.Message = fmt.Sprintf("Adapter Node Error: %s", err.Error()) } else { resp.Message = fmt.Sprintf("%s; Adapter Node Error: %s", resp.Message, err.Error()) } continue } for _, item := range newNode { if item.Port == 0 { protocols, _ := data.UnmarshalProtocols() if len(protocols) > 0 { item.Port = protocols[0].Port } } newNodes = append(newNodes, item) } } if len(newServers) > 0 { err = tx.Model(&node.Server{}).CreateInBatches(newServers, 20).Error if err != nil { tx.Rollback() l.Errorw("[MigrateServerNode] Insert New Server List Error: ", logger.Field("error", err.Error())) return &types.MigrateServerNodeResponse{ Succee: 0, Fail: uint64(len(newServers)), Message: fmt.Sprintf("Insert New Server List Error: %s", err.Error()), }, nil } } if len(newNodes) > 0 { err = tx.Model(&node.Node{}).CreateInBatches(newNodes, 20).Error if err != nil { tx.Rollback() l.Errorw("[MigrateServerNode] Insert New Node List Error: ", logger.Field("error", err.Error())) return &types.MigrateServerNodeResponse{ Succee: uint64(len(newServers)), Fail: uint64(len(newNodes)), Message: fmt.Sprintf("Insert New Node List Error: %s", err.Error()), }, nil } } tx.Commit() return &types.MigrateServerNodeResponse{ Succee: uint64(len(newServers)), Fail: 0, Message: fmt.Sprintf("Migrate Success: %d servers and %d nodes", len(newServers), len(newNodes)), }, nil } func (l *MigrateServerNodeLogic) adapterServer(info *server.Server) (*node.Server, error) { result := &node.Server{ Name: info.Name, Country: info.Country, City: info.City, Ratio: info.TrafficRatio, Address: info.ServerAddr, Sort: int(info.Sort), Protocols: "", } var protocols []node.Protocol switch info.Protocol { case ShadowSocks: var src server.Shadowsocks err := json.Unmarshal([]byte(info.Config), &src) if err != nil { return nil, err } protocols = append(protocols, node.Protocol{ Type: "shadowsocks", Cipher: src.Method, Port: uint16(src.Port), ServerKey: src.ServerKey, }) case Vmess: var src server.Vmess err := json.Unmarshal([]byte(info.Config), &src) if err != nil { return nil, err } protocol := node.Protocol{ Type: "vmess", Port: uint16(src.Port), Security: src.Security, SNI: src.SecurityConfig.SNI, AllowInsecure: src.SecurityConfig.AllowInsecure, Fingerprint: src.SecurityConfig.Fingerprint, RealityServerAddr: src.SecurityConfig.RealityServerAddr, RealityServerPort: src.SecurityConfig.RealityServerPort, RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, RealityPublicKey: src.SecurityConfig.RealityPublicKey, RealityShortId: src.SecurityConfig.RealityShortId, Transport: src.Transport, Host: src.TransportConfig.Host, Path: src.TransportConfig.Path, ServiceName: src.TransportConfig.ServiceName, Flow: src.Flow, } protocols = append(protocols, protocol) protocols = append(protocols, protocol) case Vless: var src server.Vless err := json.Unmarshal([]byte(info.Config), &src) if err != nil { return nil, err } protocol := node.Protocol{ Type: "vless", Port: uint16(src.Port), Security: src.Security, SNI: src.SecurityConfig.SNI, AllowInsecure: src.SecurityConfig.AllowInsecure, Fingerprint: src.SecurityConfig.Fingerprint, RealityServerAddr: src.SecurityConfig.RealityServerAddr, RealityServerPort: src.SecurityConfig.RealityServerPort, RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, RealityPublicKey: src.SecurityConfig.RealityPublicKey, RealityShortId: src.SecurityConfig.RealityShortId, Transport: src.Transport, Host: src.TransportConfig.Host, Path: src.TransportConfig.Path, ServiceName: src.TransportConfig.ServiceName, Flow: src.Flow, } protocols = append(protocols, protocol) case Trojan: var src server.Trojan err := json.Unmarshal([]byte(info.Config), &src) if err != nil { return nil, err } protocol := node.Protocol{ Type: "trojan", Port: uint16(src.Port), Security: src.Security, SNI: src.SecurityConfig.SNI, AllowInsecure: src.SecurityConfig.AllowInsecure, Fingerprint: src.SecurityConfig.Fingerprint, RealityServerAddr: src.SecurityConfig.RealityServerAddr, RealityServerPort: src.SecurityConfig.RealityServerPort, RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, RealityPublicKey: src.SecurityConfig.RealityPublicKey, RealityShortId: src.SecurityConfig.RealityShortId, Transport: src.Transport, Host: src.TransportConfig.Host, Path: src.TransportConfig.Path, ServiceName: src.TransportConfig.ServiceName, Flow: src.Flow, } protocols = append(protocols, protocol) case Hysteria2: var src server.Hysteria2 err := json.Unmarshal([]byte(info.Config), &src) if err != nil { return nil, err } protocol := node.Protocol{ Type: "hysteria2", Port: uint16(src.Port), HopPorts: src.HopPorts, HopInterval: src.HopInterval, ObfsPassword: src.ObfsPassword, SNI: src.SecurityConfig.SNI, AllowInsecure: src.SecurityConfig.AllowInsecure, Fingerprint: src.SecurityConfig.Fingerprint, RealityServerAddr: src.SecurityConfig.RealityServerAddr, RealityServerPort: src.SecurityConfig.RealityServerPort, RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, RealityPublicKey: src.SecurityConfig.RealityPublicKey, RealityShortId: src.SecurityConfig.RealityShortId, } protocols = append(protocols, protocol) case Tuic: var src server.Tuic err := json.Unmarshal([]byte(info.Config), &src) if err != nil { return nil, err } protocol := node.Protocol{ Type: "tuic", Port: uint16(src.Port), DisableSNI: src.DisableSNI, ReduceRtt: src.ReduceRtt, UDPRelayMode: src.UDPRelayMode, CongestionController: src.CongestionController, SNI: src.SecurityConfig.SNI, AllowInsecure: src.SecurityConfig.AllowInsecure, Fingerprint: src.SecurityConfig.Fingerprint, RealityServerAddr: src.SecurityConfig.RealityServerAddr, RealityServerPort: src.SecurityConfig.RealityServerPort, RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, RealityPublicKey: src.SecurityConfig.RealityPublicKey, RealityShortId: src.SecurityConfig.RealityShortId, } protocols = append(protocols, protocol) case AnyTLS: var src server.AnyTLS err := json.Unmarshal([]byte(info.Config), &src) if err != nil { return nil, err } protocol := node.Protocol{ Type: "anytls", Port: uint16(src.Port), SNI: src.SecurityConfig.SNI, AllowInsecure: src.SecurityConfig.AllowInsecure, Fingerprint: src.SecurityConfig.Fingerprint, RealityServerAddr: src.SecurityConfig.RealityServerAddr, RealityServerPort: src.SecurityConfig.RealityServerPort, RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, RealityPublicKey: src.SecurityConfig.RealityPublicKey, RealityShortId: src.SecurityConfig.RealityShortId, } protocols = append(protocols, protocol) } if len(protocols) > 0 { err := result.MarshalProtocols(protocols) if err != nil { return nil, err } } return result, nil } func (l *MigrateServerNodeLogic) adapterNode(info *server.Server) ([]*node.Node, error) { var nodes []*node.Node enable := true switch info.RelayMode { case server.RelayModeNone: nodes = append(nodes, &node.Node{ Name: info.Name, Tags: "", Port: 0, Address: info.ServerAddr, ServerId: info.Id, Protocol: info.Protocol, Enabled: &enable, }) default: var relays []server.NodeRelay err := json.Unmarshal([]byte(info.RelayNode), &relays) if err != nil { return nil, err } for _, relay := range relays { nodes = append(nodes, &node.Node{ Name: relay.Prefix + info.Name, Tags: "", Port: uint16(relay.Port), Address: relay.Host, ServerId: info.Id, Protocol: info.Protocol, Enabled: &enable, }) } } return nodes, nil }