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
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:
354
internal/cli/root.go
Normal file
354
internal/cli/root.go
Normal 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user