- 提取 App 公共逻辑到 app_common.go,消除 app.go/app_windows.go 重复定义
- 提取 Server 生命周期/中间件/路由逻辑到独立文件(lifecycle.go/middleware_builder.go/router.go)
- 提取 Proxy 缓存处理/头部修改/目标选择到独立模块
- 提取 CheckIPAccess/CheckTokenAuth 到 utils/httperror.go,消除 status/purge 重复实现
- 修复 stream 双向转发:任一方向完成立即关闭双端,避免连接泄漏
- 修复 SSL/TLS 中静默忽略错误的问题,添加日志记录
- 统一日志消息为英文
💘 Generated with Crush
Assisted-by: GLM 5.1 via Crush <crush@charm.land>
115 lines
2.9 KiB
Go
115 lines
2.9 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"rua.plus/lolly/internal/config"
|
|
"rua.plus/lolly/internal/converter/nginx"
|
|
"rua.plus/lolly/internal/version"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// Run decides behavior based on flags: generate config, import nginx config, print version, or start the app.
|
|
func Run(cfgPath string, genConfig bool, outputPath string, importPath string, showVersion bool) int {
|
|
if genConfig && importPath != "" {
|
|
fmt.Fprintln(os.Stderr, "error: --generate-config and --import are mutually exclusive")
|
|
return 1
|
|
}
|
|
if outputPath != "" && !genConfig && importPath == "" {
|
|
fmt.Fprintln(os.Stderr, "error: -o requires either --generate-config or --import")
|
|
return 1
|
|
}
|
|
|
|
if genConfig {
|
|
return generateConfig(outputPath)
|
|
}
|
|
|
|
if importPath != "" {
|
|
if err := importNginxConfig(importPath, outputPath); err != nil {
|
|
fmt.Fprintln(os.Stderr, "error:", err)
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
if showVersion {
|
|
printVersion()
|
|
return 0
|
|
}
|
|
|
|
app := NewApp(cfgPath)
|
|
return app.Run()
|
|
}
|
|
|
|
func generateConfig(outputPath string) int {
|
|
cfg := config.DefaultConfig()
|
|
yamlData, err := config.GenerateConfigYAML(cfg)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to generate config: %v\n", err)
|
|
return 1
|
|
}
|
|
|
|
if outputPath == "" {
|
|
fmt.Print(string(yamlData))
|
|
} else {
|
|
if err := os.WriteFile(outputPath, yamlData, 0o644); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to write file: %v\n", err)
|
|
return 1
|
|
}
|
|
fmt.Printf("Config written to: %s\n", outputPath)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func importNginxConfig(path, outputPath string) error {
|
|
nginxCfg, err := nginx.ParseFile(path)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse nginx config: %w", err)
|
|
}
|
|
|
|
result, err := nginx.Convert(nginxCfg)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to convert config: %w", err)
|
|
}
|
|
|
|
for _, w := range result.Warnings {
|
|
fmt.Fprintf(os.Stderr, "warning: %s:line %d: %s\n", w.File, w.Line, w.Message)
|
|
}
|
|
|
|
if validateErr := config.Validate(result.Config); validateErr != nil {
|
|
return fmt.Errorf("converted config validation failed: %w", validateErr)
|
|
}
|
|
|
|
yamlData, err := yaml.Marshal(result.Config)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal YAML: %w", err)
|
|
}
|
|
|
|
if outputPath == "" {
|
|
if _, err := os.Stdout.Write(yamlData); err != nil {
|
|
return fmt.Errorf("failed to write to stdout: %w", err)
|
|
}
|
|
} else {
|
|
if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
|
|
return fmt.Errorf("failed to create output directory: %w", err)
|
|
}
|
|
if err := os.WriteFile(outputPath, yamlData, 0o644); err != nil {
|
|
return fmt.Errorf("failed to write file: %w", err)
|
|
}
|
|
fmt.Printf("Config written to: %s\n", outputPath)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func printVersion() {
|
|
fmt.Printf("lolly version %s\n", version.Version)
|
|
fmt.Printf(" Git: %s (%s)\n", version.GitCommit, version.GitBranch)
|
|
fmt.Printf(" Built: %s\n", version.BuildTime)
|
|
fmt.Printf(" Go: %s\n", version.GoVersion)
|
|
fmt.Printf(" Platform: %s\n", version.BuildPlatform)
|
|
}
|