diff --git a/go.mod b/go.mod index 5906486a..acc021e8 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.15 require ( github.com/BurntSushi/toml v0.3.1 github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect + github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.3 github.com/google/go-cmp v0.5.4 diff --git a/go.sum b/go.sum index 72190eb4..13b54d7c 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= +github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/infra/conf/serial/loader.go b/infra/conf/serial/loader.go index b0f9f128..61ee8077 100644 --- a/infra/conf/serial/loader.go +++ b/infra/conf/serial/loader.go @@ -7,6 +7,8 @@ import ( "io/ioutil" "github.com/BurntSushi/toml" + "github.com/ghodss/yaml" + "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/core" "github.com/xtls/xray-core/infra/conf" @@ -117,3 +119,35 @@ func LoadTOMLConfig(reader io.Reader) (*core.Config, error) { return pbConfig, nil } + +// DecodeYAMLConfig reads from reader and decode the config into *conf.Config +// using github.com/ghodss/yaml to convert yaml to json +// syntax error could be detected. +func DecodeYAMLConfig(reader io.Reader) (*conf.Config, error) { + + yamlFile, err := ioutil.ReadAll(reader) + if err != nil { + return nil, newError("failed to read config file").Base(err) + } + + jsonFile, err := yaml.YAMLToJSON(yamlFile) + if err != nil { + return nil, newError("failed to read config file").Base(err) + } + + return DecodeJSONConfig(bytes.NewReader(jsonFile)) +} + +func LoadYAMLConfig(reader io.Reader) (*core.Config, error) { + yamlConfig, err := DecodeYAMLConfig(reader) + if err != nil { + return nil, err + } + + pbConfig, err := yamlConfig.Build() + if err != nil { + return nil, newError("failed to parse yaml config").Base(err) + } + + return pbConfig, nil +} diff --git a/main/distro/all/all.go b/main/distro/all/all.go index cc7ec2f0..197ae627 100644 --- a/main/distro/all/all.go +++ b/main/distro/all/all.go @@ -62,6 +62,7 @@ import ( // _ "github.com/xtls/xray-core/main/json" // The following line loads JSON internally _ "github.com/xtls/xray-core/main/jsonem" + _ "github.com/xtls/xray-core/main/yaml" _ "github.com/xtls/xray-core/main/toml" diff --git a/main/run.go b/main/run.go index 33fefaa1..f5cfb94f 100644 --- a/main/run.go +++ b/main/run.go @@ -152,6 +152,8 @@ func getConfigFilePath() cmdarg.Arg { func getConfigFormat() string { switch strings.ToLower(*format) { + case "yaml", "yml": + return "yaml" case "pb", "protobuf": return "protobuf" case "toml": @@ -165,6 +167,9 @@ func startXray() (core.Server, error) { configFiles := getConfigFilePath() config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles) + + //config, err := core.LoadConfigs(getConfigFormat(), configFiles) + if err != nil { return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err) } diff --git a/main/yaml/errors.generated.go b/main/yaml/errors.generated.go new file mode 100644 index 00000000..c4da8fa9 --- /dev/null +++ b/main/yaml/errors.generated.go @@ -0,0 +1,9 @@ +package yaml + +import "github.com/xtls/xray-core/common/errors" + +type errPathObjHolder struct{} + +func newError(values ...interface{}) *errors.Error { + return errors.New(values...).WithPathObj(errPathObjHolder{}) +} diff --git a/main/yaml/yaml.go b/main/yaml/yaml.go new file mode 100644 index 00000000..4a647756 --- /dev/null +++ b/main/yaml/yaml.go @@ -0,0 +1,44 @@ +package yaml + +import ( + "io" + + "github.com/xtls/xray-core/common" + "github.com/xtls/xray-core/common/cmdarg" + "github.com/xtls/xray-core/core" + "github.com/xtls/xray-core/infra/conf" + "github.com/xtls/xray-core/infra/conf/serial" + "github.com/xtls/xray-core/main/confloader" +) + +func init() { + common.Must(core.RegisterConfigLoader(&core.ConfigFormat{ + Name: "YAML", + Extension: []string{"yaml", "yml"}, + Loader: func(input interface{}) (*core.Config, error) { + switch v := input.(type) { + case cmdarg.Arg: + cf := &conf.Config{} + for i, arg := range v { + newError("Reading config: ", arg).AtInfo().WriteToLog() + r, err := confloader.LoadConfig(arg) + common.Must(err) + c, err := serial.DecodeYAMLConfig(r) + common.Must(err) + if i == 0 { + // This ensure even if the muti-json parser do not support a setting, + // It is still respected automatically for the first configure file + *cf = *c + continue + } + cf.Override(c, arg) + } + return cf.Build() + case io.Reader: + return serial.LoadYAMLConfig(v) + default: + return nil, newError("unknow type") + } + }, + })) +}