2019-02-10 13:04:11 -05:00
|
|
|
package serial
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"v2ray.com/core"
|
|
|
|
"v2ray.com/core/common/errors"
|
|
|
|
"v2ray.com/core/infra/conf"
|
|
|
|
json_reader "v2ray.com/core/infra/conf/json"
|
|
|
|
)
|
|
|
|
|
|
|
|
type offset struct {
|
|
|
|
line int
|
|
|
|
char int
|
|
|
|
}
|
|
|
|
|
|
|
|
func findOffset(b []byte, o int) *offset {
|
|
|
|
if o >= len(b) || o < 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
line := 1
|
|
|
|
char := 0
|
|
|
|
for i, x := range b {
|
|
|
|
if i == o {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if x == '\n' {
|
|
|
|
line++
|
|
|
|
char = 0
|
|
|
|
} else {
|
|
|
|
char++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &offset{line: line, char: char}
|
|
|
|
}
|
|
|
|
|
2020-01-01 12:23:56 -05:00
|
|
|
func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
|
2019-02-10 13:04:11 -05:00
|
|
|
jsonConfig := &conf.Config{}
|
|
|
|
|
|
|
|
jsonContent := bytes.NewBuffer(make([]byte, 0, 10240))
|
|
|
|
jsonReader := io.TeeReader(&json_reader.Reader{
|
|
|
|
Reader: reader,
|
|
|
|
}, jsonContent)
|
|
|
|
decoder := json.NewDecoder(jsonReader)
|
|
|
|
|
|
|
|
if err := decoder.Decode(jsonConfig); err != nil {
|
|
|
|
var pos *offset
|
|
|
|
cause := errors.Cause(err)
|
|
|
|
switch tErr := cause.(type) {
|
|
|
|
case *json.SyntaxError:
|
|
|
|
pos = findOffset(jsonContent.Bytes(), int(tErr.Offset))
|
|
|
|
case *json.UnmarshalTypeError:
|
|
|
|
pos = findOffset(jsonContent.Bytes(), int(tErr.Offset))
|
|
|
|
}
|
|
|
|
if pos != nil {
|
|
|
|
return nil, newError("failed to read config file at line ", pos.line, " char ", pos.char).Base(err)
|
|
|
|
}
|
|
|
|
return nil, newError("failed to read config file").Base(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pbConfig, err := jsonConfig.Build()
|
|
|
|
if err != nil {
|
|
|
|
return nil, newError("failed to parse json config").Base(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return pbConfig, nil
|
|
|
|
}
|