diff --git a/main/commands/run.go b/main/commands/run.go index b948b9f74..2fbb7a2bc 100644 --- a/main/commands/run.go +++ b/main/commands/run.go @@ -4,15 +4,59 @@ import ( "fmt" "log" "os" + "os/signal" "path/filepath" + "runtime" "strings" + "syscall" core "github.com/v2fly/v2ray-core/v5" "github.com/v2fly/v2ray-core/v5/common/cmdarg" "github.com/v2fly/v2ray-core/v5/common/platform" "github.com/v2fly/v2ray-core/v5/main/commands/base" + "github.com/v2fly/v2ray-core/v5/main/plugins" ) +// CmdRun runs V2Ray with config +var CmdRun = &base.Command{ + CustomFlags: true, + UsageLine: "{{.Exec}} run [-c config.json] [-d dir]", + Short: "run V2Ray with config", + Long: ` +Run V2Ray with config. + +{{.Exec}} will also use the config directory specified by environment +variable "v2ray.location.confdir". If no config found, it tries +to load config from one of below: + + 1. The default "config.json" in the current directory + 2. The config file from ENV "v2ray.location.config" + 3. The stdin if all failed above + +Arguments: + + -c, -config + Config file for V2Ray. Multiple assign is accepted. + + -d, -confdir + A directory with config files. Multiple assign is accepted. + + -r + Load confdir recursively. + + -format + Format of config input. (default "auto") + +Examples: + + {{.Exec}} {{.LongName}} -c config.json + {{.Exec}} {{.LongName}} -d path/to/dir + +Use "{{.Exec}} help format-loader" for more information about format. + `, + Run: executeRun, +} + var ( configFiles cmdarg.Arg configDirs cmdarg.Arg @@ -30,6 +74,45 @@ func setConfigFlags(cmd *base.Command) { cmd.Flag.Var(&configDirs, "d", "") } +func executeRun(cmd *base.Command, args []string) { + setConfigFlags(cmd) + var pluginFuncs []func() error + for _, plugin := range plugins.Plugins { + if f := plugin(cmd); f != nil { + pluginFuncs = append(pluginFuncs, f) + } + } + cmd.Flag.Parse(args) + printVersion() + configFiles = getConfigFilePath() + server, err := startV2Ray() + if err != nil { + base.Fatalf("Failed to start: %s", err) + } + + for _, f := range pluginFuncs { + go func(f func() error) { + if err := f(); err != nil { + log.Print(err) + } + }(f) + } + + if err := server.Start(); err != nil { + base.Fatalf("Failed to start: %s", err) + } + defer server.Close() + + // Explicitly triggering GC to remove garbage from config loading. + runtime.GC() + + { + osSignals := make(chan os.Signal, 1) + signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM) + <-osSignals + } +} + func fileExists(file string) bool { info, err := os.Stat(file) return err == nil && !info.IsDir() diff --git a/main/commands/run_default.go b/main/commands/run_default.go deleted file mode 100644 index 3a44b23c8..000000000 --- a/main/commands/run_default.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build !pprof -// +build !pprof - -package commands - -import ( - "os" - "os/signal" - "runtime" - "syscall" - - "github.com/v2fly/v2ray-core/v5/main/commands/base" -) - -// CmdRun runs V2Ray with config -var CmdRun = &base.Command{ - CustomFlags: true, - UsageLine: "{{.Exec}} run [-c config.json] [-d dir]", - Short: "run V2Ray with config", - Long: ` -Run V2Ray with config. - -{{.Exec}} will also use the config directory specified by environment -variable "v2ray.location.confdir". If no config found, it tries -to load config from one of below: - - 1. The default "config.json" in the current directory - 2. The config file from ENV "v2ray.location.config" - 3. The stdin if all failed above - -Arguments: - - -c, -config - Config file for V2Ray. Multiple assign is accepted. - - -d, -confdir - A directory with config files. Multiple assign is accepted. - - -r - Load confdir recursively. - - -format - Format of config input. (default "auto") - -Examples: - - {{.Exec}} {{.LongName}} -c config.json - {{.Exec}} {{.LongName}} -d path/to/dir - -Use "{{.Exec}} help format-loader" for more information about format. - `, - Run: executeRun, -} - -func executeRun(cmd *base.Command, args []string) { - setConfigFlags(cmd) - cmd.Flag.Parse(args) - printVersion() - configFiles = getConfigFilePath() - server, err := startV2Ray() - if err != nil { - base.Fatalf("Failed to start: %s", err) - } - - if err := server.Start(); err != nil { - base.Fatalf("Failed to start: %s", err) - } - defer server.Close() - - // Explicitly triggering GC to remove garbage from config loading. - runtime.GC() - - { - osSignals := make(chan os.Signal, 1) - signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM) - <-osSignals - } -} diff --git a/main/commands/run_pprof.go b/main/commands/run_pprof.go deleted file mode 100644 index 201a459a2..000000000 --- a/main/commands/run_pprof.go +++ /dev/null @@ -1,93 +0,0 @@ -//go:build pprof -// +build pprof - -package commands - -import ( - "log" - "net/http" - _ "net/http/pprof" - "os" - "os/signal" - "runtime" - "syscall" - - "github.com/v2fly/v2ray-core/v5/main/commands/base" -) - -// CmdRun runs V2Ray with config -var CmdRun = &base.Command{ - CustomFlags: true, - UsageLine: "{{.Exec}} run [-c config.json] [-d dir] [-pprof port]", - Short: "run V2Ray with config", - Long: ` -Run V2Ray with config. - -{{.Exec}} will also use the config directory specified by environment -variable "v2ray.location.confdir". If no config found, it tries -to load config from one of below: - - 1. The default "config.json" in the current directory - 2. The config file from ENV "v2ray.location.config" - 3. The stdin if all failed above - -Arguments: - - -c, -config - Config file for V2Ray. Multiple assign is accepted. - - -d, -confdir - A directory with config files. Multiple assign is accepted. - - -r - Load confdir recursively. - - -format - Format of config input. (default "auto") - - -pprof - HTTP server port for pprof debugging. (default "8080") - -Examples: - - {{.Exec}} {{.LongName}} -c config.json - {{.Exec}} {{.LongName}} -d path/to/dir - -Use "{{.Exec}} help format-loader" for more information about format. - `, - Run: executeRun, -} - -func executeRun(cmd *base.Command, args []string) { - setConfigFlags(cmd) - pprof := cmd.Flag.String("pprof", ":8080", "") - cmd.Flag.Parse(args) - printVersion() - configFiles = getConfigFilePath() - server, err := startV2Ray() - if err != nil { - base.Fatalf("Failed to start: %s", err) - } - - if addr := *pprof; addr != "" { - go func() { - if err := http.ListenAndServe(addr, nil); err != nil { - log.Print(err) - } - }() - } - - if err := server.Start(); err != nil { - base.Fatalf("Failed to start: %s", err) - } - defer server.Close() - - // Explicitly triggering GC to remove garbage from config loading. - runtime.GC() - - { - osSignals := make(chan os.Signal, 1) - signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM) - <-osSignals - } -} diff --git a/main/plugins/plugin.go b/main/plugins/plugin.go new file mode 100644 index 000000000..58786b00a --- /dev/null +++ b/main/plugins/plugin.go @@ -0,0 +1,11 @@ +package plugins + +import "github.com/v2fly/v2ray-core/v5/main/commands/base" + +var Plugins []Plugin + +type Plugin func(*base.Command) func() error + +func RegisterPlugin(plugin Plugin) { + Plugins = append(Plugins, plugin) +} diff --git a/main/plugins/plugin_pprof.go b/main/plugins/plugin_pprof.go new file mode 100644 index 000000000..85f3bf763 --- /dev/null +++ b/main/plugins/plugin_pprof.go @@ -0,0 +1,28 @@ +package plugins + +import ( + "net/http" + "net/http/pprof" + + "github.com/v2fly/v2ray-core/v5/main/commands/base" +) + +var pprofPlugin Plugin = func(cmd *base.Command) func() error { + addr := cmd.Flag.String("pprof", "", "") + return func() error { + if *addr != "" { + h := http.NewServeMux() + h.HandleFunc("/debug/pprof/", pprof.Index) + h.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + h.HandleFunc("/debug/pprof/profile", pprof.Profile) + h.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + h.HandleFunc("/debug/pprof/trace", pprof.Trace) + return (&http.Server{Addr: *addr, Handler: h}).ListenAndServe() + } + return nil + } +} + +func init() { + RegisterPlugin(pprofPlugin) +}