Files
Rogee 7fcabe0225
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
first commit
2025-09-28 10:05:07 +08:00

354 lines
8.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}
}