github.com/xmplusdev/xray-core@v1.8.10/infra/conf/serial/loader.go (about) 1 package serial 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io" 7 8 "github.com/ghodss/yaml" 9 "github.com/pelletier/go-toml" 10 "github.com/xmplusdev/xray-core/common/errors" 11 "github.com/xmplusdev/xray-core/core" 12 "github.com/xmplusdev/xray-core/infra/conf" 13 json_reader "github.com/xmplusdev/xray-core/infra/conf/json" 14 ) 15 16 type offset struct { 17 line int 18 char int 19 } 20 21 func findOffset(b []byte, o int) *offset { 22 if o >= len(b) || o < 0 { 23 return nil 24 } 25 26 line := 1 27 char := 0 28 for i, x := range b { 29 if i == o { 30 break 31 } 32 if x == '\n' { 33 line++ 34 char = 0 35 } else { 36 char++ 37 } 38 } 39 40 return &offset{line: line, char: char} 41 } 42 43 // DecodeJSONConfig reads from reader and decode the config into *conf.Config 44 // syntax error could be detected. 45 func DecodeJSONConfig(reader io.Reader) (*conf.Config, error) { 46 jsonConfig := &conf.Config{} 47 48 jsonContent := bytes.NewBuffer(make([]byte, 0, 10240)) 49 jsonReader := io.TeeReader(&json_reader.Reader{ 50 Reader: reader, 51 }, jsonContent) 52 decoder := json.NewDecoder(jsonReader) 53 54 if err := decoder.Decode(jsonConfig); err != nil { 55 var pos *offset 56 cause := errors.Cause(err) 57 switch tErr := cause.(type) { 58 case *json.SyntaxError: 59 pos = findOffset(jsonContent.Bytes(), int(tErr.Offset)) 60 case *json.UnmarshalTypeError: 61 pos = findOffset(jsonContent.Bytes(), int(tErr.Offset)) 62 } 63 if pos != nil { 64 return nil, newError("failed to read config file at line ", pos.line, " char ", pos.char).Base(err) 65 } 66 return nil, newError("failed to read config file").Base(err) 67 } 68 69 return jsonConfig, nil 70 } 71 72 func LoadJSONConfig(reader io.Reader) (*core.Config, error) { 73 jsonConfig, err := DecodeJSONConfig(reader) 74 if err != nil { 75 return nil, err 76 } 77 78 pbConfig, err := jsonConfig.Build() 79 if err != nil { 80 return nil, newError("failed to parse json config").Base(err) 81 } 82 83 return pbConfig, nil 84 } 85 86 // DecodeTOMLConfig reads from reader and decode the config into *conf.Config 87 // using github.com/pelletier/go-toml and map to convert toml to json. 88 func DecodeTOMLConfig(reader io.Reader) (*conf.Config, error) { 89 tomlFile, err := io.ReadAll(reader) 90 if err != nil { 91 return nil, newError("failed to read config file").Base(err) 92 } 93 94 configMap := make(map[string]interface{}) 95 if err := toml.Unmarshal(tomlFile, &configMap); err != nil { 96 return nil, newError("failed to convert toml to map").Base(err) 97 } 98 99 jsonFile, err := json.Marshal(&configMap) 100 if err != nil { 101 return nil, newError("failed to convert map to json").Base(err) 102 } 103 104 return DecodeJSONConfig(bytes.NewReader(jsonFile)) 105 } 106 107 func LoadTOMLConfig(reader io.Reader) (*core.Config, error) { 108 tomlConfig, err := DecodeTOMLConfig(reader) 109 if err != nil { 110 return nil, err 111 } 112 113 pbConfig, err := tomlConfig.Build() 114 if err != nil { 115 return nil, newError("failed to parse toml config").Base(err) 116 } 117 118 return pbConfig, nil 119 } 120 121 // DecodeYAMLConfig reads from reader and decode the config into *conf.Config 122 // using github.com/ghodss/yaml to convert yaml to json. 123 func DecodeYAMLConfig(reader io.Reader) (*conf.Config, error) { 124 yamlFile, err := io.ReadAll(reader) 125 if err != nil { 126 return nil, newError("failed to read config file").Base(err) 127 } 128 129 jsonFile, err := yaml.YAMLToJSON(yamlFile) 130 if err != nil { 131 return nil, newError("failed to convert yaml to json").Base(err) 132 } 133 134 return DecodeJSONConfig(bytes.NewReader(jsonFile)) 135 } 136 137 func LoadYAMLConfig(reader io.Reader) (*core.Config, error) { 138 yamlConfig, err := DecodeYAMLConfig(reader) 139 if err != nil { 140 return nil, err 141 } 142 143 pbConfig, err := yamlConfig.Build() 144 if err != nil { 145 return nil, newError("failed to parse yaml config").Base(err) 146 } 147 148 return pbConfig, nil 149 }