convert.go 3.4 KB

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