From 7a0af318df9011d30f20c7cd5142851d97b1eb1b Mon Sep 17 00:00:00 2001 From: Jebbs Date: Thu, 11 Mar 2021 05:03:26 +0800 Subject: [PATCH] refine api, run command and merger (#766) * mergers code optimize * api log work with pipe * remove inbounds/outbounds by tags *fix rmo flag parse * cmds description and message optimize --- infra/conf/mergers/extensions.go | 4 +- infra/conf/mergers/formats.go | 40 ------------------ infra/conf/mergers/merge.go | 22 +++++----- infra/conf/mergers/merger_base.go | 10 +++-- infra/conf/mergers/mergers.go | 49 ++++++++++++++++++++--- infra/conf/mergers/names.go | 2 +- main/commands/all/api/inbounds_add.go | 12 ++++-- main/commands/all/api/inbounds_remove.go | 39 +++++++++++++----- main/commands/all/api/log.go | 13 ++++-- main/commands/all/api/outbounds_add.go | 12 ++++-- main/commands/all/api/outbounds_remove.go | 41 ++++++++++++++----- main/commands/all/api/stats.go | 5 ++- main/commands/all/convert.go | 34 ++++++++-------- main/commands/all/format_doc.go | 12 +++--- main/commands/run.go | 12 +++++- main/commands/test.go | 12 +++++- 16 files changed, 194 insertions(+), 125 deletions(-) delete mode 100644 infra/conf/mergers/formats.go diff --git a/infra/conf/mergers/extensions.go b/infra/conf/mergers/extensions.go index d627b1edb..2a7fa40f7 100644 --- a/infra/conf/mergers/extensions.go +++ b/infra/conf/mergers/extensions.go @@ -8,7 +8,7 @@ func GetExtensions(formatName string) ([]string, error) { if lowerName == "auto" { return GetAllExtensions(), nil } - f, found := mergeLoaderByName[lowerName] + f, found := mergersByName[lowerName] if !found { return nil, newError(formatName+" not found", formatName).AtWarning() } @@ -18,7 +18,7 @@ func GetExtensions(formatName string) ([]string, error) { // GetAllExtensions get all extensions supported func GetAllExtensions() []string { extensions := make([]string, 0) - for _, f := range mergeLoaderByName { + for _, f := range mergersByName { extensions = append(extensions, f.Extensions...) } return extensions diff --git a/infra/conf/mergers/formats.go b/infra/conf/mergers/formats.go deleted file mode 100644 index c2f1350a5..000000000 --- a/infra/conf/mergers/formats.go +++ /dev/null @@ -1,40 +0,0 @@ -package mergers - -//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen - -import ( - "strings" -) - -// MergeableFormat is a configurable mergeable format of V2Ray config file. -type MergeableFormat struct { - Name string - Extensions []string - Loader MergeLoader -} - -// MergeLoader is a utility to merge V2Ray config from external source into a map and returns it. -type MergeLoader func(input interface{}, m map[string]interface{}) error - -var ( - mergeLoaderByName = make(map[string]*MergeableFormat) - mergeLoaderByExt = make(map[string]*MergeableFormat) -) - -// RegisterMergeLoader add a new MergeLoader. -func RegisterMergeLoader(format *MergeableFormat) error { - if _, found := mergeLoaderByName[format.Name]; found { - return newError(format.Name, " already registered.") - } - mergeLoaderByName[format.Name] = format - - for _, ext := range format.Extensions { - lext := strings.ToLower(ext) - if f, found := mergeLoaderByExt[lext]; found { - return newError(ext, " already registered to ", f.Name) - } - mergeLoaderByExt[lext] = format - } - - return nil -} diff --git a/infra/conf/mergers/merge.go b/infra/conf/mergers/merge.go index 9b151d633..9be9d5eb0 100644 --- a/infra/conf/mergers/merge.go +++ b/infra/conf/mergers/merge.go @@ -12,15 +12,15 @@ import ( // MergeAs load input and merge as specified format into m func MergeAs(formatName string, input interface{}, m map[string]interface{}) error { - f, found := mergeLoaderByName[formatName] + f, found := mergersByName[formatName] if !found { - return newError("format loader not found for: ", formatName) + return newError("format merger not found for: ", formatName) } - return f.Loader(input, m) + return f.Merge(input, m) } // Merge loads inputs and merges them into m -// it detects extension for loader selecting, or try all loaders +// it detects extension for merger selecting, or try all mergers // if no extension found func Merge(input interface{}, m map[string]interface{}) error { switch v := input.(type) { @@ -49,7 +49,7 @@ func Merge(input interface{}, m map[string]interface{}) error { return err } case io.Reader: - // read to []byte incase it tries different loaders + // read to []byte incase it tries different mergers bs, err := ioutil.ReadAll(v) if err != nil { return err @@ -69,24 +69,24 @@ func mergeSingleFile(input interface{}, m map[string]interface{}) error { ext := getExtension(file) if ext != "" { lext := strings.ToLower(ext) - f, found := mergeLoaderByExt[lext] + f, found := mergersByExt[lext] if !found { return newError("unmergeable format extension: ", ext) } - return f.Loader(file, m) + return f.Merge(file, m) } } - // no extension, try all loaders - for _, f := range mergeLoaderByName { + // no extension, try all mergers + for _, f := range mergersByName { if f.Name == core.FormatAuto { continue } - err := f.Loader(input, m) + err := f.Merge(input, m) if err == nil { return nil } } - return newError("tried all loaders but failed for: ", input).AtWarning() + return newError("tried all mergers but failed for: ", input).AtWarning() } func getExtension(filename string) string { diff --git a/infra/conf/mergers/merger_base.go b/infra/conf/mergers/merger_base.go index cddeb556b..7e6302f24 100644 --- a/infra/conf/mergers/merger_base.go +++ b/infra/conf/mergers/merger_base.go @@ -11,15 +11,17 @@ import ( type jsonConverter func(v []byte) ([]byte, error) -func makeLoader(name string, extensions []string, converter jsonConverter) *MergeableFormat { - return &MergeableFormat{ +// makeMerger makes a merger who merge the format by converting it to JSON +func makeMerger(name string, extensions []string, converter jsonConverter) *Merger { + return &Merger{ Name: name, Extensions: extensions, - Loader: makeConvertToJSONLoader(converter), + Merge: makeToJSONMergeFunc(converter), } } -func makeConvertToJSONLoader(converter func(v []byte) ([]byte, error)) MergeLoader { +// makeToJSONMergeFunc makes a merge func who merge the format by converting it to JSON +func makeToJSONMergeFunc(converter func(v []byte) ([]byte, error)) MergeFunc { return func(input interface{}, target map[string]interface{}) error { if target == nil { panic("merge target is nil") diff --git a/infra/conf/mergers/mergers.go b/infra/conf/mergers/mergers.go index 5f9ad5144..1f5f0c8a9 100644 --- a/infra/conf/mergers/mergers.go +++ b/infra/conf/mergers/mergers.go @@ -1,32 +1,69 @@ package mergers +//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen + import ( + "strings" + core "github.com/v2fly/v2ray-core/v4" "github.com/v2fly/v2ray-core/v4/common" "github.com/v2fly/v2ray-core/v4/infra/conf/json" ) func init() { - common.Must(RegisterMergeLoader(makeLoader( + common.Must(RegisterMerger(makeMerger( core.FormatJSON, []string{".json", ".jsonc"}, nil, ))) - common.Must(RegisterMergeLoader(makeLoader( + common.Must(RegisterMerger(makeMerger( core.FormatTOML, []string{".toml"}, json.FromTOML, ))) - common.Must(RegisterMergeLoader(makeLoader( + common.Must(RegisterMerger(makeMerger( core.FormatYAML, []string{".yml", ".yaml"}, json.FromYAML, ))) - common.Must(RegisterMergeLoader( - &MergeableFormat{ + common.Must(RegisterMerger( + &Merger{ Name: core.FormatAuto, Extensions: nil, - Loader: Merge, + Merge: Merge, }), ) } + +// Merger is a configurable format merger for V2Ray config files. +type Merger struct { + Name string + Extensions []string + Merge MergeFunc +} + +// MergeFunc is a utility to merge V2Ray config from external source into a map and returns it. +type MergeFunc func(input interface{}, m map[string]interface{}) error + +var ( + mergersByName = make(map[string]*Merger) + mergersByExt = make(map[string]*Merger) +) + +// RegisterMerger add a new Merger. +func RegisterMerger(format *Merger) error { + if _, found := mergersByName[format.Name]; found { + return newError(format.Name, " already registered.") + } + mergersByName[format.Name] = format + + for _, ext := range format.Extensions { + lext := strings.ToLower(ext) + if f, found := mergersByExt[lext]; found { + return newError(ext, " already registered to ", f.Name) + } + mergersByExt[lext] = format + } + + return nil +} diff --git a/infra/conf/mergers/names.go b/infra/conf/mergers/names.go index adbfa9e0f..43e3daaed 100644 --- a/infra/conf/mergers/names.go +++ b/infra/conf/mergers/names.go @@ -3,7 +3,7 @@ package mergers // GetAllNames get names of all formats func GetAllNames() []string { names := make([]string, 0) - for _, f := range mergeLoaderByName { + for _, f := range mergersByName { names = append(names, f.Name) } return names diff --git a/main/commands/all/api/inbounds_add.go b/main/commands/all/api/inbounds_add.go index 82f0cc73f..f4a16b48b 100644 --- a/main/commands/all/api/inbounds_add.go +++ b/main/commands/all/api/inbounds_add.go @@ -10,15 +10,18 @@ import ( var cmdAddInbounds = &base.Command{ CustomFlags: true, - UsageLine: "{{.Exec}} api adi [--server=127.0.0.1:8080] [c2.json]...", + UsageLine: "{{.Exec}} api adi [--server=127.0.0.1:8080] [c1.json] [dir1]...", Short: "add inbounds", Long: ` Add inbounds to V2Ray. +> Make sure you have "HandlerService" set in "config.api.services" +of server config. + Arguments: -format - Specify the input format. + The input format. Available values: "auto", "json", "toml", "yaml" Default: "auto" @@ -33,7 +36,8 @@ Arguments: Example: - {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json + {{.Exec}} {{.LongName}} dir + {{.Exec}} {{.LongName}} c1.json c2.yaml `, Run: executeAddInbounds, } @@ -44,7 +48,7 @@ func executeAddInbounds(cmd *base.Command, args []string) { cmd.Flag.Parse(args) c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively) if err != nil { - base.Fatalf("%s", err) + base.Fatalf("failed to load: %s", err) } if len(c.InboundConfigs) == 0 { base.Fatalf("no valid inbound found") diff --git a/main/commands/all/api/inbounds_remove.go b/main/commands/all/api/inbounds_remove.go index 5259e0522..63291c8b7 100644 --- a/main/commands/all/api/inbounds_remove.go +++ b/main/commands/all/api/inbounds_remove.go @@ -10,21 +10,27 @@ import ( var cmdRemoveInbounds = &base.Command{ CustomFlags: true, - UsageLine: "{{.Exec}} api rmi [--server=127.0.0.1:8080] [json_file] [tag]...", + UsageLine: "{{.Exec}} api rmi [--server=127.0.0.1:8080] [c1.json] [dir1]...", Short: "remove inbounds", Long: ` Remove inbounds from V2Ray. +> Make sure you have "HandlerService" set in "config.api.services" +of server config. + Arguments: -format - Specify the input format. + The input format. Available values: "auto", "json", "toml", "yaml" Default: "auto" -r Load folders recursively. + -tags + The input are tags instead of config files + -s, -server The API server address. Default 127.0.0.1:8080 @@ -33,7 +39,9 @@ Arguments: Example: - {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json "tag name" + {{.Exec}} {{.LongName}} dir + {{.Exec}} {{.LongName}} c1.json c2.yaml + {{.Exec}} {{.LongName}} -tags tag1 tag2 `, Run: executeRemoveInbounds, } @@ -41,12 +49,23 @@ Example: func executeRemoveInbounds(cmd *base.Command, args []string) { setSharedFlags(cmd) setSharedConfigFlags(cmd) + isTags := cmd.Flag.Bool("tags", false, "") cmd.Flag.Parse(args) - c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively) - if err != nil { - base.Fatalf("%s", err) + + var tags []string + if *isTags { + tags = cmd.Flag.Args() + } else { + c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively) + if err != nil { + base.Fatalf("failed to load: %s", err) + } + tags = make([]string, 0) + for _, c := range c.InboundConfigs { + tags = append(tags, c.Tag) + } } - if len(c.InboundConfigs) == 0 { + if len(tags) == 0 { base.Fatalf("no inbound to remove") } @@ -54,10 +73,10 @@ func executeRemoveInbounds(cmd *base.Command, args []string) { defer close() client := handlerService.NewHandlerServiceClient(conn) - for _, c := range c.InboundConfigs { - fmt.Println("removing:", c.Tag) + for _, tag := range tags { + fmt.Println("removing:", tag) r := &handlerService.RemoveInboundRequest{ - Tag: c.Tag, + Tag: tag, } _, err := client.RemoveInbound(ctx, r) if err != nil { diff --git a/main/commands/all/api/log.go b/main/commands/all/api/log.go index 34a9ce41e..f96bc28e0 100644 --- a/main/commands/all/api/log.go +++ b/main/commands/all/api/log.go @@ -3,6 +3,7 @@ package api import ( "io" "log" + "os" logService "github.com/v2fly/v2ray-core/v4/app/log/command" "github.com/v2fly/v2ray-core/v4/main/commands/base" @@ -15,6 +16,9 @@ var cmdLog = &base.Command{ Long: ` Follow and print logs from v2ray. +> Make sure you have "LoggerService" set in "config.api.services" +of server config. + > It ignores -timeout flag while following logs Arguments: @@ -33,10 +37,10 @@ Example: {{.Exec}} {{.LongName}} {{.Exec}} {{.LongName}} --restart `, - Run: executeRestartLogger, + Run: executeLog, } -func executeRestartLogger(cmd *base.Command, args []string) { +func executeLog(cmd *base.Command, args []string) { var restart bool cmd.Flag.BoolVar(&restart, "restart", false, "") setSharedFlags(cmd) @@ -69,7 +73,8 @@ func followLogger() { if err != nil { base.Fatalf("failed to follow logger: %s", err) } - + // work with `v2ray api log | grep expr` + log.SetOutput(os.Stdout) for { resp, err := stream.Recv() if err == io.EOF { @@ -78,6 +83,6 @@ func followLogger() { if err != nil { base.Fatalf("failed to fetch log: %s", err) } - log.Print(resp.Message) + log.Println(resp.Message) } } diff --git a/main/commands/all/api/outbounds_add.go b/main/commands/all/api/outbounds_add.go index 15db1ffa4..c70bdcca0 100644 --- a/main/commands/all/api/outbounds_add.go +++ b/main/commands/all/api/outbounds_add.go @@ -10,15 +10,18 @@ import ( var cmdAddOutbounds = &base.Command{ CustomFlags: true, - UsageLine: "{{.Exec}} api ado [--server=127.0.0.1:8080] [c2.json]...", + UsageLine: "{{.Exec}} api ado [--server=127.0.0.1:8080] [c1.json] [dir1]...", Short: "add outbounds", Long: ` Add outbounds to V2Ray. +> Make sure you have "HandlerService" set in "config.api.services" +of server config. + Arguments: -format - Specify the input format. + The input format. Available values: "auto", "json", "toml", "yaml" Default: "auto" @@ -33,7 +36,8 @@ Arguments: Example: - {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json + {{.Exec}} {{.LongName}} dir + {{.Exec}} {{.LongName}} c1.json c2.yaml `, Run: executeAddOutbounds, } @@ -44,7 +48,7 @@ func executeAddOutbounds(cmd *base.Command, args []string) { cmd.Flag.Parse(args) c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively) if err != nil { - base.Fatalf("%s", err) + base.Fatalf("failed to load: %s", err) } if len(c.OutboundConfigs) == 0 { base.Fatalf("no valid outbound found") diff --git a/main/commands/all/api/outbounds_remove.go b/main/commands/all/api/outbounds_remove.go index 2f97b5ab0..2a536c548 100644 --- a/main/commands/all/api/outbounds_remove.go +++ b/main/commands/all/api/outbounds_remove.go @@ -10,21 +10,27 @@ import ( var cmdRemoveOutbounds = &base.Command{ CustomFlags: true, - UsageLine: "{{.Exec}} api rmo [--server=127.0.0.1:8080] [json_file] [tag]...", + UsageLine: "{{.Exec}} api rmo [--server=127.0.0.1:8080] [c1.json] [dir1]...", Short: "remove outbounds", Long: ` Remove outbounds from V2Ray. +> Make sure you have "HandlerService" set in "config.api.services" +of server config. + Arguments: -format - Specify the input format. + The input format. Available values: "auto", "json", "toml", "yaml" Default: "auto" -r Load folders recursively. + -tags + The input are tags instead of config files + -s, -server The API server address. Default 127.0.0.1:8080 @@ -33,20 +39,33 @@ Arguments: Example: - {{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json "tag name" + {{.Exec}} {{.LongName}} dir + {{.Exec}} {{.LongName}} c1.json c2.yaml + {{.Exec}} {{.LongName}} -tags tag1 tag2 `, Run: executeRemoveOutbounds, } func executeRemoveOutbounds(cmd *base.Command, args []string) { setSharedFlags(cmd) - cmd.Flag.Parse(args) setSharedConfigFlags(cmd) - c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively) - if err != nil { - base.Fatalf("%s", err) + isTags := cmd.Flag.Bool("tags", false, "") + cmd.Flag.Parse(args) + + var tags []string + if *isTags { + tags = cmd.Flag.Args() + } else { + c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively) + if err != nil { + base.Fatalf("failed to load: %s", err) + } + tags = make([]string, 0) + for _, c := range c.OutboundConfigs { + tags = append(tags, c.Tag) + } } - if len(c.OutboundConfigs) == 0 { + if len(tags) == 0 { base.Fatalf("no outbound to remove") } @@ -54,10 +73,10 @@ func executeRemoveOutbounds(cmd *base.Command, args []string) { defer close() client := handlerService.NewHandlerServiceClient(conn) - for _, c := range c.OutboundConfigs { - fmt.Println("removing:", c.Tag) + for _, tag := range tags { + fmt.Println("removing:", tag) r := &handlerService.RemoveOutboundRequest{ - Tag: c.Tag, + Tag: tag, } _, err := client.RemoveOutbound(ctx, r) if err != nil { diff --git a/main/commands/all/api/stats.go b/main/commands/all/api/stats.go index 8f9ba327d..243fcb1b3 100644 --- a/main/commands/all/api/stats.go +++ b/main/commands/all/api/stats.go @@ -19,13 +19,16 @@ var cmdStats = &base.Command{ Long: ` Query statistics from V2Ray. +> Make sure you have "StatsService" set in "config.api.services" +of server config. + Arguments: -regexp The patterns are using regexp. -reset - Fetch values then reset statistics counters to 0. + Reset counters to 0 after fetching their values. -runtime Get runtime statistics. diff --git a/main/commands/all/convert.go b/main/commands/all/convert.go index d6199dc41..317c5b67d 100644 --- a/main/commands/all/convert.go +++ b/main/commands/all/convert.go @@ -23,17 +23,17 @@ var cmdConvert = &base.Command{ Short: "convert config files", Long: ` Convert config files between different formats. Files are merged -before convert if multiple assigned. +before convert. Arguments: -i, -input - Specify the input format. + The input format. Available values: "auto", "json", "toml", "yaml" Default: "auto" -o, -output - Specify the output format + The output format Available values: "json", "toml", "yaml", "protobuf" / "pb" Default: "json" @@ -42,15 +42,15 @@ Arguments: Examples: - {{.Exec}} {{.LongName}} -output=protobuf config.json (1) - {{.Exec}} {{.LongName}} -input=toml config.toml (2) - {{.Exec}} {{.LongName}} "path/to/dir" (3) - {{.Exec}} {{.LongName}} -i yaml -o protobuf c1.yaml .yaml (4) + {{.Exec}} {{.LongName}} -output=protobuf "path/to/dir" (1) + {{.Exec}} {{.LongName}} -o=yaml config.toml (2) + {{.Exec}} {{.LongName}} c1.json c2.json (3) + {{.Exec}} {{.LongName}} -output=yaml c1.yaml .yaml (4) -(1) Convert json to protobuf -(2) Convert toml to json -(3) Merge json files in dir -(4) Merge yaml files and convert to protobuf +(1) Merge all supported files in dir and convert to protobuf +(2) Convert toml to yaml +(3) Merge json files +(4) Merge yaml files Use "{{.Exec}} help config-merge" for more information about merge. `, @@ -81,11 +81,11 @@ func executeConvert(cmd *base.Command, args []string) { m, err := helpers.LoadConfigToMap(cmd.Flag.Args(), inputFormat, confDirRecursively) if err != nil { - base.Fatalf(err.Error()) + base.Fatalf("failed to merge: %s", err) } err = merge.ApplyRules(m) if err != nil { - base.Fatalf(err.Error()) + base.Fatalf("failed to apply merge rules: %s", err) } var out []byte @@ -93,17 +93,17 @@ func executeConvert(cmd *base.Command, args []string) { case core.FormatJSON: out, err = json.Marshal(m) if err != nil { - base.Fatalf("failed to marshal json: %s", err) + base.Fatalf("failed to convert to json: %s", err) } case core.FormatTOML: out, err = toml.Marshal(m) if err != nil { - base.Fatalf("failed to marshal json: %s", err) + base.Fatalf("failed to convert to toml: %s", err) } case core.FormatYAML: out, err = yaml.Marshal(m) if err != nil { - base.Fatalf("failed to marshal json: %s", err) + base.Fatalf("failed to convert to yaml: %s", err) } case core.FormatProtobuf, core.FormatProtobufShort: data, err := json.Marshal(m) @@ -121,7 +121,7 @@ func executeConvert(cmd *base.Command, args []string) { } out, err = proto.Marshal(pbConfig) if err != nil { - base.Fatalf("failed to marshal proto config: %s", err) + base.Fatalf("failed to convert to protobuf: %s", err) } default: base.Errorf("invalid output format: %s", outputFormat) diff --git a/main/commands/all/format_doc.go b/main/commands/all/format_doc.go index beaaef601..cdb081064 100644 --- a/main/commands/all/format_doc.go +++ b/main/commands/all/format_doc.go @@ -8,12 +8,12 @@ var docFormat = &base.Command{ UsageLine: "{{.Exec}} format-loader", Short: "config formats and loading", Long: ` -{{.Exec}} supports different config formats: +{{.Exec}} is equipped with multiple loaders to support different +config formats: * auto - The default loader, supports all extensions below. - It loads config by format detecting, with mixed - formats support. + The default loader, supports all formats listed below, with + format detecting, and mixed fomats support. * json (.json, .jsonc) The json loader, multiple files support, mergeable. @@ -21,14 +21,14 @@ var docFormat = &base.Command{ * toml (.toml) The toml loader, multiple files support, mergeable. - * yaml (.yml) + * yaml (.yml, .yaml) The yaml loader, multiple files support, mergeable. * protobuf / pb (.pb) Single file support, unmergeable. -The following explains how format loaders behave with examples. +The following explains how format loaders behaves. Examples: diff --git a/main/commands/run.go b/main/commands/run.go index 734ea54b3..3160bb4ec 100644 --- a/main/commands/run.go +++ b/main/commands/run.go @@ -25,19 +25,27 @@ var CmdRun = &base.Command{ Long: ` Run V2Ray with config. +{{.Exec}} will also use the config directory specified by environment +variable "v2ray.location.confdir". If no config found, it tries +to load config from one of below: + + 1. The default "config.json" in the current directory + 2. The config file from ENV "v2ray.location.config" + 3. The stdin if all failed above + Arguments: -c, -config Config file for V2Ray. Multiple assign is accepted. -d, -confdir - A dir with config files. Multiple assign is accepted. + A directory with config files. Multiple assign is accepted. -r Load confdir recursively. -format - Format of input files. (default "json") + Format of config input. (default "auto") Examples: diff --git a/main/commands/test.go b/main/commands/test.go index b5c00a3b9..ecafec84b 100644 --- a/main/commands/test.go +++ b/main/commands/test.go @@ -16,19 +16,27 @@ var CmdTest = &base.Command{ Long: ` Test config files, without launching V2Ray server. +{{.Exec}} will also use the config directory specified by environment +variable "v2ray.location.confdir". If no config found, it tries +to load config from one of below: + + 1. The default "config.json" in the current directory + 2. The config file from ENV "v2ray.location.config" + 3. The stdin if all failed above + Arguments: -c, -config Config file for V2Ray. Multiple assign is accepted. -d, -confdir - A dir with config files. Multiple assign is accepted. + A directory with config files. Multiple assign is accepted. -r Load confdir recursively. -format - Format of input files. (default "json") + Format of config input. (default "auto") Examples: