first commit
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

This commit is contained in:
Rogee
2025-09-28 10:05:07 +08:00
commit 7fcabe0225
481 changed files with 125127 additions and 0 deletions

354
internal/cli/root.go Normal file
View File

@@ -0,0 +1,354 @@
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)
}
}