github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/infra/conf/serial/loader.go (about)

     1  package serial
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io"
     7  
     8  	core "github.com/v2fly/v2ray-core/v5"
     9  	"github.com/v2fly/v2ray-core/v5/common/errors"
    10  	json_reader "github.com/v2fly/v2ray-core/v5/infra/conf/json"
    11  	v4 "github.com/v2fly/v2ray-core/v5/infra/conf/v4"
    12  )
    13  
    14  type offset struct {
    15  	line int
    16  	char int
    17  }
    18  
    19  func findOffset(b []byte, o int) *offset {
    20  	if o >= len(b) || o < 0 {
    21  		return nil
    22  	}
    23  
    24  	line := 1
    25  	char := 0
    26  	for i, x := range b {
    27  		if i == o {
    28  			break
    29  		}
    30  		if x == '\n' {
    31  			line++
    32  			char = 0
    33  		} else {
    34  			char++
    35  		}
    36  	}
    37  
    38  	return &offset{line: line, char: char}
    39  }
    40  
    41  // DecodeJSONConfig reads from reader and decode the config into *conf.Config
    42  // syntax error could be detected.
    43  func DecodeJSONConfig(reader io.Reader) (*v4.Config, error) {
    44  	jsonConfig := &v4.Config{}
    45  	err := DecodeJSON(reader, jsonConfig)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	return jsonConfig, nil
    50  }
    51  
    52  // DecodeJSON reads from reader and decode into target
    53  // syntax error could be detected.
    54  func DecodeJSON(reader io.Reader, target interface{}) error {
    55  	jsonContent := bytes.NewBuffer(make([]byte, 0, 10240))
    56  	jsonReader := io.TeeReader(&json_reader.Reader{
    57  		Reader: reader,
    58  	}, jsonContent)
    59  	decoder := json.NewDecoder(jsonReader)
    60  
    61  	if err := decoder.Decode(target); err != nil {
    62  		var pos *offset
    63  		cause := errors.Cause(err)
    64  		switch tErr := cause.(type) {
    65  		case *json.SyntaxError:
    66  			pos = findOffset(jsonContent.Bytes(), int(tErr.Offset))
    67  		case *json.UnmarshalTypeError:
    68  			pos = findOffset(jsonContent.Bytes(), int(tErr.Offset))
    69  		}
    70  		if pos != nil {
    71  			return newError("failed to read config file at line ", pos.line, " char ", pos.char).Base(err)
    72  		}
    73  		return newError("failed to read config file").Base(err)
    74  	}
    75  
    76  	return nil
    77  }
    78  
    79  func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
    80  	jsonConfig, err := DecodeJSONConfig(reader)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	pbConfig, err := jsonConfig.Build()
    86  	if err != nil {
    87  		return nil, newError("failed to parse json config").Base(err)
    88  	}
    89  
    90  	return pbConfig, nil
    91  }