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:
565
internal/cli/command.go
Normal file
565
internal/cli/command.go
Normal file
@@ -0,0 +1,565 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CommandType 定义命令类型
|
||||
type CommandType int
|
||||
|
||||
const (
|
||||
SERVER CommandType = iota
|
||||
CONFIG
|
||||
TEST
|
||||
VERSION
|
||||
HELP
|
||||
UNKNOWN
|
||||
)
|
||||
|
||||
// Command 表示CLI命令的结构
|
||||
// 该结构体包含命令的所有参数和配置
|
||||
type Command struct {
|
||||
// 基本命令信息
|
||||
Type CommandType `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Aliases []string `json:"aliases"`
|
||||
Usage string `json:"usage"`
|
||||
|
||||
// 位置参数
|
||||
Args []string `json:"args"`
|
||||
ArgsCount int `json:"args_count"`
|
||||
|
||||
// 标志参数
|
||||
Flags map[string]string `json:"flags"`
|
||||
Booleans map[string]bool `json:"booleans"`
|
||||
Integers map[string]int64 `json:"integers"`
|
||||
Floats map[string]float64 `json:"floats"`
|
||||
|
||||
// 选项参数
|
||||
Options map[string][]string `json:"options"`
|
||||
|
||||
// 环境变量
|
||||
EnvVars map[string]string `json:"env_vars"`
|
||||
|
||||
// 配置文件
|
||||
ConfigFile string `json:"config_file"`
|
||||
Config interface{} `json:"config"`
|
||||
|
||||
// 执行信息
|
||||
Executed bool `json:"executed"`
|
||||
ExecutedAt time.Time `json:"executed_at"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
ExitCode int `json:"exit_code"`
|
||||
Output string `json:"output"`
|
||||
Error error `json:"error"`
|
||||
|
||||
// 上下文信息
|
||||
WorkingDir string `json:"working_dir"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
|
||||
// 调试信息
|
||||
Debug bool `json:"debug"`
|
||||
Verbose bool `json:"verbose"`
|
||||
Quiet bool `json:"quiet"`
|
||||
DryRun bool `json:"dry_run"`
|
||||
|
||||
// 自定义数据
|
||||
Custom map[string]interface{} `json:"custom,omitempty"`
|
||||
}
|
||||
|
||||
// NewCommand 创建新的命令实例
|
||||
// 返回包含基本信息的Command结构体
|
||||
func NewCommand(cmdType CommandType, name, description string) *Command {
|
||||
return &Command{
|
||||
Type: cmdType,
|
||||
Name: name,
|
||||
Description: description,
|
||||
Args: make([]string, 0),
|
||||
Flags: make(map[string]string),
|
||||
Booleans: make(map[string]bool),
|
||||
Integers: make(map[string]int64),
|
||||
Floats: make(map[string]float64),
|
||||
Options: make(map[string][]string),
|
||||
EnvVars: make(map[string]string),
|
||||
WorkingDir: getCurrentWorkingDir(),
|
||||
Custom: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
// NewServerCommand 创建服务器命令
|
||||
// 返回配置好的服务器命令实例
|
||||
func NewServerCommand() *Command {
|
||||
cmd := NewCommand(SERVER, "server", "Start the subconverter server")
|
||||
cmd.Usage = "server [flags]"
|
||||
cmd.Aliases = []string{"serve", "start"}
|
||||
|
||||
// 默认标志
|
||||
cmd.Booleans["debug"] = false
|
||||
cmd.Booleans["verbose"] = false
|
||||
cmd.Integers["port"] = 25500
|
||||
cmd.Flags["host"] = "0.0.0.0"
|
||||
cmd.Flags["config"] = ""
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewConfigCommand 创建配置命令
|
||||
// 返回配置好的配置命令实例
|
||||
func NewConfigCommand() *Command {
|
||||
cmd := NewCommand(CONFIG, "config", "Manage configuration")
|
||||
cmd.Usage = "config <subcommand> [flags]"
|
||||
cmd.Aliases = []string{"conf", "cfg"}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewTestCommand 创建测试命令
|
||||
// 返回配置好的测试命令实例
|
||||
func NewTestCommand() *Command {
|
||||
cmd := NewCommand(TEST, "test", "Run tests")
|
||||
cmd.Usage = "test <subcommand> [flags]"
|
||||
cmd.Aliases = []string{"t"}
|
||||
|
||||
cmd.Booleans["verbose"] = false
|
||||
cmd.Booleans["cover"] = false
|
||||
cmd.Flags["run"] = ""
|
||||
cmd.Flags["output"] = ""
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewVersionCommand 创建版本命令
|
||||
// 返回配置好的版本命令实例
|
||||
func NewVersionCommand() *Command {
|
||||
cmd := NewCommand(VERSION, "version", "Show version information")
|
||||
cmd.Usage = "version [flags]"
|
||||
cmd.Aliases = []string{"v", "ver"}
|
||||
|
||||
cmd.Booleans["verbose"] = false
|
||||
cmd.Booleans["short"] = false
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NewHelpCommand 创建帮助命令
|
||||
// 返回配置好的帮助命令实例
|
||||
func NewHelpCommand() *Command {
|
||||
cmd := NewCommand(HELP, "help", "Show help information")
|
||||
cmd.Usage = "help [command]"
|
||||
cmd.Aliases = []string{"h", "?"}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// AddArg 添加位置参数
|
||||
func (c *Command) AddArg(arg string) {
|
||||
c.Args = append(c.Args, arg)
|
||||
c.ArgsCount = len(c.Args)
|
||||
}
|
||||
|
||||
// AddArgs 添加多个位置参数
|
||||
func (c *Command) AddArgs(args ...string) {
|
||||
c.Args = append(c.Args, args...)
|
||||
c.ArgsCount = len(c.Args)
|
||||
}
|
||||
|
||||
// SetFlag 设置字符串标志
|
||||
func (c *Command) SetFlag(key, value string) {
|
||||
c.Flags[key] = value
|
||||
}
|
||||
|
||||
// SetBoolean 设置布尔标志
|
||||
func (c *Command) SetBoolean(key string, value bool) {
|
||||
c.Booleans[key] = value
|
||||
}
|
||||
|
||||
// SetInteger 设置整数标志
|
||||
func (c *Command) SetInteger(key string, value int64) {
|
||||
c.Integers[key] = value
|
||||
}
|
||||
|
||||
// SetFloat 设置浮点数标志
|
||||
func (c *Command) SetFloat(key string, value float64) {
|
||||
c.Floats[key] = value
|
||||
}
|
||||
|
||||
// AddOption 添加选项参数
|
||||
func (c *Command) AddOption(key string, values ...string) {
|
||||
if c.Options == nil {
|
||||
c.Options = make(map[string][]string)
|
||||
}
|
||||
c.Options[key] = append(c.Options[key], values...)
|
||||
}
|
||||
|
||||
// SetEnvVar 设置环境变量
|
||||
func (c *Command) SetEnvVar(key, value string) {
|
||||
if c.EnvVars == nil {
|
||||
c.EnvVars = make(map[string]string)
|
||||
}
|
||||
c.EnvVars[key] = value
|
||||
}
|
||||
|
||||
// GetArg 获取位置参数
|
||||
func (c *Command) GetArg(index int) (string, bool) {
|
||||
if index < 0 || index >= len(c.Args) {
|
||||
return "", false
|
||||
}
|
||||
return c.Args[index], true
|
||||
}
|
||||
|
||||
// GetFlag 获取字符串标志
|
||||
func (c *Command) GetFlag(key string) (string, bool) {
|
||||
value, exists := c.Flags[key]
|
||||
return value, exists
|
||||
}
|
||||
|
||||
// GetBoolean 获取布尔标志
|
||||
func (c *Command) GetBoolean(key string) (bool, bool) {
|
||||
value, exists := c.Booleans[key]
|
||||
return value, exists
|
||||
}
|
||||
|
||||
// GetInteger 获取整数标志
|
||||
func (c *Command) GetInteger(key string) (int64, bool) {
|
||||
value, exists := c.Integers[key]
|
||||
return value, exists
|
||||
}
|
||||
|
||||
// GetFloat 获取浮点数标志
|
||||
func (c *Command) GetFloat(key string) (float64, bool) {
|
||||
value, exists := c.Floats[key]
|
||||
return value, exists
|
||||
}
|
||||
|
||||
// GetOptions 获取选项参数
|
||||
func (c *Command) GetOptions(key string) ([]string, bool) {
|
||||
value, exists := c.Options[key]
|
||||
return value, exists
|
||||
}
|
||||
|
||||
// GetEnvVar 获取环境变量
|
||||
func (c *Command) GetEnvVar(key string) (string, bool) {
|
||||
value, exists := c.EnvVars[key]
|
||||
return value, exists
|
||||
}
|
||||
|
||||
// HasFlag 检查是否有指定标志
|
||||
func (c *Command) HasFlag(key string) bool {
|
||||
_, exists := c.Flags[key]
|
||||
return exists
|
||||
}
|
||||
|
||||
// HasBoolean 检查是否有指定布尔标志
|
||||
func (c *Command) HasBoolean(key string) bool {
|
||||
_, exists := c.Booleans[key]
|
||||
return exists
|
||||
}
|
||||
|
||||
// HasOption 检查是否有指定选项
|
||||
func (c *Command) HasOption(key string) bool {
|
||||
_, exists := c.Options[key]
|
||||
return exists
|
||||
}
|
||||
|
||||
// ArgCount 返回位置参数数量
|
||||
func (c *Command) ArgCount() int {
|
||||
return len(c.Args)
|
||||
}
|
||||
|
||||
// IsExecuted 检查命令是否已执行
|
||||
func (c *Command) IsExecuted() bool {
|
||||
return c.Executed
|
||||
}
|
||||
|
||||
// IsSuccessful 检查命令是否成功执行
|
||||
func (c *Command) IsSuccessful() bool {
|
||||
return c.Executed && c.ExitCode == 0
|
||||
}
|
||||
|
||||
// SetConfig 设置配置信息
|
||||
func (c *Command) SetConfig(config interface{}) {
|
||||
c.Config = config
|
||||
}
|
||||
|
||||
// SetConfigFile 设置配置文件路径
|
||||
func (c *Command) SetConfigFile(path string) {
|
||||
c.ConfigFile = path
|
||||
}
|
||||
|
||||
// SetOutput 设置输出信息
|
||||
func (c *Command) SetOutput(output string) {
|
||||
c.Output = output
|
||||
}
|
||||
|
||||
// SetError 设置错误信息
|
||||
func (c *Command) SetError(err error) {
|
||||
c.Error = err
|
||||
c.ExitCode = 1
|
||||
}
|
||||
|
||||
// MarkExecuted 标记命令为已执行
|
||||
func (c *Command) MarkExecuted() {
|
||||
c.Executed = true
|
||||
c.ExecutedAt = time.Now()
|
||||
}
|
||||
|
||||
// MarkSuccessful 标记命令为成功执行
|
||||
func (c *Command) MarkSuccessful() {
|
||||
c.MarkExecuted()
|
||||
c.ExitCode = 0
|
||||
}
|
||||
|
||||
// MarkFailed 标记命令为执行失败
|
||||
func (c *Command) MarkFailed(exitCode int) {
|
||||
c.MarkExecuted()
|
||||
c.ExitCode = exitCode
|
||||
}
|
||||
|
||||
// SetDuration 设置执行持续时间
|
||||
func (c *Command) SetDuration(duration time.Duration) {
|
||||
c.Duration = duration
|
||||
}
|
||||
|
||||
// AddCustom 添加自定义数据
|
||||
func (c *Command) AddCustom(key string, value interface{}) {
|
||||
if c.Custom == nil {
|
||||
c.Custom = make(map[string]interface{})
|
||||
}
|
||||
c.Custom[key] = value
|
||||
}
|
||||
|
||||
// GetCustom 获取自定义数据
|
||||
func (c *Command) GetCustom(key string) (interface{}, bool) {
|
||||
value, exists := c.Custom[key]
|
||||
return value, exists
|
||||
}
|
||||
|
||||
// Validate 验证命令的有效性
|
||||
func (c *Command) Validate() error {
|
||||
if c.Name == "" {
|
||||
return fmt.Errorf("command name cannot be empty")
|
||||
}
|
||||
|
||||
if c.Type < SERVER || c.Type > UNKNOWN {
|
||||
return fmt.Errorf("invalid command type: %d", c.Type)
|
||||
}
|
||||
|
||||
// 验证必需的参数
|
||||
switch c.Type {
|
||||
case SERVER:
|
||||
if port, exists := c.Integers["port"]; exists && (port < 1 || port > 65535) {
|
||||
return fmt.Errorf("invalid port number: %d", port)
|
||||
}
|
||||
case CONFIG:
|
||||
if len(c.Args) == 0 {
|
||||
return fmt.Errorf("config command requires a subcommand")
|
||||
}
|
||||
case TEST:
|
||||
if len(c.Args) == 0 {
|
||||
return fmt.Errorf("test command requires a subcommand")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUsage 返回使用说明
|
||||
func (c *Command) GetUsage() string {
|
||||
if c.Usage != "" {
|
||||
return c.Usage
|
||||
}
|
||||
return c.Name
|
||||
}
|
||||
|
||||
// GetFullUsage 返回完整的使用说明
|
||||
func (c *Command) GetFullUsage() string {
|
||||
var builder strings.Builder
|
||||
|
||||
builder.WriteString(fmt.Sprintf("Usage: %s", c.GetUsage()))
|
||||
|
||||
if c.Description != "" {
|
||||
builder.WriteString(fmt.Sprintf("\n\n%s", c.Description))
|
||||
}
|
||||
|
||||
if len(c.Aliases) > 0 {
|
||||
builder.WriteString(fmt.Sprintf("\n\nAliases: %s", strings.Join(c.Aliases, ", ")))
|
||||
}
|
||||
|
||||
// 添加位置参数说明
|
||||
if len(c.Args) > 0 {
|
||||
builder.WriteString("\n\nArguments:")
|
||||
for i, arg := range c.Args {
|
||||
builder.WriteString(fmt.Sprintf("\n %d: %s", i+1, arg))
|
||||
}
|
||||
}
|
||||
|
||||
// 添加标志说明
|
||||
if len(c.Flags) > 0 || len(c.Booleans) > 0 || len(c.Integers) > 0 || len(c.Floats) > 0 {
|
||||
builder.WriteString("\n\nFlags:")
|
||||
|
||||
for key, value := range c.Flags {
|
||||
builder.WriteString(fmt.Sprintf("\n --%s=%s", key, value))
|
||||
}
|
||||
|
||||
for key, value := range c.Booleans {
|
||||
builder.WriteString(fmt.Sprintf("\n --%s (default: %t)", key, value))
|
||||
}
|
||||
|
||||
for key, value := range c.Integers {
|
||||
builder.WriteString(fmt.Sprintf("\n --%s=%d", key, value))
|
||||
}
|
||||
|
||||
for key, value := range c.Floats {
|
||||
builder.WriteString(fmt.Sprintf("\n --%s=%f", key, value))
|
||||
}
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// Clone 创建命令的副本
|
||||
func (c *Command) Clone() *Command {
|
||||
clone := &Command{
|
||||
Type: c.Type,
|
||||
Name: c.Name,
|
||||
Description: c.Description,
|
||||
Usage: c.Usage,
|
||||
ArgsCount: c.ArgsCount,
|
||||
ConfigFile: c.ConfigFile,
|
||||
Config: c.Config,
|
||||
Executed: c.Executed,
|
||||
ExecutedAt: c.ExecutedAt,
|
||||
Duration: c.Duration,
|
||||
ExitCode: c.ExitCode,
|
||||
Output: c.Output,
|
||||
Error: c.Error,
|
||||
WorkingDir: c.WorkingDir,
|
||||
UserID: c.UserID,
|
||||
SessionID: c.SessionID,
|
||||
Debug: c.Debug,
|
||||
Verbose: c.Verbose,
|
||||
Quiet: c.Quiet,
|
||||
DryRun: c.DryRun,
|
||||
}
|
||||
|
||||
// 深拷贝切片
|
||||
if len(c.Aliases) > 0 {
|
||||
clone.Aliases = make([]string, len(c.Aliases))
|
||||
copy(clone.Aliases, c.Aliases)
|
||||
}
|
||||
|
||||
if len(c.Args) > 0 {
|
||||
clone.Args = make([]string, len(c.Args))
|
||||
copy(clone.Args, c.Args)
|
||||
}
|
||||
|
||||
// 深拷贝映射
|
||||
if len(c.Flags) > 0 {
|
||||
clone.Flags = make(map[string]string)
|
||||
for k, v := range c.Flags {
|
||||
clone.Flags[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Booleans) > 0 {
|
||||
clone.Booleans = make(map[string]bool)
|
||||
for k, v := range c.Booleans {
|
||||
clone.Booleans[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Integers) > 0 {
|
||||
clone.Integers = make(map[string]int64)
|
||||
for k, v := range c.Integers {
|
||||
clone.Integers[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Floats) > 0 {
|
||||
clone.Floats = make(map[string]float64)
|
||||
for k, v := range c.Floats {
|
||||
clone.Floats[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Options) > 0 {
|
||||
clone.Options = make(map[string][]string)
|
||||
for k, v := range c.Options {
|
||||
clone.Options[k] = make([]string, len(v))
|
||||
copy(clone.Options[k], v)
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.EnvVars) > 0 {
|
||||
clone.EnvVars = make(map[string]string)
|
||||
for k, v := range c.EnvVars {
|
||||
clone.EnvVars[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Custom) > 0 {
|
||||
clone.Custom = make(map[string]interface{})
|
||||
for k, v := range c.Custom {
|
||||
clone.Custom[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return clone
|
||||
}
|
||||
|
||||
// String 返回命令的字符串表示
|
||||
func (c *Command) String() string {
|
||||
if c.Executed {
|
||||
return fmt.Sprintf("%s (executed in %v, exit code: %d)", c.Name, c.Duration, c.ExitCode)
|
||||
}
|
||||
return fmt.Sprintf("%s (not executed)", c.Name)
|
||||
}
|
||||
|
||||
// GetCurrentWorkingDir 获取当前工作目录
|
||||
func getCurrentWorkingDir() string {
|
||||
if dir, err := os.Getwd(); err == nil {
|
||||
return dir
|
||||
}
|
||||
return "."
|
||||
}
|
||||
|
||||
// CommandTypeToString 将命令类型转换为字符串
|
||||
func CommandTypeToString(cmdType CommandType) string {
|
||||
switch cmdType {
|
||||
case SERVER:
|
||||
return "server"
|
||||
case CONFIG:
|
||||
return "config"
|
||||
case TEST:
|
||||
return "test"
|
||||
case VERSION:
|
||||
return "version"
|
||||
case HELP:
|
||||
return "help"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// StringToCommandType 将字符串转换为命令类型
|
||||
func StringToCommandType(s string) CommandType {
|
||||
switch strings.ToLower(s) {
|
||||
case "server", "serve", "start":
|
||||
return SERVER
|
||||
case "config", "conf", "cfg":
|
||||
return CONFIG
|
||||
case "test", "t":
|
||||
return TEST
|
||||
case "version", "v", "ver":
|
||||
return VERSION
|
||||
case "help", "h", "?":
|
||||
return HELP
|
||||
default:
|
||||
return UNKNOWN
|
||||
}
|
||||
}
|
||||
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