convert.go 4.5 KB

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