github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/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/xtls/xray-core/common/errors"
    11  	"github.com/xtls/xray-core/core"
    12  	"github.com/xtls/xray-core/infra/conf"
    13  	json_reader "github.com/xtls/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  }