convert.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package jsonv4
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "os"
  6. "strings"
  7. "github.com/pelletier/go-toml"
  8. "google.golang.org/protobuf/proto"
  9. "gopkg.in/yaml.v3"
  10. core "github.com/v2fly/v2ray-core/v5"
  11. "github.com/v2fly/v2ray-core/v5/infra/conf/jsonpb"
  12. "github.com/v2fly/v2ray-core/v5/infra/conf/merge"
  13. "github.com/v2fly/v2ray-core/v5/infra/conf/v2jsonpb"
  14. "github.com/v2fly/v2ray-core/v5/main/commands/base"
  15. "github.com/v2fly/v2ray-core/v5/main/commands/helpers"
  16. )
  17. var cmdConvert = &base.Command{
  18. CustomFlags: true,
  19. UsageLine: "{{.Exec}} convert [c1.json] [<url>.json] [dir1] ...",
  20. Short: "convert config files",
  21. Long: `
  22. Convert config files between different formats. Files are merged
  23. before convert.
  24. Arguments:
  25. -i, -input <format>
  26. The input format.
  27. Available values: "auto", "json", "toml", "yaml"
  28. Default: "auto"
  29. -o, -output <format>
  30. The output format
  31. Available values: "json", "toml", "yaml", "protobuf" / "pb"
  32. Default: "json"
  33. -r
  34. Load folders recursively.
  35. Examples:
  36. {{.Exec}} {{.LongName}} -output=protobuf "path/to/dir" (1)
  37. {{.Exec}} {{.LongName}} -o=yaml config.toml (2)
  38. {{.Exec}} {{.LongName}} c1.json c2.json (3)
  39. {{.Exec}} {{.LongName}} -output=yaml c1.yaml <url>.yaml (4)
  40. (1) Merge all supported files in dir and convert to protobuf
  41. (2) Convert toml to yaml
  42. (3) Merge json files
  43. (4) Merge yaml files
  44. Use "{{.Exec}} help config-merge" for more information about merge.
  45. `,
  46. }
  47. func init() {
  48. cmdConvert.Run = executeConvert // break init loop
  49. }
  50. var (
  51. inputFormat string
  52. outputFormat string
  53. confDirRecursively bool
  54. )
  55. func setConfArgs(cmd *base.Command) {
  56. cmd.Flag.StringVar(&inputFormat, "input", core.FormatAuto, "")
  57. cmd.Flag.StringVar(&inputFormat, "i", core.FormatAuto, "")
  58. cmd.Flag.StringVar(&outputFormat, "output", "json", "")
  59. cmd.Flag.StringVar(&outputFormat, "o", "json", "")
  60. cmd.Flag.BoolVar(&confDirRecursively, "r", false, "")
  61. }
  62. func executeConvert(cmd *base.Command, args []string) {
  63. setConfArgs(cmd)
  64. cmd.Flag.Parse(args)
  65. inputFormat = strings.ToLower(inputFormat)
  66. outputFormat = strings.ToLower(outputFormat)
  67. inputFormatMerge := inputFormat
  68. if inputFormat == "jsonv5" {
  69. inputFormatMerge = "json"
  70. }
  71. m, err := helpers.LoadConfigToMap(cmd.Flag.Args(), inputFormatMerge, confDirRecursively)
  72. if err != nil {
  73. base.Fatalf("failed to merge: %s", err)
  74. }
  75. err = merge.ApplyRules(m)
  76. if err != nil {
  77. base.Fatalf("failed to apply merge rules: %s", err)
  78. }
  79. var out []byte
  80. switch outputFormat {
  81. case core.FormatJSON:
  82. out, err = json.Marshal(m)
  83. if err != nil {
  84. base.Fatalf("failed to convert to json: %s", err)
  85. }
  86. case core.FormatTOML:
  87. out, err = toml.Marshal(m)
  88. if err != nil {
  89. base.Fatalf("failed to convert to toml: %s", err)
  90. }
  91. case core.FormatYAML:
  92. out, err = yaml.Marshal(m)
  93. if err != nil {
  94. base.Fatalf("failed to convert to yaml: %s", err)
  95. }
  96. case core.FormatProtobuf, core.FormatProtobufShort:
  97. data, err := json.Marshal(m)
  98. if err != nil {
  99. base.Fatalf("failed to marshal json: %s", err)
  100. }
  101. r := bytes.NewReader(data)
  102. pbConfig, err := core.LoadConfig(inputFormat, r)
  103. if err != nil {
  104. base.Fatalf(err.Error())
  105. }
  106. out, err = proto.Marshal(pbConfig)
  107. if err != nil {
  108. base.Fatalf("failed to convert to protobuf: %s", err)
  109. }
  110. case jsonpb.FormatProtobufJSONPB:
  111. data, err := json.Marshal(m)
  112. if err != nil {
  113. base.Fatalf("failed to marshal json: %s", err)
  114. }
  115. r := bytes.NewReader(data)
  116. pbConfig, err := core.LoadConfig(inputFormat, r)
  117. if err != nil {
  118. base.Fatalf(err.Error())
  119. }
  120. w := bytes.NewBuffer(nil)
  121. err = jsonpb.DumpJSONPb(pbConfig, w)
  122. if err != nil {
  123. base.Fatalf(err.Error())
  124. }
  125. out = w.Bytes()
  126. case v2jsonpb.FormatProtobufV2JSONPB:
  127. data, err := json.Marshal(m)
  128. if err != nil {
  129. base.Fatalf("failed to marshal json: %s", err)
  130. }
  131. r := bytes.NewReader(data)
  132. pbConfig, err := core.LoadConfig(inputFormat, r)
  133. if err != nil {
  134. base.Fatalf(err.Error())
  135. }
  136. out, err = v2jsonpb.DumpV2JsonPb(pbConfig)
  137. if err != nil {
  138. base.Fatalf(err.Error())
  139. }
  140. default:
  141. base.Errorf("invalid output format: %s", outputFormat)
  142. base.Errorf("Run '%s help %s' for details.", base.CommandEnv.Exec, cmd.LongName())
  143. base.Exit()
  144. }
  145. if _, err := os.Stdout.Write(out); err != nil {
  146. base.Fatalf("failed to write stdout: %s", err)
  147. }
  148. }