package generator import ( "fmt" "strings" "github.com/subconverter-go/internal/logging" "github.com/subconverter-go/internal/parser" ) // LoonGenerator Loon格式生成器 // 实现Loon代理配置的生成功能 type LoonGenerator struct { logger *logging.Logger } // NewLoonGenerator 创建新的Loon生成器 // 返回初始化好的LoonGenerator实例 func NewLoonGenerator(logger *logging.Logger) *LoonGenerator { return &LoonGenerator{ logger: logger, } } // Generate 生成Loon配置 func (g *LoonGenerator) Generate(configs []*parser.ProxyConfig, options *GenerationOptions) (string, error) { g.logger.Debugf("Generating Loon configuration") // 生成Loon配置文本 var builder strings.Builder // 生成头部信息 g.generateHeader(&builder, options) // 生成代理配置 g.generateProxies(&builder, configs) // 生成代理组 g.generateProxyGroups(&builder, configs, options) // 生成规则 g.generateRules(&builder, options) return builder.String(), nil } // ValidateOptions 验证Loon生成选项 func (g *LoonGenerator) ValidateOptions(options *GenerationOptions) error { g.logger.Debugf("Validating Loon generation options") // 验证基本信息 if options.Name == "" { return fmt.Errorf("configuration name is required") } // 验证端口 if options.MixedPort < 0 || options.MixedPort > 65535 { return fmt.Errorf("invalid mixed port: %d", options.MixedPort) } return nil } // GetSupportedFormats 获取支持的格式 func (g *LoonGenerator) GetSupportedFormats() []string { return []string{"loon"} } // generateHeader 生成配置头部信息 func (g *LoonGenerator) generateHeader(builder *strings.Builder, options *GenerationOptions) { builder.WriteString("# Loon Configuration\n") builder.WriteString("# Generated by SubConverter-Go\n") builder.WriteString(fmt.Sprintf("# Name: %s\n\n", options.Name)) // 基本配置 builder.WriteString("[General]\n") builder.WriteString("bypass-system = true\n") builder.WriteString("bypass-tun = 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12\n") builder.WriteString("dns-server = 119.29.29.29, 223.5.5.5, 1.1.1.1\n") if options.MixedPort > 0 { builder.WriteString(fmt.Sprintf("http-port = %d\n", options.MixedPort)) builder.WriteString(fmt.Sprintf("socks5-port = %d\n", options.MixedPort+1)) } builder.WriteString("allow-wifi-access = false\n") builder.WriteString("wifi-access-http-port = 6152\n") builder.WriteString("wifi-access-socks5-port = 6153\n") if options.IPv6 { builder.WriteString("ipv6 = true\n") } else { builder.WriteString("ipv6 = false\n") } builder.WriteString("prefer-ipv6 = false\n") builder.WriteString("enhanced-mode-by-rule = false\n") builder.WriteString("fallback-dns-server = 223.5.5.5\n") builder.WriteString("loglevel = info\n") builder.WriteString("skip-proxy = 127.0.0.1, 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12\n") if options.EnableLan { builder.WriteString("enhanced-mode-by-rule = true\n") } builder.WriteString("\n") } // generateProxies 生成代理配置 func (g *LoonGenerator) generateProxies(builder *strings.Builder, configs []*parser.ProxyConfig) { builder.WriteString("[Proxy]\n") for i, config := range configs { proxy := g.convertProxyConfig(config) builder.WriteString(proxy) if i < len(configs)-1 { builder.WriteString("\n") } } builder.WriteString("\n") } // convertProxyConfig 转换代理配置为Loon格式 func (g *LoonGenerator) convertProxyConfig(proxyConfig *parser.ProxyConfig) string { switch proxyConfig.Protocol { case "ss": return g.generateSSProxy(proxyConfig) case "ssr": return g.generateSSRProxy(proxyConfig) case "vmess": return g.generateVMessProxy(proxyConfig) case "trojan": return g.generateTrojanProxy(proxyConfig) case "http", "https": return g.generateHTTPProxy(proxyConfig) case "socks5": return g.generateSocks5Proxy(proxyConfig) default: return "" } } // generateSSProxy 生成Shadowsocks代理配置 func (g *LoonGenerator) generateSSProxy(config *parser.ProxyConfig) string { method, _ := config.Settings["method"].(string) password, _ := config.Settings["password"].(string) plugin, _ := config.Settings["plugin"].(string) if plugin != "" { return fmt.Sprintf("%s = Shadowsocks, %s, %d, %s, %s, %s, %s", config.Name, config.Server, config.Port, method, password, plugin, g.generatePluginOpts(config)) } return fmt.Sprintf("%s = Shadowsocks, %s, %d, %s, %s", config.Name, config.Server, config.Port, method, password) } // generateSSRProxy 生成ShadowsocksR代理配置 func (g *LoonGenerator) generateSSRProxy(config *parser.ProxyConfig) string { method, _ := config.Settings["method"].(string) password, _ := config.Settings["password"].(string) protocol, _ := config.Settings["protocol"].(string) protocolParam, _ := config.Settings["protocol-param"].(string) obfs, _ := config.Settings["obfs"].(string) obfsParam, _ := config.Settings["obfs-param"].(string) return fmt.Sprintf("%s = ShadowsocksR, %s, %d, %s, %s, %s, %s, %s, %s", config.Name, config.Server, config.Port, method, password, protocol, protocolParam, obfs, obfsParam) } // generateVMessProxy 生成VMess代理配置 func (g *LoonGenerator) generateVMessProxy(config *parser.ProxyConfig) string { uuid, _ := config.Settings["uuid"].(string) alterId, _ := config.Settings["alterId"].(int) network, _ := config.Settings["network"].(string) tls, _ := config.Settings["tls"].(string) host, _ := config.Settings["host"].(string) path, _ := config.Settings["path"].(string) var opts []string opts = append(opts, fmt.Sprintf("%s", config.Server)) opts = append(opts, fmt.Sprintf("%d", config.Port)) opts = append(opts, fmt.Sprintf("%s", "auto")) // Loon会自动选择加密方式 opts = append(opts, fmt.Sprintf("%s", uuid)) opts = append(opts, fmt.Sprintf("%d", alterId)) if network != "" { opts = append(opts, fmt.Sprintf("%s", network)) } if tls != "" { opts = append(opts, fmt.Sprintf("tls")) } if host != "" { opts = append(opts, fmt.Sprintf("%s", host)) } if path != "" { opts = append(opts, fmt.Sprintf("%s", path)) } return fmt.Sprintf("%s = VMess, %s", config.Name, strings.Join(opts, ", ")) } // generateTrojanProxy 生成Trojan代理配置 func (g *LoonGenerator) generateTrojanProxy(config *parser.ProxyConfig) string { password, _ := config.Settings["password"].(string) sni, _ := config.Settings["sni"].(string) network, _ := config.Settings["network"].(string) var opts []string opts = append(opts, fmt.Sprintf("%s", config.Server)) opts = append(opts, fmt.Sprintf("%d", config.Port)) opts = append(opts, fmt.Sprintf("%s", password)) if sni != "" { opts = append(opts, fmt.Sprintf("%s", sni)) } if network != "" { opts = append(opts, fmt.Sprintf("%s", network)) } return fmt.Sprintf("%s = Trojan, %s", config.Name, strings.Join(opts, ", ")) } // generateHTTPProxy 生成HTTP代理配置 func (g *LoonGenerator) generateHTTPProxy(config *parser.ProxyConfig) string { username, _ := config.Settings["username"].(string) password, _ := config.Settings["password"].(string) tls, _ := config.Settings["tls"].(bool) if username != "" && password != "" { if tls { return fmt.Sprintf("%s = HTTPS, %s, %d, %s, %s", config.Name, config.Server, config.Port, username, password) } return fmt.Sprintf("%s = HTTP, %s, %d, %s, %s", config.Name, config.Server, config.Port, username, password) } if tls { return fmt.Sprintf("%s = HTTPS, %s, %d", config.Name, config.Server, config.Port) } return fmt.Sprintf("%s = HTTP, %s, %d", config.Name, config.Server, config.Port) } // generateSocks5Proxy 生成Socks5代理配置 func (g *LoonGenerator) generateSocks5Proxy(config *parser.ProxyConfig) string { username, _ := config.Settings["username"].(string) password, _ := config.Settings["password"].(string) if username != "" && password != "" { return fmt.Sprintf("%s = SOCKS5, %s, %d, %s, %s", config.Name, config.Server, config.Port, username, password) } return fmt.Sprintf("%s = SOCKS5, %s, %d", config.Name, config.Server, config.Port) } // generatePluginOpts 生成插件选项 func (g *LoonGenerator) generatePluginOpts(config *parser.ProxyConfig) string { // 这里可以根据具体插件生成相应的选项 return "" } // generateProxyGroups 生成代理组 func (g *LoonGenerator) generateProxyGroups(builder *strings.Builder, configs []*parser.ProxyConfig, options *GenerationOptions) { builder.WriteString("[Proxy Group]\n") // 创建代理名称列表 proxyNames := make([]string, 0) for _, config := range configs { proxyNames = append(proxyNames, config.Name) } // 选择代理组 builder.WriteString(fmt.Sprintf("Proxy = select, %s\n", strings.Join(proxyNames, ", "))) // URL测试代理组 if options.ProxyTest { testURL := options.ProxyURL if testURL == "" { testURL = "http://www.gstatic.com/generate_204" } builder.WriteString(fmt.Sprintf("URL-Test = url-test, %s, url=%s, interval=300\n", strings.Join(proxyNames, ", "), testURL)) } // 故障转移代理组 builder.WriteString(fmt.Sprintf("Fallback = fallback, %s, url=http://www.gstatic.com/generate_204, interval=300\n", strings.Join(proxyNames, ", "))) // 直连和拒绝代理组 builder.WriteString("Direct = select, DIRECT\n") builder.WriteString("Reject = select, REJECT\n\n") } // generateRules 生成规则 func (g *LoonGenerator) generateRules(builder *strings.Builder, options *GenerationOptions) { builder.WriteString("[Rule]\n") // 添加默认规则 if len(options.Rules) > 0 { builder.WriteString(strings.Join(options.Rules, "\n")) } else { // 添加默认规则集 defaultRules := []string{ "DOMAIN-SUFFIX,bilibili.com,DIRECT", "DOMAIN-SUFFIX,baidu.com,DIRECT", "DOMAIN-SUFFIX,cn,DIRECT", "DOMAIN-KEYWORD,google,Proxy", "DOMAIN-KEYWORD,github,Proxy", "DOMAIN-KEYWORD,twitter,Proxy", "DOMAIN-KEYWORD,facebook,Proxy", "DOMAIN-KEYWORD,youtube,Proxy", "DOMAIN-KEYWORD,instagram,Proxy", "DOMAIN-KEYWORD,telegram,Proxy", "GEOIP,CN,DIRECT", "IP-CIDR,127.0.0.0/8,DIRECT", "IP-CIDR,192.168.0.0/16,DIRECT", "IP-CIDR,10.0.0.0/8,DIRECT", "IP-CIDR,172.16.0.0/12,DIRECT", "FINAL,Proxy", } builder.WriteString(strings.Join(defaultRules, "\n")) } // 启用IPv6支持 if options.IPv6 { builder.WriteString("\n# IPv6 Rules\n") builder.WriteString("IP-CIDR6,::1/128,DIRECT\n") builder.WriteString("IP-CIDR6,fc00::/7,DIRECT\n") } // 启用局域网支持 if options.EnableLan { builder.WriteString("\n# LAN Rules\n") builder.WriteString("SRC-IP-CIDR,192.168.0.0/16,DIRECT\n") builder.WriteString("SRC-IP-CIDR,10.0.0.0/8,DIRECT\n") builder.WriteString("SRC-IP-CIDR,172.16.0.0/12,DIRECT\n") } }