Browse Source

abstract type for conf load func

vcptr 6 years ago
parent
commit
1bb34bfe17
5 changed files with 95 additions and 57 deletions
  1. 14 0
      common/cmdarg/cmdarg.go
  2. 26 8
      config.go
  3. 16 12
      main/json/config_json.go
  4. 19 15
      main/jsonem/jsonem.go
  5. 20 22
      main/main.go

+ 14 - 0
common/cmdarg/cmdarg.go

@@ -0,0 +1,14 @@
+package cmdarg
+
+import "strings"
+
+type Arg []string
+
+func (c *Arg) String() string {
+	return strings.Join([]string(*c), " ")
+}
+
+func (c *Arg) Set(value string) error {
+	*c = append(*c, value)
+	return nil
+}

+ 26 - 8
config.go

@@ -4,11 +4,13 @@ package core
 
 
 import (
 import (
 	"io"
 	"io"
+	"io/ioutil"
 	"strings"
 	"strings"
 
 
 	"github.com/golang/protobuf/proto"
 	"github.com/golang/protobuf/proto"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/buf"
+	"v2ray.com/core/common/cmdarg"
 )
 )
 
 
 // ConfigFormat is a configurable format of V2Ray config file.
 // ConfigFormat is a configurable format of V2Ray config file.
@@ -19,7 +21,7 @@ type ConfigFormat struct {
 }
 }
 
 
 // ConfigLoader is a utility to load V2Ray config from external source.
 // ConfigLoader is a utility to load V2Ray config from external source.
-type ConfigLoader func(input io.Reader) (*Config, error)
+type ConfigLoader func(input interface{}) (*Config, error)
 
 
 var (
 var (
 	configLoaderByName = make(map[string]*ConfigFormat)
 	configLoaderByName = make(map[string]*ConfigFormat)
@@ -54,7 +56,10 @@ func getExtension(filename string) string {
 }
 }
 
 
 // LoadConfig loads config with given format from given source.
 // LoadConfig loads config with given format from given source.
-func LoadConfig(formatName string, filename string, input io.Reader) (*Config, error) {
+// input accepts 2 different types:
+// * []string slice of multiple filename/url(s) to open to read
+// * io.Reader that reads a config content (the original way)
+func LoadConfig(formatName string, filename string, input interface{}) (*Config, error) {
 	ext := getExtension(filename)
 	ext := getExtension(filename)
 	if len(ext) > 0 {
 	if len(ext) > 0 {
 		if f, found := configLoaderByExt[ext]; found {
 		if f, found := configLoaderByExt[ext]; found {
@@ -69,12 +74,8 @@ func LoadConfig(formatName string, filename string, input io.Reader) (*Config, e
 	return nil, newError("Unable to load config in ", formatName).AtWarning()
 	return nil, newError("Unable to load config in ", formatName).AtWarning()
 }
 }
 
 
-func loadProtobufConfig(input io.Reader) (*Config, error) {
+func loadProtobufConfig(data []byte) (*Config, error) {
 	config := new(Config)
 	config := new(Config)
-	data, err := buf.ReadAllToBytes(input)
-	if err != nil {
-		return nil, err
-	}
 	if err := proto.Unmarshal(data, config); err != nil {
 	if err := proto.Unmarshal(data, config); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -85,6 +86,23 @@ func init() {
 	common.Must(RegisterConfigLoader(&ConfigFormat{
 	common.Must(RegisterConfigLoader(&ConfigFormat{
 		Name:      "Protobuf",
 		Name:      "Protobuf",
 		Extension: []string{"pb"},
 		Extension: []string{"pb"},
-		Loader:    loadProtobufConfig,
+		Loader: func(input interface{}) (*Config, error) {
+			switch v := input.(type) {
+			case cmdarg.Arg:
+				if len(v) == 0 {
+					return nil, newError("input has no element")
+				}
+				// pb type can only handle the first config
+				data, err := ioutil.ReadFile(v[0])
+				common.Must(err)
+				return loadProtobufConfig(data)
+			case io.Reader:
+				data, err := buf.ReadAllToBytes(v)
+				common.Must(err)
+				return loadProtobufConfig(data)
+			default:
+				return nil, newError("unknow type")
+			}
+		},
 	}))
 	}))
 }
 }

+ 16 - 12
main/json/config_json.go

@@ -3,31 +3,35 @@ package json
 //go:generate errorgen
 //go:generate errorgen
 
 
 import (
 import (
-	"encoding/json"
 	"io"
 	"io"
-	"io/ioutil"
 
 
 	"v2ray.com/core"
 	"v2ray.com/core"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/buf"
+	"v2ray.com/core/common/cmdarg"
 	"v2ray.com/core/common/platform/ctlcmd"
 	"v2ray.com/core/common/platform/ctlcmd"
+	"v2ray.com/core/infra/conf/serial"
 )
 )
 
 
 func init() {
 func init() {
 	common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
 	common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
 		Name:      "JSON",
 		Name:      "JSON",
 		Extension: []string{"json"},
 		Extension: []string{"json"},
-		Loader: func(input io.Reader) (*core.Config, error) {
-			fns := []string{}
-			data, _ := ioutil.ReadAll(input)
-			json.Unmarshal(data, &fns)
-			jsonContent, err := ctlcmd.Run(append([]string{"config"}, fns...), nil)
-			if err != nil {
-				return nil, newError("failed to execute v2ctl to convert config file.").Base(err).AtWarning()
+		Loader: func(input interface{}) (*core.Config, error) {
+			switch v := input.(type) {
+			case cmdarg.Arg:
+				jsonContent, err := ctlcmd.Run(append([]string{"config"}, v...), nil)
+				if err != nil {
+					return nil, newError("failed to execute v2ctl to convert config file.").Base(err).AtWarning()
+				}
+				return core.LoadConfig("protobuf", "", &buf.MultiBufferContainer{
+					MultiBuffer: jsonContent,
+				})
+			case io.Reader:
+				return serial.LoadJSONConfig(v)
+			default:
+				return nil, newError("unknow type")
 			}
 			}
-			return core.LoadConfig("protobuf", "", &buf.MultiBufferContainer{
-				MultiBuffer: jsonContent,
-			})
 		},
 		},
 	}))
 	}))
 }
 }

+ 19 - 15
main/jsonem/jsonem.go

@@ -2,7 +2,6 @@ package jsonem
 
 
 import (
 import (
 	"bytes"
 	"bytes"
-	"encoding/json"
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
@@ -13,6 +12,7 @@ import (
 	"v2ray.com/core"
 	"v2ray.com/core"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/buf"
+	"v2ray.com/core/common/cmdarg"
 	"v2ray.com/core/infra/conf"
 	"v2ray.com/core/infra/conf"
 	"v2ray.com/core/infra/conf/serial"
 	"v2ray.com/core/infra/conf/serial"
 )
 )
@@ -21,21 +21,25 @@ func init() {
 	common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
 	common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
 		Name:      "JSON",
 		Name:      "JSON",
 		Extension: []string{"json"},
 		Extension: []string{"json"},
-		Loader: func(input io.Reader) (*core.Config, error) {
-			fns := []string{}
-			data, _ := ioutil.ReadAll(input)
-			json.Unmarshal(data, &fns)
-
-			cf := &conf.Config{}
-			for _, arg := range fns {
-				r, err := LoadArg(arg)
-				common.Must(err)
-				c, err := serial.DecodeJSONConfig(r)
-				common.Must(err)
-				cf.Override(c, arg)
+		Loader: func(input interface{}) (*core.Config, error) {
+			switch v := input.(type) {
+			case cmdarg.Arg:
+				cf := &conf.Config{}
+				for _, arg := range v {
+					r, err := LoadArg(arg)
+					common.Must(err)
+					c, err := serial.DecodeJSONConfig(r)
+					common.Must(err)
+					cf.Override(c, arg)
+				}
+				return cf.Build()
+			case io.Reader:
+				return serial.LoadJSONConfig(v)
+			default:
+				return nil, newError("unknow type")
 			}
 			}
-			return cf.Build()
-		}}))
+		},
+	}))
 }
 }
 
 
 func LoadArg(arg string) (out io.Reader, err error) {
 func LoadArg(arg string) (out io.Reader, err error) {

+ 20 - 22
main/main.go

@@ -3,8 +3,6 @@ package main
 //go:generate errorgen
 //go:generate errorgen
 
 
 import (
 import (
-	"bytes"
-	"encoding/json"
 	"flag"
 	"flag"
 	"fmt"
 	"fmt"
 	"os"
 	"os"
@@ -15,26 +13,17 @@ import (
 	"syscall"
 	"syscall"
 
 
 	"v2ray.com/core"
 	"v2ray.com/core"
+	"v2ray.com/core/common/cmdarg"
 	"v2ray.com/core/common/platform"
 	"v2ray.com/core/common/platform"
 	_ "v2ray.com/core/main/distro/all"
 	_ "v2ray.com/core/main/distro/all"
 )
 )
 
 
-type CmdConfig []string
-
-func (c *CmdConfig) String() string {
-	return strings.Join([]string(*c), ",")
-}
-
-func (c *CmdConfig) Set(value string) error {
-	*c = append(*c, value)
-	return nil
-}
-
 var (
 var (
-	configFiles CmdConfig // "Config file for V2Ray.", the option is customed type, parse in main
+	configFiles cmdarg.Arg // "Config file for V2Ray.", the option is customed type, parse in main
 	version     = flag.Bool("version", false, "Show current version of V2Ray.")
 	version     = flag.Bool("version", false, "Show current version of V2Ray.")
 	test        = flag.Bool("test", false, "Test config file only, without launching V2Ray server.")
 	test        = flag.Bool("test", false, "Test config file only, without launching V2Ray server.")
-	format      = flag.String("format", "json", "Format of input file.")
+	format      = flag.String("format", "", "Format of input file.")
+	errNoConfig = newError("no valid config")
 )
 )
 
 
 func fileExists(file string) bool {
 func fileExists(file string) bool {
@@ -42,8 +31,7 @@ func fileExists(file string) bool {
 	return err == nil && !info.IsDir()
 	return err == nil && !info.IsDir()
 }
 }
 
 
-func getConfigFilePath() CmdConfig {
-
+func getConfigFilePath() cmdarg.Arg {
 	if len(configFiles) > 0 {
 	if len(configFiles) > 0 {
 		return configFiles
 		return configFiles
 	}
 	}
@@ -51,15 +39,15 @@ func getConfigFilePath() CmdConfig {
 	if workingDir, err := os.Getwd(); err == nil {
 	if workingDir, err := os.Getwd(); err == nil {
 		configFile := filepath.Join(workingDir, "config.json")
 		configFile := filepath.Join(workingDir, "config.json")
 		if fileExists(configFile) {
 		if fileExists(configFile) {
-			return []string{configFile}
+			return cmdarg.Arg{configFile}
 		}
 		}
 	}
 	}
 
 
 	if configFile := platform.GetConfigurationPath(); fileExists(configFile) {
 	if configFile := platform.GetConfigurationPath(); fileExists(configFile) {
-		return []string{configFile}
+		return cmdarg.Arg{configFile}
 	}
 	}
 
 
-	return []string{}
+	return configFiles
 }
 }
 
 
 func GetConfigFormat() string {
 func GetConfigFormat() string {
@@ -73,8 +61,14 @@ func GetConfigFormat() string {
 
 
 func startV2Ray() (core.Server, error) {
 func startV2Ray() (core.Server, error) {
 	configFiles := getConfigFilePath()
 	configFiles := getConfigFilePath()
-	fs, _ := json.Marshal(configFiles)
-	config, err := core.LoadConfig(GetConfigFormat(), configFiles[0], bytes.NewBuffer(fs))
+	if len(configFiles) == 0 {
+		if *format == "" {
+			return nil, errNoConfig
+		}
+		configFiles = []string{"stdin:"}
+	}
+
+	config, err := core.LoadConfig(GetConfigFormat(), configFiles[0], configFiles)
 	if err != nil {
 	if err != nil {
 		return nil, newError("failed to read config files: [", configFiles.String(), "]").Base(err)
 		return nil, newError("failed to read config files: [", configFiles.String(), "]").Base(err)
 	}
 	}
@@ -96,6 +90,7 @@ func printVersion() {
 
 
 func main() {
 func main() {
 	flag.Var(&configFiles, "config", "Config file for V2Ray. Multiple assign is accepted (only json). Latter ones overrides the former ones.")
 	flag.Var(&configFiles, "config", "Config file for V2Ray. Multiple assign is accepted (only json). Latter ones overrides the former ones.")
+	flag.Var(&configFiles, "c", "short alias of -config")
 	flag.Parse()
 	flag.Parse()
 
 
 	printVersion()
 	printVersion()
@@ -108,6 +103,9 @@ func main() {
 	if err != nil {
 	if err != nil {
 		fmt.Println(err.Error())
 		fmt.Println(err.Error())
 		// Configuration error. Exit with a special value to prevent systemd from restarting.
 		// Configuration error. Exit with a special value to prevent systemd from restarting.
+		if err == errNoConfig {
+			flag.PrintDefaults()
+		}
 		os.Exit(23)
 		os.Exit(23)
 	}
 	}