diff --git a/main/confloader/confloader.go b/main/confloader/confloader.go new file mode 100644 index 000000000..f9dd9223d --- /dev/null +++ b/main/confloader/confloader.go @@ -0,0 +1,21 @@ +package confloader + +import ( + "io" + "os" +) + +//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg confloader -path Main,ConfLoader + +type configFileLoader func(string) (io.ReadCloser, error) + +var ( + EffectiveConfigFileLoader configFileLoader +) + +func LoadConfig(file string) (io.ReadCloser, error) { + if EffectiveConfigFileLoader == nil { + return os.Stdin, nil + } + return EffectiveConfigFileLoader(file) +} diff --git a/main/confloader/errors.generated.go b/main/confloader/errors.generated.go new file mode 100644 index 000000000..41fb556ca --- /dev/null +++ b/main/confloader/errors.generated.go @@ -0,0 +1,5 @@ +package confloader + +import "v2ray.com/core/common/errors" + +func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Main", "ConfLoader") } diff --git a/main/confloader/external/errors.generated.go b/main/confloader/external/errors.generated.go new file mode 100644 index 000000000..0c85ab53c --- /dev/null +++ b/main/confloader/external/errors.generated.go @@ -0,0 +1,5 @@ +package external + +import "v2ray.com/core/common/errors" + +func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Main", "ConfLoader", "External") } diff --git a/main/confloader/external/external.go b/main/confloader/external/external.go new file mode 100644 index 000000000..21cc709a2 --- /dev/null +++ b/main/confloader/external/external.go @@ -0,0 +1,54 @@ +package external + +import ( + "io" + "os" + "strings" + + "v2ray.com/core/common/buf" + "v2ray.com/core/common/platform/ctlcmd" + "v2ray.com/core/main/confloader" +) + +//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg external -path Main,ConfLoader,External + +type ClosableMultiBuffer struct { + buf.MultiBuffer +} + +func (c *ClosableMultiBuffer) Close() error { + c.MultiBuffer.Release() + return nil +} + +func loadConfigFile(configFile string) (io.ReadCloser, error) { + if configFile == "stdin:" { + return os.Stdin, nil + } + + if strings.HasPrefix(configFile, "http://") || strings.HasPrefix(configFile, "https://") { + content, err := ctlcmd.Run([]string{"fetch", configFile}, nil) + if err != nil { + return nil, err + } + return &ClosableMultiBuffer{content}, nil + } + + fixedFile := os.ExpandEnv(configFile) + file, err := os.Open(fixedFile) + if err != nil { + return nil, newError("config file not readable").Base(err) + } + defer file.Close() + + content, err := buf.ReadAllToMultiBuffer(file) + if err != nil { + return nil, newError("failed to load config file: ", fixedFile).Base(err).AtWarning() + } + return &ClosableMultiBuffer{content}, nil + +} + +func init() { + confloader.EffectiveConfigFileLoader = loadConfigFile +} diff --git a/main/distro/all/all.go b/main/distro/all/all.go index 989d7c2e0..486c5be8b 100644 --- a/main/distro/all/all.go +++ b/main/distro/all/all.go @@ -48,4 +48,7 @@ import ( // JSON config format _ "v2ray.com/core/main/json" + + // Load config from file or http(s) + _ "v2ray.com/core/main/confloader/external" ) diff --git a/main/main.go b/main/main.go index 55b293d08..6179b676a 100644 --- a/main/main.go +++ b/main/main.go @@ -5,7 +5,6 @@ package main import ( "flag" "fmt" - "io" "os" "os/signal" "path/filepath" @@ -14,7 +13,7 @@ import ( "v2ray.com/core" "v2ray.com/core/common/platform" - "v2ray.com/core/common/platform/ctlcmd" + "v2ray.com/core/main/confloader" _ "v2ray.com/core/main/distro/all" ) @@ -61,24 +60,12 @@ func GetConfigFormat() string { func startV2Ray() (core.Server, error) { configFile := getConfigFilePath() - var configInput io.Reader - if configFile == "stdin:" { - configInput = os.Stdin - } else if strings.HasPrefix(configFile, "http://") || strings.HasPrefix(configFile, "https://") { - content, err := ctlcmd.Run([]string{"fetch", configFile}, nil) - if err != nil { - return nil, err - } - configInput = &content - } else { - fixedFile := os.ExpandEnv(configFile) - file, err := os.Open(fixedFile) - if err != nil { - return nil, newError("config file not readable").Base(err) - } - defer file.Close() - configInput = file + configInput, err := confloader.LoadConfig(configFile) + if err != nil { + return nil, newError("failed to load config: ", configFile).Base(err) } + defer configInput.Close() + config, err := core.LoadConfig(GetConfigFormat(), configFile, configInput) if err != nil { return nil, newError("failed to read config file: ", configFile).Base(err)