|
|
@@ -2,33 +2,54 @@ package all
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
+ "encoding/json"
|
|
|
+ "google.golang.org/protobuf/proto"
|
|
|
"os"
|
|
|
+ "strings"
|
|
|
|
|
|
"github.com/v2fly/v2ray-core/v4/commands/base"
|
|
|
- "github.com/v2fly/v2ray-core/v4/infra/conf/merge"
|
|
|
"github.com/v2fly/v2ray-core/v4/infra/conf/serial"
|
|
|
- "google.golang.org/protobuf/proto"
|
|
|
+ "gopkg.in/yaml.v2"
|
|
|
)
|
|
|
|
|
|
var cmdConvert = &base.Command{
|
|
|
- UsageLine: "{{.Exec}} convert [-r] [c1.json] [<url>.json] [dir1] ...",
|
|
|
- Short: "Convert multiple json config to protobuf",
|
|
|
+ CustomFlags: true,
|
|
|
+ UsageLine: "{{.Exec}} convert [c1.json] [<url>.json] [dir1] ...",
|
|
|
+ Short: "Convert config files",
|
|
|
Long: `
|
|
|
-Convert JSON config to protobuf.
|
|
|
-
|
|
|
-If multiple JSON files or folders specified, it merges them first, then convert.
|
|
|
+Convert config files between different formats. Files are merged
|
|
|
+before convert if multiple assigned.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
+ -i, -input
|
|
|
+ Specify the input format.
|
|
|
+ Available values: "json", "yaml"
|
|
|
+ Default: "json"
|
|
|
+
|
|
|
+ -o, -output
|
|
|
+ Specify the output format
|
|
|
+ Available values: "json", "yaml", "protobuf" / "pb"
|
|
|
+ Default: "json"
|
|
|
+
|
|
|
-r
|
|
|
Load confdir recursively.
|
|
|
|
|
|
Examples:
|
|
|
|
|
|
- {{.Exec}} {{.LongName}} config.json
|
|
|
- {{.Exec}} {{.LongName}} c1.json c2.json
|
|
|
- {{.Exec}} {{.LongName}} c1.json https://url.to/c2.json
|
|
|
- {{.Exec}} {{.LongName}} "path/to/json_dir"
|
|
|
+ {{.Exec}} {{.LongName}} -output=protobuf config.json (1)
|
|
|
+ {{.Exec}} {{.LongName}} -output=yaml config.json (2)
|
|
|
+ {{.Exec}} {{.LongName}} -input=yaml config.yaml (3)
|
|
|
+ {{.Exec}} {{.LongName}} "path/to/dir" (4)
|
|
|
+ {{.Exec}} {{.LongName}} -i yaml -o protobuf c1.yaml <url>.yaml (5)
|
|
|
+
|
|
|
+(1) Convert json to protobuf
|
|
|
+(2) Convert json to yaml
|
|
|
+(3) Convert yaml to json
|
|
|
+(4) Merge json files in dir
|
|
|
+(5) Merge yaml files and convert to protobuf
|
|
|
+
|
|
|
+Use "{{.Exec}} help config-merge" for more information about merge.
|
|
|
`,
|
|
|
}
|
|
|
|
|
|
@@ -36,36 +57,76 @@ func init() {
|
|
|
cmdConvert.Run = executeConvert // break init loop
|
|
|
}
|
|
|
|
|
|
-var convertReadDirRecursively = cmdConvert.Flag.Bool("r", false, "")
|
|
|
+var (
|
|
|
+ inputFormat string
|
|
|
+ outputFormat string
|
|
|
+ confDirRecursively bool
|
|
|
+)
|
|
|
+var formatExtensions = map[string][]string{
|
|
|
+ "json": {".json", ".jsonc"},
|
|
|
+ "yaml": {".yaml", ".yml"},
|
|
|
+}
|
|
|
|
|
|
+func setConfArgs(cmd *base.Command) {
|
|
|
+ cmd.Flag.StringVar(&inputFormat, "input", "json", "")
|
|
|
+ cmd.Flag.StringVar(&inputFormat, "i", "json", "")
|
|
|
+ cmd.Flag.StringVar(&outputFormat, "output", "json", "")
|
|
|
+ cmd.Flag.StringVar(&outputFormat, "o", "json", "")
|
|
|
+ cmd.Flag.BoolVar(&confDirRecursively, "r", true, "")
|
|
|
+}
|
|
|
func executeConvert(cmd *base.Command, args []string) {
|
|
|
+ setConfArgs(cmd)
|
|
|
+ cmd.Flag.Parse(args)
|
|
|
unnamed := cmd.Flag.Args()
|
|
|
- files := resolveFolderToFiles(unnamed, *convertReadDirRecursively)
|
|
|
+ inputFormat = strings.ToLower(inputFormat)
|
|
|
+ outputFormat = strings.ToLower(outputFormat)
|
|
|
+
|
|
|
+ files := resolveFolderToFiles(unnamed, formatExtensions[inputFormat], confDirRecursively)
|
|
|
if len(files) == 0 {
|
|
|
base.Fatalf("empty config list")
|
|
|
}
|
|
|
+ m := mergeConvertToMap(files, inputFormat)
|
|
|
|
|
|
- data, err := merge.FilesToJSON(files)
|
|
|
- if err != nil {
|
|
|
- base.Fatalf("failed to load json: %s", err)
|
|
|
- }
|
|
|
- r := bytes.NewReader(data)
|
|
|
- cf, err := serial.DecodeJSONConfig(r)
|
|
|
- if err != nil {
|
|
|
- base.Fatalf("failed to decode json: %s", err)
|
|
|
- }
|
|
|
-
|
|
|
- pbConfig, err := cf.Build()
|
|
|
- if err != nil {
|
|
|
- base.Fatalf(err.Error())
|
|
|
- }
|
|
|
-
|
|
|
- bytesConfig, err := proto.Marshal(pbConfig)
|
|
|
- if err != nil {
|
|
|
- base.Fatalf("failed to marshal proto config: %s", err)
|
|
|
+ var (
|
|
|
+ out []byte
|
|
|
+ err error
|
|
|
+ )
|
|
|
+ switch outputFormat {
|
|
|
+ case "json":
|
|
|
+ out, err = json.Marshal(m)
|
|
|
+ if err != nil {
|
|
|
+ base.Fatalf("failed to marshal json: %s", err)
|
|
|
+ }
|
|
|
+ case "yaml":
|
|
|
+ out, err = yaml.Marshal(m)
|
|
|
+ if err != nil {
|
|
|
+ base.Fatalf("failed to marshal json: %s", err)
|
|
|
+ }
|
|
|
+ case "pb", "protobuf":
|
|
|
+ data, err := json.Marshal(m)
|
|
|
+ if err != nil {
|
|
|
+ base.Fatalf("failed to marshal json: %s", err)
|
|
|
+ }
|
|
|
+ r := bytes.NewReader(data)
|
|
|
+ cf, err := serial.DecodeJSONConfig(r)
|
|
|
+ if err != nil {
|
|
|
+ base.Fatalf("failed to decode json: %s", err)
|
|
|
+ }
|
|
|
+ pbConfig, err := cf.Build()
|
|
|
+ if err != nil {
|
|
|
+ base.Fatalf(err.Error())
|
|
|
+ }
|
|
|
+ out, err = proto.Marshal(pbConfig)
|
|
|
+ if err != nil {
|
|
|
+ base.Fatalf("failed to marshal proto config: %s", err)
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ base.Errorf("invalid output format: %s", outputFormat)
|
|
|
+ base.Errorf("Run '%s help %s' for details.", base.CommandEnv.Exec, cmd.LongName())
|
|
|
+ base.Exit()
|
|
|
}
|
|
|
|
|
|
- if _, err := os.Stdout.Write(bytesConfig); err != nil {
|
|
|
+ if _, err := os.Stdout.Write(out); err != nil {
|
|
|
base.Fatalf("failed to write proto config: %s", err)
|
|
|
}
|
|
|
}
|