loader.go 3.5 KB

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