-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
160 lines (137 loc) · 3.64 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package core
import (
"io"
"strings"
"github.com/golang/protobuf/proto"
"github.com/jaskon139/xray-core/common"
"github.com/jaskon139/xray-core/common/buf"
"github.com/jaskon139/xray-core/common/cmdarg"
"github.com/jaskon139/xray-core/main/confloader"
)
// ConfigFormat is a configurable format of Xray config file.
type ConfigFormat struct {
Name string
Extension []string
Loader ConfigLoader
}
// 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)
ConfigBuilderForFiles ConfigBuilder
)
// RegisterConfigLoader add a new ConfigLoader.
func RegisterConfigLoader(format *ConfigFormat) error {
name := strings.ToLower(format.Name)
if _, found := configLoaderByName[name]; found {
return newError(format.Name, " already registered.")
}
configLoaderByName[name] = format
for _, ext := range format.Extension {
lext := strings.ToLower(ext)
if f, found := configLoaderByExt[lext]; found {
return newError(ext, " already registered to ", f.Name)
}
configLoaderByExt[lext] = format
}
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 {
return ""
}
return filename[idx+1:]
}
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 {
var f string
if formatName == "auto" {
if file != "stdin:" {
f = getFormat(file)
} else {
f = "json"
}
} else {
f = formatName
}
if f == "" {
return nil, newError("Failed to get format of ", file).AtWarning()
}
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()
}
}
return nil, newError("Unable to load config").AtWarning()
}
func loadProtobufConfig(data []byte) (*Config, error) {
config := new(Config)
if err := proto.Unmarshal(data, config); err != nil {
return nil, err
}
return config, nil
}
func init() {
common.Must(RegisterConfigLoader(&ConfigFormat{
Name: "Protobuf",
Extension: []string{"pb"},
Loader: func(input interface{}) (*Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
r, err := confloader.LoadConfig(v[0])
common.Must(err)
data, err := buf.ReadAllToBytes(r)
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")
}
},
}))
}