mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-23 07:23:01 +00: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.
|
// ConfigLoader is a utility to load Xray config from external source.
|
||||||
type ConfigLoader func(input interface{}) (*Config, error)
|
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 (
|
var (
|
||||||
configLoaderByName = make(map[string]*ConfigFormat)
|
configLoaderByName = make(map[string]*ConfigFormat)
|
||||||
configLoaderByExt = make(map[string]*ConfigFormat)
|
configLoaderByExt = make(map[string]*ConfigFormat)
|
||||||
|
ConfigBuilderForFiles ConfigBuilder
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegisterConfigLoader add a new ConfigLoader.
|
// RegisterConfigLoader add a new ConfigLoader.
|
||||||
@ -46,6 +50,21 @@ func RegisterConfigLoader(format *ConfigFormat) error {
|
|||||||
return nil
|
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 {
|
func getExtension(filename string) string {
|
||||||
idx := strings.LastIndexByte(filename, '.')
|
idx := strings.LastIndexByte(filename, '.')
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
@ -54,23 +73,48 @@ func getExtension(filename string) string {
|
|||||||
return filename[idx+1:]
|
return filename[idx+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig loads config with given format from given source.
|
func getFormat(filename string) string {
|
||||||
// input accepts 2 different types:
|
return GetFormatByExtension(getExtension(filename))
|
||||||
// * []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) {
|
func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
||||||
ext := getExtension(filename)
|
switch v := input.(type) {
|
||||||
if len(ext) > 0 {
|
case cmdarg.Arg:
|
||||||
if f, found := configLoaderByExt[ext]; found {
|
|
||||||
return f.Loader(input)
|
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 {
|
if f, found := configLoaderByName[formatName]; found {
|
||||||
return f.Loader(input)
|
return f.Loader(v)
|
||||||
|
} else {
|
||||||
|
return nil, newError("Unable to load config in", formatName).AtWarning()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, newError("Unable to load config in ", formatName).AtWarning()
|
return nil, newError("Unable to load config").AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadProtobufConfig(data []byte) (*Config, error) {
|
func loadProtobufConfig(data []byte) (*Config, error) {
|
||||||
|
@ -25,7 +25,7 @@ func CreateObject(v *Instance, config interface{}) (interface{}, error) {
|
|||||||
//
|
//
|
||||||
// xray:api:stable
|
// xray:api:stable
|
||||||
func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/cmdarg"
|
"github.com/xtls/xray-core/common/cmdarg"
|
||||||
@ -158,30 +157,25 @@ func getConfigFilePath() cmdarg.Arg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getConfigFormat() string {
|
func getConfigFormat() string {
|
||||||
switch strings.ToLower(*format) {
|
f := core.GetFormatByExtension(*format)
|
||||||
case "pb", "protobuf":
|
if f == "" {
|
||||||
return "protobuf"
|
f = "json"
|
||||||
case "yaml", "yml":
|
|
||||||
return "yaml"
|
|
||||||
case "toml":
|
|
||||||
return "toml"
|
|
||||||
default:
|
|
||||||
return "json"
|
|
||||||
}
|
}
|
||||||
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func startXray() (core.Server, error) {
|
func startXray() (core.Server, error) {
|
||||||
configFiles := getConfigFilePath()
|
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 {
|
if err != nil {
|
||||||
return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err)
|
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 {
|
if err != nil {
|
||||||
return nil, newError("failed to create server").Base(err)
|
return nil, newError("failed to create server").Base(err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user