mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-01-19 15:57:04 -05:00
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
This commit is contained in:
parent
2523d77919
commit
7a0af318df
@ -8,7 +8,7 @@ func GetExtensions(formatName string) ([]string, error) {
|
|||||||
if lowerName == "auto" {
|
if lowerName == "auto" {
|
||||||
return GetAllExtensions(), nil
|
return GetAllExtensions(), nil
|
||||||
}
|
}
|
||||||
f, found := mergeLoaderByName[lowerName]
|
f, found := mergersByName[lowerName]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, newError(formatName+" not found", formatName).AtWarning()
|
return nil, newError(formatName+" not found", formatName).AtWarning()
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ func GetExtensions(formatName string) ([]string, error) {
|
|||||||
// GetAllExtensions get all extensions supported
|
// GetAllExtensions get all extensions supported
|
||||||
func GetAllExtensions() []string {
|
func GetAllExtensions() []string {
|
||||||
extensions := make([]string, 0)
|
extensions := make([]string, 0)
|
||||||
for _, f := range mergeLoaderByName {
|
for _, f := range mergersByName {
|
||||||
extensions = append(extensions, f.Extensions...)
|
extensions = append(extensions, f.Extensions...)
|
||||||
}
|
}
|
||||||
return extensions
|
return extensions
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -12,15 +12,15 @@ import (
|
|||||||
|
|
||||||
// MergeAs load input and merge as specified format into m
|
// MergeAs load input and merge as specified format into m
|
||||||
func MergeAs(formatName string, input interface{}, m map[string]interface{}) error {
|
func MergeAs(formatName string, input interface{}, m map[string]interface{}) error {
|
||||||
f, found := mergeLoaderByName[formatName]
|
f, found := mergersByName[formatName]
|
||||||
if !found {
|
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
|
// 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
|
// if no extension found
|
||||||
func Merge(input interface{}, m map[string]interface{}) error {
|
func Merge(input interface{}, m map[string]interface{}) error {
|
||||||
switch v := input.(type) {
|
switch v := input.(type) {
|
||||||
@ -49,7 +49,7 @@ func Merge(input interface{}, m map[string]interface{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case io.Reader:
|
case io.Reader:
|
||||||
// read to []byte incase it tries different loaders
|
// read to []byte incase it tries different mergers
|
||||||
bs, err := ioutil.ReadAll(v)
|
bs, err := ioutil.ReadAll(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -69,24 +69,24 @@ func mergeSingleFile(input interface{}, m map[string]interface{}) error {
|
|||||||
ext := getExtension(file)
|
ext := getExtension(file)
|
||||||
if ext != "" {
|
if ext != "" {
|
||||||
lext := strings.ToLower(ext)
|
lext := strings.ToLower(ext)
|
||||||
f, found := mergeLoaderByExt[lext]
|
f, found := mergersByExt[lext]
|
||||||
if !found {
|
if !found {
|
||||||
return newError("unmergeable format extension: ", ext)
|
return newError("unmergeable format extension: ", ext)
|
||||||
}
|
}
|
||||||
return f.Loader(file, m)
|
return f.Merge(file, m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// no extension, try all loaders
|
// no extension, try all mergers
|
||||||
for _, f := range mergeLoaderByName {
|
for _, f := range mergersByName {
|
||||||
if f.Name == core.FormatAuto {
|
if f.Name == core.FormatAuto {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := f.Loader(input, m)
|
err := f.Merge(input, m)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return 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 {
|
func getExtension(filename string) string {
|
||||||
|
@ -11,15 +11,17 @@ import (
|
|||||||
|
|
||||||
type jsonConverter func(v []byte) ([]byte, error)
|
type jsonConverter func(v []byte) ([]byte, error)
|
||||||
|
|
||||||
func makeLoader(name string, extensions []string, converter jsonConverter) *MergeableFormat {
|
// makeMerger makes a merger who merge the format by converting it to JSON
|
||||||
return &MergeableFormat{
|
func makeMerger(name string, extensions []string, converter jsonConverter) *Merger {
|
||||||
|
return &Merger{
|
||||||
Name: name,
|
Name: name,
|
||||||
Extensions: extensions,
|
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 {
|
return func(input interface{}, target map[string]interface{}) error {
|
||||||
if target == nil {
|
if target == nil {
|
||||||
panic("merge target is nil")
|
panic("merge target is nil")
|
||||||
|
@ -1,32 +1,69 @@
|
|||||||
package mergers
|
package mergers
|
||||||
|
|
||||||
|
//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
core "github.com/v2fly/v2ray-core/v4"
|
core "github.com/v2fly/v2ray-core/v4"
|
||||||
"github.com/v2fly/v2ray-core/v4/common"
|
"github.com/v2fly/v2ray-core/v4/common"
|
||||||
"github.com/v2fly/v2ray-core/v4/infra/conf/json"
|
"github.com/v2fly/v2ray-core/v4/infra/conf/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(RegisterMergeLoader(makeLoader(
|
common.Must(RegisterMerger(makeMerger(
|
||||||
core.FormatJSON,
|
core.FormatJSON,
|
||||||
[]string{".json", ".jsonc"},
|
[]string{".json", ".jsonc"},
|
||||||
nil,
|
nil,
|
||||||
)))
|
)))
|
||||||
common.Must(RegisterMergeLoader(makeLoader(
|
common.Must(RegisterMerger(makeMerger(
|
||||||
core.FormatTOML,
|
core.FormatTOML,
|
||||||
[]string{".toml"},
|
[]string{".toml"},
|
||||||
json.FromTOML,
|
json.FromTOML,
|
||||||
)))
|
)))
|
||||||
common.Must(RegisterMergeLoader(makeLoader(
|
common.Must(RegisterMerger(makeMerger(
|
||||||
core.FormatYAML,
|
core.FormatYAML,
|
||||||
[]string{".yml", ".yaml"},
|
[]string{".yml", ".yaml"},
|
||||||
json.FromYAML,
|
json.FromYAML,
|
||||||
)))
|
)))
|
||||||
common.Must(RegisterMergeLoader(
|
common.Must(RegisterMerger(
|
||||||
&MergeableFormat{
|
&Merger{
|
||||||
Name: core.FormatAuto,
|
Name: core.FormatAuto,
|
||||||
Extensions: nil,
|
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
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ package mergers
|
|||||||
// GetAllNames get names of all formats
|
// GetAllNames get names of all formats
|
||||||
func GetAllNames() []string {
|
func GetAllNames() []string {
|
||||||
names := make([]string, 0)
|
names := make([]string, 0)
|
||||||
for _, f := range mergeLoaderByName {
|
for _, f := range mergersByName {
|
||||||
names = append(names, f.Name)
|
names = append(names, f.Name)
|
||||||
}
|
}
|
||||||
return names
|
return names
|
||||||
|
@ -10,15 +10,18 @@ import (
|
|||||||
|
|
||||||
var cmdAddInbounds = &base.Command{
|
var cmdAddInbounds = &base.Command{
|
||||||
CustomFlags: true,
|
CustomFlags: true,
|
||||||
UsageLine: "{{.Exec}} api adi [--server=127.0.0.1:8080] <c1.json> [c2.json]...",
|
UsageLine: "{{.Exec}} api adi [--server=127.0.0.1:8080] [c1.json] [dir1]...",
|
||||||
Short: "add inbounds",
|
Short: "add inbounds",
|
||||||
Long: `
|
Long: `
|
||||||
Add inbounds to V2Ray.
|
Add inbounds to V2Ray.
|
||||||
|
|
||||||
|
> Make sure you have "HandlerService" set in "config.api.services"
|
||||||
|
of server config.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
-format <format>
|
-format <format>
|
||||||
Specify the input format.
|
The input format.
|
||||||
Available values: "auto", "json", "toml", "yaml"
|
Available values: "auto", "json", "toml", "yaml"
|
||||||
Default: "auto"
|
Default: "auto"
|
||||||
|
|
||||||
@ -33,7 +36,8 @@ Arguments:
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
|
{{.Exec}} {{.LongName}} dir
|
||||||
|
{{.Exec}} {{.LongName}} c1.json c2.yaml
|
||||||
`,
|
`,
|
||||||
Run: executeAddInbounds,
|
Run: executeAddInbounds,
|
||||||
}
|
}
|
||||||
@ -44,7 +48,7 @@ func executeAddInbounds(cmd *base.Command, args []string) {
|
|||||||
cmd.Flag.Parse(args)
|
cmd.Flag.Parse(args)
|
||||||
c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively)
|
c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("%s", err)
|
base.Fatalf("failed to load: %s", err)
|
||||||
}
|
}
|
||||||
if len(c.InboundConfigs) == 0 {
|
if len(c.InboundConfigs) == 0 {
|
||||||
base.Fatalf("no valid inbound found")
|
base.Fatalf("no valid inbound found")
|
||||||
|
@ -10,21 +10,27 @@ import (
|
|||||||
|
|
||||||
var cmdRemoveInbounds = &base.Command{
|
var cmdRemoveInbounds = &base.Command{
|
||||||
CustomFlags: true,
|
CustomFlags: true,
|
||||||
UsageLine: "{{.Exec}} api rmi [--server=127.0.0.1:8080] <json_file|tag> [json_file] [tag]...",
|
UsageLine: "{{.Exec}} api rmi [--server=127.0.0.1:8080] [c1.json] [dir1]...",
|
||||||
Short: "remove inbounds",
|
Short: "remove inbounds",
|
||||||
Long: `
|
Long: `
|
||||||
Remove inbounds from V2Ray.
|
Remove inbounds from V2Ray.
|
||||||
|
|
||||||
|
> Make sure you have "HandlerService" set in "config.api.services"
|
||||||
|
of server config.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
-format <format>
|
-format <format>
|
||||||
Specify the input format.
|
The input format.
|
||||||
Available values: "auto", "json", "toml", "yaml"
|
Available values: "auto", "json", "toml", "yaml"
|
||||||
Default: "auto"
|
Default: "auto"
|
||||||
|
|
||||||
-r
|
-r
|
||||||
Load folders recursively.
|
Load folders recursively.
|
||||||
|
|
||||||
|
-tags
|
||||||
|
The input are tags instead of config files
|
||||||
|
|
||||||
-s, -server <server:port>
|
-s, -server <server:port>
|
||||||
The API server address. Default 127.0.0.1:8080
|
The API server address. Default 127.0.0.1:8080
|
||||||
|
|
||||||
@ -33,7 +39,9 @@ Arguments:
|
|||||||
|
|
||||||
Example:
|
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,
|
Run: executeRemoveInbounds,
|
||||||
}
|
}
|
||||||
@ -41,12 +49,23 @@ Example:
|
|||||||
func executeRemoveInbounds(cmd *base.Command, args []string) {
|
func executeRemoveInbounds(cmd *base.Command, args []string) {
|
||||||
setSharedFlags(cmd)
|
setSharedFlags(cmd)
|
||||||
setSharedConfigFlags(cmd)
|
setSharedConfigFlags(cmd)
|
||||||
|
isTags := cmd.Flag.Bool("tags", false, "")
|
||||||
cmd.Flag.Parse(args)
|
cmd.Flag.Parse(args)
|
||||||
|
|
||||||
|
var tags []string
|
||||||
|
if *isTags {
|
||||||
|
tags = cmd.Flag.Args()
|
||||||
|
} else {
|
||||||
c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively)
|
c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("%s", err)
|
base.Fatalf("failed to load: %s", err)
|
||||||
}
|
}
|
||||||
if len(c.InboundConfigs) == 0 {
|
tags = make([]string, 0)
|
||||||
|
for _, c := range c.InboundConfigs {
|
||||||
|
tags = append(tags, c.Tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(tags) == 0 {
|
||||||
base.Fatalf("no inbound to remove")
|
base.Fatalf("no inbound to remove")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,10 +73,10 @@ func executeRemoveInbounds(cmd *base.Command, args []string) {
|
|||||||
defer close()
|
defer close()
|
||||||
|
|
||||||
client := handlerService.NewHandlerServiceClient(conn)
|
client := handlerService.NewHandlerServiceClient(conn)
|
||||||
for _, c := range c.InboundConfigs {
|
for _, tag := range tags {
|
||||||
fmt.Println("removing:", c.Tag)
|
fmt.Println("removing:", tag)
|
||||||
r := &handlerService.RemoveInboundRequest{
|
r := &handlerService.RemoveInboundRequest{
|
||||||
Tag: c.Tag,
|
Tag: tag,
|
||||||
}
|
}
|
||||||
_, err := client.RemoveInbound(ctx, r)
|
_, err := client.RemoveInbound(ctx, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
logService "github.com/v2fly/v2ray-core/v4/app/log/command"
|
logService "github.com/v2fly/v2ray-core/v4/app/log/command"
|
||||||
"github.com/v2fly/v2ray-core/v4/main/commands/base"
|
"github.com/v2fly/v2ray-core/v4/main/commands/base"
|
||||||
@ -15,6 +16,9 @@ var cmdLog = &base.Command{
|
|||||||
Long: `
|
Long: `
|
||||||
Follow and print logs from v2ray.
|
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
|
> It ignores -timeout flag while following logs
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@ -33,10 +37,10 @@ Example:
|
|||||||
{{.Exec}} {{.LongName}}
|
{{.Exec}} {{.LongName}}
|
||||||
{{.Exec}} {{.LongName}} --restart
|
{{.Exec}} {{.LongName}} --restart
|
||||||
`,
|
`,
|
||||||
Run: executeRestartLogger,
|
Run: executeLog,
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeRestartLogger(cmd *base.Command, args []string) {
|
func executeLog(cmd *base.Command, args []string) {
|
||||||
var restart bool
|
var restart bool
|
||||||
cmd.Flag.BoolVar(&restart, "restart", false, "")
|
cmd.Flag.BoolVar(&restart, "restart", false, "")
|
||||||
setSharedFlags(cmd)
|
setSharedFlags(cmd)
|
||||||
@ -69,7 +73,8 @@ func followLogger() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("failed to follow logger: %s", err)
|
base.Fatalf("failed to follow logger: %s", err)
|
||||||
}
|
}
|
||||||
|
// work with `v2ray api log | grep expr`
|
||||||
|
log.SetOutput(os.Stdout)
|
||||||
for {
|
for {
|
||||||
resp, err := stream.Recv()
|
resp, err := stream.Recv()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@ -78,6 +83,6 @@ func followLogger() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("failed to fetch log: %s", err)
|
base.Fatalf("failed to fetch log: %s", err)
|
||||||
}
|
}
|
||||||
log.Print(resp.Message)
|
log.Println(resp.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,18 @@ import (
|
|||||||
|
|
||||||
var cmdAddOutbounds = &base.Command{
|
var cmdAddOutbounds = &base.Command{
|
||||||
CustomFlags: true,
|
CustomFlags: true,
|
||||||
UsageLine: "{{.Exec}} api ado [--server=127.0.0.1:8080] <c1.json> [c2.json]...",
|
UsageLine: "{{.Exec}} api ado [--server=127.0.0.1:8080] [c1.json] [dir1]...",
|
||||||
Short: "add outbounds",
|
Short: "add outbounds",
|
||||||
Long: `
|
Long: `
|
||||||
Add outbounds to V2Ray.
|
Add outbounds to V2Ray.
|
||||||
|
|
||||||
|
> Make sure you have "HandlerService" set in "config.api.services"
|
||||||
|
of server config.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
-format <format>
|
-format <format>
|
||||||
Specify the input format.
|
The input format.
|
||||||
Available values: "auto", "json", "toml", "yaml"
|
Available values: "auto", "json", "toml", "yaml"
|
||||||
Default: "auto"
|
Default: "auto"
|
||||||
|
|
||||||
@ -33,7 +36,8 @@ Arguments:
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
{{.Exec}} {{.LongName}} --server=127.0.0.1:8080 c1.json c2.json
|
{{.Exec}} {{.LongName}} dir
|
||||||
|
{{.Exec}} {{.LongName}} c1.json c2.yaml
|
||||||
`,
|
`,
|
||||||
Run: executeAddOutbounds,
|
Run: executeAddOutbounds,
|
||||||
}
|
}
|
||||||
@ -44,7 +48,7 @@ func executeAddOutbounds(cmd *base.Command, args []string) {
|
|||||||
cmd.Flag.Parse(args)
|
cmd.Flag.Parse(args)
|
||||||
c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively)
|
c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("%s", err)
|
base.Fatalf("failed to load: %s", err)
|
||||||
}
|
}
|
||||||
if len(c.OutboundConfigs) == 0 {
|
if len(c.OutboundConfigs) == 0 {
|
||||||
base.Fatalf("no valid outbound found")
|
base.Fatalf("no valid outbound found")
|
||||||
|
@ -10,21 +10,27 @@ import (
|
|||||||
|
|
||||||
var cmdRemoveOutbounds = &base.Command{
|
var cmdRemoveOutbounds = &base.Command{
|
||||||
CustomFlags: true,
|
CustomFlags: true,
|
||||||
UsageLine: "{{.Exec}} api rmo [--server=127.0.0.1:8080] <json_file|tag> [json_file] [tag]...",
|
UsageLine: "{{.Exec}} api rmo [--server=127.0.0.1:8080] [c1.json] [dir1]...",
|
||||||
Short: "remove outbounds",
|
Short: "remove outbounds",
|
||||||
Long: `
|
Long: `
|
||||||
Remove outbounds from V2Ray.
|
Remove outbounds from V2Ray.
|
||||||
|
|
||||||
|
> Make sure you have "HandlerService" set in "config.api.services"
|
||||||
|
of server config.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
-format <format>
|
-format <format>
|
||||||
Specify the input format.
|
The input format.
|
||||||
Available values: "auto", "json", "toml", "yaml"
|
Available values: "auto", "json", "toml", "yaml"
|
||||||
Default: "auto"
|
Default: "auto"
|
||||||
|
|
||||||
-r
|
-r
|
||||||
Load folders recursively.
|
Load folders recursively.
|
||||||
|
|
||||||
|
-tags
|
||||||
|
The input are tags instead of config files
|
||||||
|
|
||||||
-s, -server <server:port>
|
-s, -server <server:port>
|
||||||
The API server address. Default 127.0.0.1:8080
|
The API server address. Default 127.0.0.1:8080
|
||||||
|
|
||||||
@ -33,20 +39,33 @@ Arguments:
|
|||||||
|
|
||||||
Example:
|
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,
|
Run: executeRemoveOutbounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeRemoveOutbounds(cmd *base.Command, args []string) {
|
func executeRemoveOutbounds(cmd *base.Command, args []string) {
|
||||||
setSharedFlags(cmd)
|
setSharedFlags(cmd)
|
||||||
cmd.Flag.Parse(args)
|
|
||||||
setSharedConfigFlags(cmd)
|
setSharedConfigFlags(cmd)
|
||||||
|
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)
|
c, err := helpers.LoadConfig(cmd.Flag.Args(), apiConfigFormat, apiConfigRecursively)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("%s", err)
|
base.Fatalf("failed to load: %s", err)
|
||||||
}
|
}
|
||||||
if len(c.OutboundConfigs) == 0 {
|
tags = make([]string, 0)
|
||||||
|
for _, c := range c.OutboundConfigs {
|
||||||
|
tags = append(tags, c.Tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(tags) == 0 {
|
||||||
base.Fatalf("no outbound to remove")
|
base.Fatalf("no outbound to remove")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,10 +73,10 @@ func executeRemoveOutbounds(cmd *base.Command, args []string) {
|
|||||||
defer close()
|
defer close()
|
||||||
|
|
||||||
client := handlerService.NewHandlerServiceClient(conn)
|
client := handlerService.NewHandlerServiceClient(conn)
|
||||||
for _, c := range c.OutboundConfigs {
|
for _, tag := range tags {
|
||||||
fmt.Println("removing:", c.Tag)
|
fmt.Println("removing:", tag)
|
||||||
r := &handlerService.RemoveOutboundRequest{
|
r := &handlerService.RemoveOutboundRequest{
|
||||||
Tag: c.Tag,
|
Tag: tag,
|
||||||
}
|
}
|
||||||
_, err := client.RemoveOutbound(ctx, r)
|
_, err := client.RemoveOutbound(ctx, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -19,13 +19,16 @@ var cmdStats = &base.Command{
|
|||||||
Long: `
|
Long: `
|
||||||
Query statistics from V2Ray.
|
Query statistics from V2Ray.
|
||||||
|
|
||||||
|
> Make sure you have "StatsService" set in "config.api.services"
|
||||||
|
of server config.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
-regexp
|
-regexp
|
||||||
The patterns are using regexp.
|
The patterns are using regexp.
|
||||||
|
|
||||||
-reset
|
-reset
|
||||||
Fetch values then reset statistics counters to 0.
|
Reset counters to 0 after fetching their values.
|
||||||
|
|
||||||
-runtime
|
-runtime
|
||||||
Get runtime statistics.
|
Get runtime statistics.
|
||||||
|
@ -23,17 +23,17 @@ var cmdConvert = &base.Command{
|
|||||||
Short: "convert config files",
|
Short: "convert config files",
|
||||||
Long: `
|
Long: `
|
||||||
Convert config files between different formats. Files are merged
|
Convert config files between different formats. Files are merged
|
||||||
before convert if multiple assigned.
|
before convert.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
-i, -input <format>
|
-i, -input <format>
|
||||||
Specify the input format.
|
The input format.
|
||||||
Available values: "auto", "json", "toml", "yaml"
|
Available values: "auto", "json", "toml", "yaml"
|
||||||
Default: "auto"
|
Default: "auto"
|
||||||
|
|
||||||
-o, -output <format>
|
-o, -output <format>
|
||||||
Specify the output format
|
The output format
|
||||||
Available values: "json", "toml", "yaml", "protobuf" / "pb"
|
Available values: "json", "toml", "yaml", "protobuf" / "pb"
|
||||||
Default: "json"
|
Default: "json"
|
||||||
|
|
||||||
@ -42,15 +42,15 @@ Arguments:
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
{{.Exec}} {{.LongName}} -output=protobuf config.json (1)
|
{{.Exec}} {{.LongName}} -output=protobuf "path/to/dir" (1)
|
||||||
{{.Exec}} {{.LongName}} -input=toml config.toml (2)
|
{{.Exec}} {{.LongName}} -o=yaml config.toml (2)
|
||||||
{{.Exec}} {{.LongName}} "path/to/dir" (3)
|
{{.Exec}} {{.LongName}} c1.json c2.json (3)
|
||||||
{{.Exec}} {{.LongName}} -i yaml -o protobuf c1.yaml <url>.yaml (4)
|
{{.Exec}} {{.LongName}} -output=yaml c1.yaml <url>.yaml (4)
|
||||||
|
|
||||||
(1) Convert json to protobuf
|
(1) Merge all supported files in dir and convert to protobuf
|
||||||
(2) Convert toml to json
|
(2) Convert toml to yaml
|
||||||
(3) Merge json files in dir
|
(3) Merge json files
|
||||||
(4) Merge yaml files and convert to protobuf
|
(4) Merge yaml files
|
||||||
|
|
||||||
Use "{{.Exec}} help config-merge" for more information about merge.
|
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)
|
m, err := helpers.LoadConfigToMap(cmd.Flag.Args(), inputFormat, confDirRecursively)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf(err.Error())
|
base.Fatalf("failed to merge: %s", err)
|
||||||
}
|
}
|
||||||
err = merge.ApplyRules(m)
|
err = merge.ApplyRules(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf(err.Error())
|
base.Fatalf("failed to apply merge rules: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var out []byte
|
var out []byte
|
||||||
@ -93,17 +93,17 @@ func executeConvert(cmd *base.Command, args []string) {
|
|||||||
case core.FormatJSON:
|
case core.FormatJSON:
|
||||||
out, err = json.Marshal(m)
|
out, err = json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("failed to marshal json: %s", err)
|
base.Fatalf("failed to convert to json: %s", err)
|
||||||
}
|
}
|
||||||
case core.FormatTOML:
|
case core.FormatTOML:
|
||||||
out, err = toml.Marshal(m)
|
out, err = toml.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("failed to marshal json: %s", err)
|
base.Fatalf("failed to convert to toml: %s", err)
|
||||||
}
|
}
|
||||||
case core.FormatYAML:
|
case core.FormatYAML:
|
||||||
out, err = yaml.Marshal(m)
|
out, err = yaml.Marshal(m)
|
||||||
if err != nil {
|
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:
|
case core.FormatProtobuf, core.FormatProtobufShort:
|
||||||
data, err := json.Marshal(m)
|
data, err := json.Marshal(m)
|
||||||
@ -121,7 +121,7 @@ func executeConvert(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
out, err = proto.Marshal(pbConfig)
|
out, err = proto.Marshal(pbConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("failed to marshal proto config: %s", err)
|
base.Fatalf("failed to convert to protobuf: %s", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
base.Errorf("invalid output format: %s", outputFormat)
|
base.Errorf("invalid output format: %s", outputFormat)
|
||||||
|
@ -8,12 +8,12 @@ var docFormat = &base.Command{
|
|||||||
UsageLine: "{{.Exec}} format-loader",
|
UsageLine: "{{.Exec}} format-loader",
|
||||||
Short: "config formats and loading",
|
Short: "config formats and loading",
|
||||||
Long: `
|
Long: `
|
||||||
{{.Exec}} supports different config formats:
|
{{.Exec}} is equipped with multiple loaders to support different
|
||||||
|
config formats:
|
||||||
|
|
||||||
* auto
|
* auto
|
||||||
The default loader, supports all extensions below.
|
The default loader, supports all formats listed below, with
|
||||||
It loads config by format detecting, with mixed
|
format detecting, and mixed fomats support.
|
||||||
formats support.
|
|
||||||
|
|
||||||
* json (.json, .jsonc)
|
* json (.json, .jsonc)
|
||||||
The json loader, multiple files support, mergeable.
|
The json loader, multiple files support, mergeable.
|
||||||
@ -21,14 +21,14 @@ var docFormat = &base.Command{
|
|||||||
* toml (.toml)
|
* toml (.toml)
|
||||||
The toml loader, multiple files support, mergeable.
|
The toml loader, multiple files support, mergeable.
|
||||||
|
|
||||||
* yaml (.yml)
|
* yaml (.yml, .yaml)
|
||||||
The yaml loader, multiple files support, mergeable.
|
The yaml loader, multiple files support, mergeable.
|
||||||
|
|
||||||
* protobuf / pb (.pb)
|
* protobuf / pb (.pb)
|
||||||
Single file support, unmergeable.
|
Single file support, unmergeable.
|
||||||
|
|
||||||
|
|
||||||
The following explains how format loaders behave with examples.
|
The following explains how format loaders behaves.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
@ -25,19 +25,27 @@ var CmdRun = &base.Command{
|
|||||||
Long: `
|
Long: `
|
||||||
Run V2Ray with config.
|
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:
|
Arguments:
|
||||||
|
|
||||||
-c, -config <file>
|
-c, -config <file>
|
||||||
Config file for V2Ray. Multiple assign is accepted.
|
Config file for V2Ray. Multiple assign is accepted.
|
||||||
|
|
||||||
-d, -confdir <dir>
|
-d, -confdir <dir>
|
||||||
A dir with config files. Multiple assign is accepted.
|
A directory with config files. Multiple assign is accepted.
|
||||||
|
|
||||||
-r
|
-r
|
||||||
Load confdir recursively.
|
Load confdir recursively.
|
||||||
|
|
||||||
-format <format>
|
-format <format>
|
||||||
Format of input files. (default "json")
|
Format of config input. (default "auto")
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
@ -16,19 +16,27 @@ var CmdTest = &base.Command{
|
|||||||
Long: `
|
Long: `
|
||||||
Test config files, without launching V2Ray server.
|
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:
|
Arguments:
|
||||||
|
|
||||||
-c, -config <file>
|
-c, -config <file>
|
||||||
Config file for V2Ray. Multiple assign is accepted.
|
Config file for V2Ray. Multiple assign is accepted.
|
||||||
|
|
||||||
-d, -confdir <dir>
|
-d, -confdir <dir>
|
||||||
A dir with config files. Multiple assign is accepted.
|
A directory with config files. Multiple assign is accepted.
|
||||||
|
|
||||||
-r
|
-r
|
||||||
Load confdir recursively.
|
Load confdir recursively.
|
||||||
|
|
||||||
-format <format>
|
-format <format>
|
||||||
Format of input files. (default "json")
|
Format of config input. (default "auto")
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user