package cli import ( "fmt" "os" "github.com/spf13/cobra" "github.com/subconverter-go/internal/config" "github.com/subconverter-go/internal/logging" httpserver "github.com/subconverter-go/internal/http" ) // RootCmd CLI根命令 // 包含所有子命令和全局配置 type RootCmd struct { cmd *cobra.Command configPath string logger *logging.Logger configMgr *config.ConfigManager server *httpserver.Server } // NewRootCmd 创建新的根命令 // 返回初始化好的RootCmd实例 func NewRootCmd() *RootCmd { root := &RootCmd{ cmd: &cobra.Command{ Use: "subconverter-go", Short: "SubConverter Go版本 - 代理订阅转换服务", Long: `SubConverter Go版本是一个高性能的代理订阅转换服务, 支持在Clash、Surge、Quantumult X等格式之间转换。 这是一个Go语言重写版本,与原C++版本保持功能兼容。`, Version: "1.0.0", }, } // 设置命令 root.setupCommands() return root } // setupCommands 设置命令结构 func (r *RootCmd) setupCommands() { // 添加全局标志 r.cmd.PersistentFlags().StringVarP(&r.configPath, "config", "c", "", "配置文件路径") r.cmd.PersistentFlags().BoolP("verbose", "v", false, "详细输出") r.cmd.PersistentFlags().BoolP("quiet", "q", false, "静默模式") // 添加子命令 r.cmd.AddCommand(r.newServerCommand()) r.cmd.AddCommand(r.newConvertCommand()) r.cmd.AddCommand(r.newConfigCommand()) r.cmd.AddCommand(r.newVersionCommand()) // 设置前执行函数 r.cmd.PersistentPreRunE = r.persistentPreRun } // persistentPreRun 持久化预运行函数 // 在所有命令执行前运行,用于初始化共享资源 func (r *RootCmd) persistentPreRun(cmd *cobra.Command, args []string) error { // 初始化日志 if err := r.initLogging(); err != nil { return fmt.Errorf("failed to initialize logging: %v", err) } // 初始化配置 if err := r.initConfig(); err != nil { return fmt.Errorf("failed to initialize config: %v", err) } return nil } // initLogging 初始化日志系统 func (r *RootCmd) initLogging() error { // 根据命令行参数设置日志级别 level := "info" if r.cmd.Flag("verbose").Changed { level = "debug" } else if r.cmd.Flag("quiet").Changed { level = "error" } // 创建日志记录器 logger, err := logging.NewLogger(&logging.LoggingConfig{ Level: level, Format: "text", Output: "stdout", MaxSize: 100, MaxBackups: 3, MaxAge: 30, Compress: true, ReportCaller: false, EnableColor: true, }) if err != nil { return err } r.logger = logger return nil } // initConfig 初始化配置管理器 func (r *RootCmd) initConfig() error { // 创建配置管理器 configMgr, err := config.NewConfigManager(r.configPath) if err != nil { return err } r.configMgr = configMgr return nil } // newServerCommand 创建服务器命令 func (r *RootCmd) newServerCommand() *cobra.Command { var ( host string port int ) cmd := &cobra.Command{ Use: "server", Short: "启动HTTP服务器", Long: "启动HTTP服务器,提供代理订阅转换API服务", RunE: func(cmd *cobra.Command, args []string) error { return r.runServer(host, port) }, } // 添加命令特定标志 cmd.Flags().StringVarP(&host, "host", "H", "", "服务器监听地址") cmd.Flags().IntVarP(&port, "port", "p", 0, "服务器监听端口") return cmd } // newConvertCommand 创建转换命令 func (r *RootCmd) newConvertCommand() *cobra.Command { var ( target string inputFile string outputFile string url string ) cmd := &cobra.Command{ Use: "convert", Short: "转换代理订阅", Long: "将代理订阅从一个格式转换为另一个格式", RunE: func(cmd *cobra.Command, args []string) error { return r.runConvert(target, inputFile, outputFile, url) }, } // 添加命令特定标志 cmd.Flags().StringVarP(&target, "target", "t", "clash", "目标格式 (clash, surge, quanx, etc.)") cmd.Flags().StringVarP(&inputFile, "input", "i", "", "输入文件路径") cmd.Flags().StringVarP(&outputFile, "output", "o", "", "输出文件路径") cmd.Flags().StringVarP(&url, "url", "u", "", "订阅URL") return cmd } // newConfigCommand 创建配置命令 func (r *RootCmd) newConfigCommand() *cobra.Command { cmd := &cobra.Command{ Use: "config", Short: "配置管理", Long: "管理SubConverter配置", } // 添加子命令 cmd.AddCommand(r.newConfigShowCommand()) cmd.AddCommand(r.newConfigValidateCommand()) return cmd } // newConfigShowCommand 创建配置显示命令 func (r *RootCmd) newConfigShowCommand() *cobra.Command { cmd := &cobra.Command{ Use: "show", Short: "显示当前配置", Long: "显示当前配置信息", RunE: func(cmd *cobra.Command, args []string) error { return r.showConfig() }, } return cmd } // newConfigValidateCommand 创建配置验证命令 func (r *RootCmd) newConfigValidateCommand() *cobra.Command { cmd := &cobra.Command{ Use: "validate", Short: "验证配置文件", Long: "验证配置文件的有效性", RunE: func(cmd *cobra.Command, args []string) error { return r.validateConfig() }, } return cmd } // newVersionCommand 创建版本命令 func (r *RootCmd) newVersionCommand() *cobra.Command { cmd := &cobra.Command{ Use: "version", Short: "显示版本信息", Long: "显示SubConverter Go版本的详细信息", Run: func(cmd *cobra.Command, args []string) { r.showVersion() }, } return cmd } // runServer 运行服务器 func (r *RootCmd) runServer(host string, port int) error { r.logger.Info("Starting SubConverter Go server...") // 获取服务器配置 serverConfig := r.configMgr.GetServerConfig() // 应用命令行参数覆盖 if host != "" { serverConfig.Host = host } if port != 0 { serverConfig.Port = port } // 更新配置 if err := r.configMgr.UpdateConfig(r.configMgr.GetConfig()); err != nil { return fmt.Errorf("failed to update server config: %v", err) } // 创建HTTP服务器 server, err := httpserver.NewServer(r.configMgr) if err != nil { return fmt.Errorf("failed to create HTTP server: %v", err) } r.server = server // 启动服务器 if err := server.Start(); err != nil { return fmt.Errorf("failed to start server: %v", err) } r.logger.Infof("Server started on %s:%d", serverConfig.Host, serverConfig.Port) // 等待关闭信号 r.server.WaitForShutdown() return nil } // runConvert 运行转换命令 func (r *RootCmd) runConvert(target, inputFile, outputFile, url string) error { r.logger.Info("Starting conversion...") r.logger.Infof("Target: %s, Input: %s, Output: %s, URL: %s", target, inputFile, outputFile, url) // 这里实现转换逻辑 // 目前只是占位符 r.logger.Warn("Conversion functionality not implemented yet") return nil } // showConfig 显示配置 func (r *RootCmd) showConfig() error { config := r.configMgr.GetConfig() r.logger.Info("Current configuration:") r.logger.Infof("Server: %s:%d", config.Server.Host, config.Server.Port) r.logger.Infof("Log Level: %s", config.Logging.Level) r.logger.Infof("Rate Limit: %d", config.Security.RateLimit) r.logger.Infof("Default Target: %s", config.Conversion.DefaultTarget) return nil } // validateConfig 验证配置 func (r *RootCmd) validateConfig() error { config := r.configMgr.GetConfig() if err := config.Validate(); err != nil { return fmt.Errorf("configuration validation failed: %v", err) } r.logger.Info("Configuration is valid") return nil } // showVersion 显示版本信息 func (r *RootCmd) showVersion() { fmt.Printf("SubConverter Go v%s\n", r.cmd.Version) fmt.Printf("Build: %s\n", "development") fmt.Printf("Go Version: %s\n", "1.21+") fmt.Println("A high-performance proxy subscription converter") } // Execute 执行命令 func (r *RootCmd) Execute() error { return r.cmd.Execute() } // Close 清理资源 func (r *RootCmd) Close() error { // 停止服务器 if r.server != nil { if err := r.server.Stop(); err != nil { r.logger.WithError(err).Error("Failed to stop server") } } // 关闭配置管理器 if r.configMgr != nil { if err := r.configMgr.Close(); err != nil { r.logger.WithError(err).Error("Failed to close config manager") } } return nil } // ExecuteMain 主执行函数 // 用于main.go调用 func ExecuteMain() { rootCmd := NewRootCmd() // 设置退出时的清理函数 defer func() { if err := rootCmd.Close(); err != nil { fmt.Fprintf(os.Stderr, "Error during cleanup: %v\n", err) os.Exit(1) } }() // 执行命令 if err := rootCmd.Execute(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } }