mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-25 06:36:05 +03:00
Support loading config from different formats (#228)
This commit is contained in:
parent
96d7156eba
commit
1b87264c53
@ -22,9 +22,13 @@ type ConfigFormat struct {
|
||||
// ConfigLoader is a utility to load Xray config from external source.
|
||||
type ConfigLoader func(input interface{}) (*Config, error)
|
||||
|
||||
// ConfigBuilder is a builder to build core.Config from filenames and formats
|
||||
type ConfigBuilder func(files []string, formats []string) (*Config, error)
|
||||
|
||||
var (
|
||||
configLoaderByName = make(map[string]*ConfigFormat)
|
||||
configLoaderByExt = make(map[string]*ConfigFormat)
|
||||
configLoaderByName = make(map[string]*ConfigFormat)
|
||||
configLoaderByExt = make(map[string]*ConfigFormat)
|
||||
ConfigBuilderForFiles ConfigBuilder
|
||||
)
|
||||
|
||||
// RegisterConfigLoader add a new ConfigLoader.
|
||||
@ -46,6 +50,21 @@ func RegisterConfigLoader(format *ConfigFormat) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetFormatByExtension(ext string) string {
|
||||
switch strings.ToLower(ext) {
|
||||
case "pb", "protobuf":
|
||||
return "protobuf"
|
||||
case "yaml", "yml":
|
||||
return "yaml"
|
||||
case "toml":
|
||||
return "toml"
|
||||
case "json":
|
||||
return "json"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func getExtension(filename string) string {
|
||||
idx := strings.LastIndexByte(filename, '.')
|
||||
if idx == -1 {
|
||||
@ -54,23 +73,48 @@ func getExtension(filename string) string {
|
||||
return filename[idx+1:]
|
||||
}
|
||||
|
||||
// LoadConfig loads config with given format from given source.
|
||||
// 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)
|
||||
if len(ext) > 0 {
|
||||
if f, found := configLoaderByExt[ext]; found {
|
||||
return f.Loader(input)
|
||||
func getFormat(filename string) string {
|
||||
return GetFormatByExtension(getExtension(filename))
|
||||
}
|
||||
|
||||
func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
||||
switch v := input.(type) {
|
||||
case cmdarg.Arg:
|
||||
|
||||
formats := make([]string, len(v))
|
||||
hasProtobuf := false
|
||||
for i, file := range v {
|
||||
f := getFormat(file)
|
||||
if f == "" {
|
||||
f = formatName
|
||||
}
|
||||
if f == "protobuf" {
|
||||
hasProtobuf = true
|
||||
}
|
||||
formats[i] = f
|
||||
}
|
||||
|
||||
// only one protobuf config file is allowed
|
||||
if hasProtobuf {
|
||||
if len(v) == 1 {
|
||||
return configLoaderByName["protobuf"].Loader(v)
|
||||
} else {
|
||||
return nil, newError("Only one protobuf config file is allowed").AtWarning()
|
||||
}
|
||||
}
|
||||
|
||||
// to avoid import cycle
|
||||
return ConfigBuilderForFiles(v, formats)
|
||||
|
||||
case io.Reader:
|
||||
if f, found := configLoaderByName[formatName]; found {
|
||||
return f.Loader(v)
|
||||
} else {
|
||||
return nil, newError("Unable to load config in", formatName).AtWarning()
|
||||
}
|
||||
}
|
||||
|
||||
if f, found := configLoaderByName[formatName]; found {
|
||||
return f.Loader(input)
|
||||
}
|
||||
|
||||
return nil, newError("Unable to load config in ", formatName).AtWarning()
|
||||
return nil, newError("Unable to load config").AtWarning()
|
||||
}
|
||||
|
||||
func loadProtobufConfig(data []byte) (*Config, error) {
|
||||
|
@ -25,7 +25,7 @@ func CreateObject(v *Instance, config interface{}) (interface{}, error) {
|
||||
//
|
||||
// xray:api:stable
|
||||
func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
|
||||
config, err := LoadConfig(configFormat, "", bytes.NewReader(configBytes))
|
||||
config, err := LoadConfig(configFormat, bytes.NewReader(configBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
44
infra/conf/serial/builder.go
Normal file
44
infra/conf/serial/builder.go
Normal file
@ -0,0 +1,44 @@
|
||||
package serial
|
||||
|
||||
import (
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/infra/conf"
|
||||
"github.com/xtls/xray-core/main/confloader"
|
||||
"io"
|
||||
)
|
||||
|
||||
func BuildConfig(files []string, formats []string) (*core.Config, error) {
|
||||
|
||||
cf := &conf.Config{}
|
||||
for i, file := range files {
|
||||
newError("Reading config: ", file).AtInfo().WriteToLog()
|
||||
r, err := confloader.LoadConfig(file)
|
||||
if err != nil {
|
||||
return nil, newError("failed to read config: ", file).Base(err)
|
||||
}
|
||||
c, err := ReaderDecoderByFormat[formats[i]](r)
|
||||
if err != nil {
|
||||
return nil, newError("failed to decode config: ", file).Base(err)
|
||||
}
|
||||
if i == 0 {
|
||||
*cf = *c
|
||||
continue
|
||||
}
|
||||
cf.Override(c, file)
|
||||
}
|
||||
return cf.Build()
|
||||
}
|
||||
|
||||
type readerDecoder func(io.Reader) (*conf.Config, error)
|
||||
|
||||
var (
|
||||
ReaderDecoderByFormat = make(map[string]readerDecoder)
|
||||
)
|
||||
|
||||
func init() {
|
||||
ReaderDecoderByFormat["json"] = DecodeJSONConfig
|
||||
ReaderDecoderByFormat["yaml"] = DecodeYAMLConfig
|
||||
ReaderDecoderByFormat["toml"] = DecodeTOMLConfig
|
||||
|
||||
core.ConfigBuilderForFiles = BuildConfig
|
||||
}
|
20
main/run.go
20
main/run.go
@ -11,7 +11,6 @@ import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/xtls/xray-core/common/cmdarg"
|
||||
@ -158,30 +157,25 @@ func getConfigFilePath() cmdarg.Arg {
|
||||
}
|
||||
|
||||
func getConfigFormat() string {
|
||||
switch strings.ToLower(*format) {
|
||||
case "pb", "protobuf":
|
||||
return "protobuf"
|
||||
case "yaml", "yml":
|
||||
return "yaml"
|
||||
case "toml":
|
||||
return "toml"
|
||||
default:
|
||||
return "json"
|
||||
f := core.GetFormatByExtension(*format)
|
||||
if f == "" {
|
||||
f = "json"
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func startXray() (core.Server, error) {
|
||||
configFiles := getConfigFilePath()
|
||||
|
||||
config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
|
||||
//config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
|
||||
|
||||
//config, err := core.LoadConfigs(getConfigFormat(), configFiles)
|
||||
c, err := core.LoadConfig(getConfigFormat(), configFiles)
|
||||
|
||||
if err != nil {
|
||||
return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err)
|
||||
}
|
||||
|
||||
server, err := core.New(config)
|
||||
server, err := core.New(c)
|
||||
if err != nil {
|
||||
return nil, newError("failed to create server").Base(err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user