mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-22 12:49:20 +02:00
Add sub-command "-dump" to "run". (#2854)
* Add MarshalToJson(). * Add cmd arg -dump for printing out merged multiple json configs. --------- Co-authored-by: nobody <nobody@nowhere.mars>
This commit is contained in:
parent
006cf491e5
commit
44bb83033f
|
@ -27,6 +27,11 @@ type generalLogger struct {
|
||||||
done *done.Instance
|
done *done.Instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serverityLogger struct {
|
||||||
|
inner *generalLogger
|
||||||
|
logLevel Severity
|
||||||
|
}
|
||||||
|
|
||||||
// NewLogger returns a generic log handler that can handle all type of messages.
|
// NewLogger returns a generic log handler that can handle all type of messages.
|
||||||
func NewLogger(logWriterCreator WriterCreator) Handler {
|
func NewLogger(logWriterCreator WriterCreator) Handler {
|
||||||
return &generalLogger{
|
return &generalLogger{
|
||||||
|
@ -37,6 +42,32 @@ func NewLogger(logWriterCreator WriterCreator) Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReplaceWithSeverityLogger(serverity Severity) {
|
||||||
|
w := CreateStdoutLogWriter()
|
||||||
|
g := &generalLogger{
|
||||||
|
creator: w,
|
||||||
|
buffer: make(chan Message, 16),
|
||||||
|
access: semaphore.New(1),
|
||||||
|
done: done.New(),
|
||||||
|
}
|
||||||
|
s := &serverityLogger{
|
||||||
|
inner: g,
|
||||||
|
logLevel: serverity,
|
||||||
|
}
|
||||||
|
RegisterHandler(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *serverityLogger) Handle(msg Message) {
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case *GeneralMessage:
|
||||||
|
if msg.Severity <= l.logLevel {
|
||||||
|
l.inner.Handle(msg)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
l.inner.Handle(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (l *generalLogger) run() {
|
func (l *generalLogger) run() {
|
||||||
defer l.access.Signal()
|
defer l.access.Signal()
|
||||||
|
|
||||||
|
@ -67,6 +98,7 @@ func (l *generalLogger) run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *generalLogger) Handle(msg Message) {
|
func (l *generalLogger) Handle(msg Message) {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case l.buffer <- msg:
|
case l.buffer <- msg:
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
package reflect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
cserial "github.com/xtls/xray-core/common/serial"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MarshalToJson(v interface{}) (string, bool) {
|
||||||
|
if itf := marshalInterface(v, true); itf != nil {
|
||||||
|
if b, err := json.MarshalIndent(itf, "", " "); err == nil {
|
||||||
|
return string(b[:]), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalTypedMessage(v *cserial.TypedMessage, ignoreNullValue bool) interface{} {
|
||||||
|
tmsg, err := v.GetInstance()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := marshalInterface(tmsg, ignoreNullValue)
|
||||||
|
if msg, ok := r.(map[string]interface{}); ok {
|
||||||
|
msg["_TypedMessage_"] = v.Type
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalSlice(v reflect.Value, ignoreNullValue bool) interface{} {
|
||||||
|
r := make([]interface{}, 0)
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
rv := v.Index(i)
|
||||||
|
if rv.CanInterface() {
|
||||||
|
value := rv.Interface()
|
||||||
|
r = append(r, marshalInterface(value, ignoreNullValue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalStruct(v reflect.Value, ignoreNullValue bool) interface{} {
|
||||||
|
r := make(map[string]interface{})
|
||||||
|
t := v.Type()
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
rv := v.Field(i)
|
||||||
|
if rv.CanInterface() {
|
||||||
|
ft := t.Field(i)
|
||||||
|
name := ft.Name
|
||||||
|
value := rv.Interface()
|
||||||
|
tv := marshalInterface(value, ignoreNullValue)
|
||||||
|
if tv != nil || !ignoreNullValue {
|
||||||
|
r[name] = tv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalMap(v reflect.Value, ignoreNullValue bool) interface{} {
|
||||||
|
// policy.level is map[uint32] *struct
|
||||||
|
kt := v.Type().Key()
|
||||||
|
vt := reflect.TypeOf((*interface{})(nil))
|
||||||
|
mt := reflect.MapOf(kt, vt)
|
||||||
|
r := reflect.MakeMap(mt)
|
||||||
|
for _, key := range v.MapKeys() {
|
||||||
|
rv := v.MapIndex(key)
|
||||||
|
if rv.CanInterface() {
|
||||||
|
iv := rv.Interface()
|
||||||
|
tv := marshalInterface(iv, ignoreNullValue)
|
||||||
|
if tv != nil || !ignoreNullValue {
|
||||||
|
r.SetMapIndex(key, reflect.ValueOf(&tv))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalIString(v interface{}) (r string, ok bool) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
r = ""
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if iStringFn, ok := v.(interface{ String() string }); ok {
|
||||||
|
return iStringFn.String(), true
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalKnownType(v interface{}, ignoreNullValue bool) (interface{}, bool) {
|
||||||
|
switch ty := v.(type) {
|
||||||
|
case cserial.TypedMessage:
|
||||||
|
return marshalTypedMessage(&ty, ignoreNullValue), true
|
||||||
|
case *cserial.TypedMessage:
|
||||||
|
return marshalTypedMessage(ty, ignoreNullValue), true
|
||||||
|
case map[string]json.RawMessage:
|
||||||
|
return ty, true
|
||||||
|
case []json.RawMessage:
|
||||||
|
return ty, true
|
||||||
|
case *json.RawMessage:
|
||||||
|
return ty, true
|
||||||
|
case json.RawMessage:
|
||||||
|
return ty, true
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var valueKinds = []reflect.Kind{
|
||||||
|
reflect.Bool,
|
||||||
|
reflect.Int,
|
||||||
|
reflect.Int8,
|
||||||
|
reflect.Int16,
|
||||||
|
reflect.Int32,
|
||||||
|
reflect.Int64,
|
||||||
|
reflect.Uint,
|
||||||
|
reflect.Uint8,
|
||||||
|
reflect.Uint16,
|
||||||
|
reflect.Uint32,
|
||||||
|
reflect.Uint64,
|
||||||
|
reflect.Uintptr,
|
||||||
|
reflect.Float32,
|
||||||
|
reflect.Float64,
|
||||||
|
reflect.Complex64,
|
||||||
|
reflect.Complex128,
|
||||||
|
reflect.String,
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValueKind(kind reflect.Kind) bool {
|
||||||
|
return slices.Contains(valueKinds, kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalInterface(v interface{}, ignoreNullValue bool) interface{} {
|
||||||
|
|
||||||
|
if r, ok := marshalKnownType(v, ignoreNullValue); ok {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
if rv.Kind() == reflect.Ptr {
|
||||||
|
rv = rv.Elem()
|
||||||
|
}
|
||||||
|
k := rv.Kind()
|
||||||
|
if k == reflect.Invalid {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if isValueKind(k) {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
switch k {
|
||||||
|
case reflect.Struct:
|
||||||
|
return marshalStruct(rv, ignoreNullValue)
|
||||||
|
case reflect.Slice:
|
||||||
|
return marshalSlice(rv, ignoreNullValue)
|
||||||
|
case reflect.Array:
|
||||||
|
return marshalSlice(rv, ignoreNullValue)
|
||||||
|
case reflect.Map:
|
||||||
|
return marshalMap(rv, ignoreNullValue)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if str, ok := marshalIString(v); ok {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
package reflect_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/xtls/xray-core/common/reflect"
|
||||||
|
cserial "github.com/xtls/xray-core/common/serial"
|
||||||
|
iserial "github.com/xtls/xray-core/infra/conf/serial"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMashalStruct(t *testing.T) {
|
||||||
|
type Foo = struct {
|
||||||
|
N int `json:"n"`
|
||||||
|
Np *int `json:"np"`
|
||||||
|
S string `json:"s"`
|
||||||
|
Arr *[]map[string]map[string]string `json:"arr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
n := 1
|
||||||
|
np := &n
|
||||||
|
arr := make([]map[string]map[string]string, 0)
|
||||||
|
m1 := make(map[string]map[string]string, 0)
|
||||||
|
m2 := make(map[string]string, 0)
|
||||||
|
m2["hello"] = "world"
|
||||||
|
m1["foo"] = m2
|
||||||
|
|
||||||
|
arr = append(arr, m1)
|
||||||
|
|
||||||
|
f1 := Foo{
|
||||||
|
N: n,
|
||||||
|
Np: np,
|
||||||
|
S: "hello",
|
||||||
|
Arr: &arr,
|
||||||
|
}
|
||||||
|
|
||||||
|
s, ok1 := MarshalToJson(f1)
|
||||||
|
sp, ok2 := MarshalToJson(&f1)
|
||||||
|
|
||||||
|
if !ok1 || !ok2 || s != sp {
|
||||||
|
t.Error("marshal failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 := Foo{}
|
||||||
|
if json.Unmarshal([]byte(s), &f2) != nil {
|
||||||
|
t.Error("json unmarshal failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
v := (*f2.Arr)[0]["foo"]["hello"]
|
||||||
|
|
||||||
|
if f1.N != f2.N || *(f1.Np) != *(f2.Np) || f1.S != f2.S || v != "world" {
|
||||||
|
t.Error("f1 not equal to f2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalConfigJson(t *testing.T) {
|
||||||
|
|
||||||
|
buf := bytes.NewBufferString(getConfig())
|
||||||
|
config, err := iserial.DecodeJSONConfig(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("decode JSON config failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
bc, err := config.Build()
|
||||||
|
if err != nil {
|
||||||
|
t.Error("build core config failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
tmsg := cserial.ToTypedMessage(bc)
|
||||||
|
tc, ok := MarshalToJson(tmsg)
|
||||||
|
if !ok {
|
||||||
|
t.Error("marshal config failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Log(tc)
|
||||||
|
|
||||||
|
keywords := []string{
|
||||||
|
"4784f9b8-a879-4fec-9718-ebddefa47750",
|
||||||
|
"bing.com",
|
||||||
|
"DomainStrategy",
|
||||||
|
"InboundTag",
|
||||||
|
"Level",
|
||||||
|
"Stats",
|
||||||
|
"UserDownlink",
|
||||||
|
"UserUplink",
|
||||||
|
"System",
|
||||||
|
"InboundDownlink",
|
||||||
|
"OutboundUplink",
|
||||||
|
}
|
||||||
|
for _, kw := range keywords {
|
||||||
|
if !strings.Contains(tc, kw) {
|
||||||
|
t.Error("marshaled config error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfig() string {
|
||||||
|
return `{
|
||||||
|
"log": {
|
||||||
|
"loglevel": "debug"
|
||||||
|
},
|
||||||
|
"stats": {},
|
||||||
|
"policy": {
|
||||||
|
"levels": {
|
||||||
|
"0": {
|
||||||
|
"statsUserUplink": true,
|
||||||
|
"statsUserDownlink": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"statsInboundUplink": true,
|
||||||
|
"statsInboundDownlink": true,
|
||||||
|
"statsOutboundUplink": true,
|
||||||
|
"statsOutboundDownlink": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"tag": "agentin",
|
||||||
|
"protocol": "http",
|
||||||
|
"port": 8080,
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"settings": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"port": 10085,
|
||||||
|
"protocol": "dokodemo-door",
|
||||||
|
"settings": {
|
||||||
|
"address": "127.0.0.1"
|
||||||
|
},
|
||||||
|
"tag": "api-in"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"api": {
|
||||||
|
"tag": "api",
|
||||||
|
"services": [
|
||||||
|
"HandlerService",
|
||||||
|
"StatsService"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"routing": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"inboundTag": [
|
||||||
|
"api-in"
|
||||||
|
],
|
||||||
|
"outboundTag": "api",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"domainStrategy": "AsIs"
|
||||||
|
},
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "vless",
|
||||||
|
"settings": {
|
||||||
|
"vnext": [
|
||||||
|
{
|
||||||
|
"address": "1.2.3.4",
|
||||||
|
"port": 1234,
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"id": "4784f9b8-a879-4fec-9718-ebddefa47750",
|
||||||
|
"encryption": "none"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tag": "agentout",
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "ws",
|
||||||
|
"security": "none",
|
||||||
|
"wsSettings": {
|
||||||
|
"path": "/?ed=2048",
|
||||||
|
"headers": {
|
||||||
|
"Host": "bing.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
|
@ -24,10 +25,14 @@ type ConfigLoader func(input interface{}) (*Config, error)
|
||||||
// ConfigBuilder is a builder to build core.Config from filenames and formats
|
// ConfigBuilder is a builder to build core.Config from filenames and formats
|
||||||
type ConfigBuilder func(files []string, formats []string) (*Config, error)
|
type ConfigBuilder func(files []string, formats []string) (*Config, error)
|
||||||
|
|
||||||
|
// ConfigMerger merge multiple json configs into on config
|
||||||
|
type ConfigsMerger func(files []string, formats []string) (string, 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
|
ConfigBuilderForFiles ConfigBuilder
|
||||||
|
ConfigMergedFormFiles ConfigsMerger
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegisterConfigLoader add a new ConfigLoader.
|
// RegisterConfigLoader add a new ConfigLoader.
|
||||||
|
@ -49,6 +54,20 @@ func RegisterConfigLoader(format *ConfigFormat) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMergedConfig(args cmdarg.Arg) (string, error) {
|
||||||
|
files := make([]string, 0)
|
||||||
|
formats := make([]string, 0)
|
||||||
|
supported := []string{"json", "yaml", "toml"}
|
||||||
|
for _, file := range args {
|
||||||
|
format := getFormat(file)
|
||||||
|
if slices.Contains(supported, format) {
|
||||||
|
files = append(files, file)
|
||||||
|
formats = append(formats, format)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ConfigMergedFormFiles(files, formats)
|
||||||
|
}
|
||||||
|
|
||||||
func GetFormatByExtension(ext string) string {
|
func GetFormatByExtension(ext string) string {
|
||||||
switch strings.ToLower(ext) {
|
switch strings.ToLower(ext) {
|
||||||
case "pb", "protobuf":
|
case "pb", "protobuf":
|
||||||
|
|
|
@ -3,12 +3,25 @@ package serial
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
creflect "github.com/xtls/xray-core/common/reflect"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/infra/conf"
|
"github.com/xtls/xray-core/infra/conf"
|
||||||
"github.com/xtls/xray-core/main/confloader"
|
"github.com/xtls/xray-core/main/confloader"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BuildConfig(files []string, formats []string) (*core.Config, error) {
|
func MergeConfigFromFiles(files []string, formats []string) (string, error) {
|
||||||
|
c, err := mergeConfigs(files, formats)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if j, ok := creflect.MarshalToJson(c); ok {
|
||||||
|
return j, nil
|
||||||
|
}
|
||||||
|
return "", newError("marshal to json failed.").AtError()
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeConfigs(files []string, formats []string) (*conf.Config, error) {
|
||||||
cf := &conf.Config{}
|
cf := &conf.Config{}
|
||||||
for i, file := range files {
|
for i, file := range files {
|
||||||
newError("Reading config: ", file).AtInfo().WriteToLog()
|
newError("Reading config: ", file).AtInfo().WriteToLog()
|
||||||
|
@ -26,7 +39,15 @@ func BuildConfig(files []string, formats []string) (*core.Config, error) {
|
||||||
}
|
}
|
||||||
cf.Override(c, file)
|
cf.Override(c, file)
|
||||||
}
|
}
|
||||||
return cf.Build()
|
return cf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildConfig(files []string, formats []string) (*core.Config, error) {
|
||||||
|
config, err := mergeConfigs(files, formats)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return config.Build()
|
||||||
}
|
}
|
||||||
|
|
||||||
type readerDecoder func(io.Reader) (*conf.Config, error)
|
type readerDecoder func(io.Reader) (*conf.Config, error)
|
||||||
|
@ -39,4 +60,5 @@ func init() {
|
||||||
ReaderDecoderByFormat["toml"] = DecodeTOMLConfig
|
ReaderDecoderByFormat["toml"] = DecodeTOMLConfig
|
||||||
|
|
||||||
core.ConfigBuilderForFiles = BuildConfig
|
core.ConfigBuilderForFiles = BuildConfig
|
||||||
|
core.ConfigMergedFormFiles = MergeConfigFromFiles
|
||||||
}
|
}
|
||||||
|
|
49
main/run.go
49
main/run.go
|
@ -12,8 +12,10 @@ import (
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/cmdarg"
|
"github.com/xtls/xray-core/common/cmdarg"
|
||||||
|
clog "github.com/xtls/xray-core/common/log"
|
||||||
"github.com/xtls/xray-core/common/platform"
|
"github.com/xtls/xray-core/common/platform"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/main/commands/base"
|
"github.com/xtls/xray-core/main/commands/base"
|
||||||
|
@ -34,7 +36,9 @@ The -format=json flag sets the format of config files.
|
||||||
Default "auto".
|
Default "auto".
|
||||||
|
|
||||||
The -test flag tells Xray to test config files only,
|
The -test flag tells Xray to test config files only,
|
||||||
without launching the server
|
without launching the server.
|
||||||
|
|
||||||
|
The -dump flag tells Xray to print the merged config.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +49,7 @@ func init() {
|
||||||
var (
|
var (
|
||||||
configFiles cmdarg.Arg // "Config file for Xray.", the option is customed type, parse in main
|
configFiles cmdarg.Arg // "Config file for Xray.", the option is customed type, parse in main
|
||||||
configDir string
|
configDir string
|
||||||
|
dump = cmdRun.Flag.Bool("dump", false, "Dump merged config only, without launching Xray server.")
|
||||||
test = cmdRun.Flag.Bool("test", false, "Test config file only, without launching Xray server.")
|
test = cmdRun.Flag.Bool("test", false, "Test config file only, without launching Xray server.")
|
||||||
format = cmdRun.Flag.String("format", "auto", "Format of input file.")
|
format = cmdRun.Flag.String("format", "auto", "Format of input file.")
|
||||||
|
|
||||||
|
@ -61,6 +66,12 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func executeRun(cmd *base.Command, args []string) {
|
func executeRun(cmd *base.Command, args []string) {
|
||||||
|
if *dump {
|
||||||
|
clog.ReplaceWithSeverityLogger(clog.Severity_Warning)
|
||||||
|
errCode := dumpConfig()
|
||||||
|
os.Exit(errCode)
|
||||||
|
}
|
||||||
|
|
||||||
printVersion()
|
printVersion()
|
||||||
server, err := startXray()
|
server, err := startXray()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -97,6 +108,18 @@ func executeRun(cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dumpConfig() int {
|
||||||
|
files := getConfigFilePath(false)
|
||||||
|
if config, err := core.GetMergedConfig(files); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
return 23
|
||||||
|
} else {
|
||||||
|
fmt.Print(config)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func fileExists(file string) bool {
|
func fileExists(file string) bool {
|
||||||
info, err := os.Stat(file)
|
info, err := os.Stat(file)
|
||||||
return err == nil && !info.IsDir()
|
return err == nil && !info.IsDir()
|
||||||
|
@ -139,12 +162,16 @@ func readConfDir(dirPath string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfigFilePath() cmdarg.Arg {
|
func getConfigFilePath(verbose bool) cmdarg.Arg {
|
||||||
if dirExists(configDir) {
|
if dirExists(configDir) {
|
||||||
log.Println("Using confdir from arg:", configDir)
|
if verbose {
|
||||||
|
log.Println("Using confdir from arg:", configDir)
|
||||||
|
}
|
||||||
readConfDir(configDir)
|
readConfDir(configDir)
|
||||||
} else if envConfDir := platform.GetConfDirPath(); dirExists(envConfDir) {
|
} else if envConfDir := platform.GetConfDirPath(); dirExists(envConfDir) {
|
||||||
log.Println("Using confdir from env:", envConfDir)
|
if verbose {
|
||||||
|
log.Println("Using confdir from env:", envConfDir)
|
||||||
|
}
|
||||||
readConfDir(envConfDir)
|
readConfDir(envConfDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,17 +182,23 @@ func getConfigFilePath() cmdarg.Arg {
|
||||||
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) {
|
||||||
log.Println("Using default config: ", configFile)
|
if verbose {
|
||||||
|
log.Println("Using default config: ", configFile)
|
||||||
|
}
|
||||||
return cmdarg.Arg{configFile}
|
return cmdarg.Arg{configFile}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if configFile := platform.GetConfigurationPath(); fileExists(configFile) {
|
if configFile := platform.GetConfigurationPath(); fileExists(configFile) {
|
||||||
log.Println("Using config from env: ", configFile)
|
if verbose {
|
||||||
|
log.Println("Using config from env: ", configFile)
|
||||||
|
}
|
||||||
return cmdarg.Arg{configFile}
|
return cmdarg.Arg{configFile}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Using config from STDIN")
|
if verbose {
|
||||||
|
log.Println("Using config from STDIN")
|
||||||
|
}
|
||||||
return cmdarg.Arg{"stdin:"}
|
return cmdarg.Arg{"stdin:"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +211,7 @@ func getConfigFormat() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func startXray() (core.Server, error) {
|
func startXray() (core.Server, error) {
|
||||||
configFiles := getConfigFilePath()
|
configFiles := getConfigFilePath(true)
|
||||||
|
|
||||||
// config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
|
// config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue