1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-28 02:05:23 +00:00

mconfig subcommand ready

This commit is contained in:
vcptr 2019-12-14 21:43:47 +08:00
parent 7b289d16cf
commit 904db6bd61
7 changed files with 135 additions and 22 deletions

View File

@ -119,6 +119,15 @@ func CreateStdoutLogWriter() WriterCreator {
} }
} }
// CreateStderrLogWriter returns a LogWriterCreator that creates LogWriter for stderr.
func CreateStderrLogWriter() WriterCreator {
return func() Writer {
return &consoleLogWriter{
logger: log.New(os.Stderr, "", log.Ldate|log.Ltime),
}
}
}
// CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file. // CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file.
func CreateFileLogWriter(path string) (WriterCreator, error) { func CreateFileLogWriter(path string) (WriterCreator, error) {
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)

View File

@ -39,6 +39,9 @@ func Run(args []string, input io.Reader) (buf.MultiBuffer, error) {
} }
return nil, newError(msg).Base(err) return nil, newError(msg).Base(err)
} }
if !errBuffer.IsEmpty() {
newError("v2ctl > ", errBuffer.String()).AtInfo().WriteToLog()
}
return outBuffer.MultiBuffer, nil return outBuffer.MultiBuffer, nil
} }

View File

@ -38,7 +38,7 @@ func findOffset(b []byte, o int) *offset {
return &offset{line: line, char: char} return &offset{line: line, char: char}
} }
func LoadJSONConfig(reader io.Reader) (*core.Config, error) { func DecodeJSONConfig(reader io.Reader) (*conf.Config, error) {
jsonConfig := &conf.Config{} jsonConfig := &conf.Config{}
jsonContent := bytes.NewBuffer(make([]byte, 0, 10240)) jsonContent := bytes.NewBuffer(make([]byte, 0, 10240))
@ -62,6 +62,15 @@ func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
return nil, newError("failed to read config file").Base(err) return nil, newError("failed to read config file").Base(err)
} }
return jsonConfig, nil
}
func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
jsonConfig, err := DecodeJSONConfig(reader)
if err != nil {
return nil, err
}
pbConfig, err := jsonConfig.Build() pbConfig, err := jsonConfig.Build()
if err != nil { if err != nil {
return nil, newError("failed to parse json config").Base(err) return nil, newError("failed to parse json config").Base(err)

View File

@ -327,7 +327,7 @@ func (c *Config) findOutboundTag(tag string) int {
} }
// Override method accepts another Config overrides the current attribute // Override method accepts another Config overrides the current attribute
func (c *Config) Override(o *Config) { func (c *Config) Override(o *Config, fn string) {
// only process the non-deprecated members // only process the non-deprecated members
@ -361,9 +361,10 @@ func (c *Config) Override(o *Config) {
if len(c.InboundConfigs) > 0 && len(o.InboundConfigs) == 1 { if len(c.InboundConfigs) > 0 && len(o.InboundConfigs) == 1 {
if idx := c.findInboundTag(o.InboundConfigs[0].Tag); idx > -1 { if idx := c.findInboundTag(o.InboundConfigs[0].Tag); idx > -1 {
c.InboundConfigs[idx] = o.InboundConfigs[0] c.InboundConfigs[idx] = o.InboundConfigs[0]
newError("updated inbound with tag: ", o.InboundConfigs[0].Tag).AtInfo().WriteToLog() newError("<", fn, "> updated inbound with tag: ", o.InboundConfigs[0].Tag).AtInfo().WriteToLog()
} else { } else {
c.InboundConfigs = append(c.InboundConfigs, o.InboundConfigs[0]) c.InboundConfigs = append(c.InboundConfigs, o.InboundConfigs[0])
newError("<", fn, "> appended inbound with tag: ", o.InboundConfigs[0].Tag).AtInfo().WriteToLog()
} }
} else { } else {
c.InboundConfigs = o.InboundConfigs c.InboundConfigs = o.InboundConfigs
@ -375,8 +376,10 @@ func (c *Config) Override(o *Config) {
if len(c.OutboundConfigs) > 0 && len(o.OutboundConfigs) == 1 { if len(c.OutboundConfigs) > 0 && len(o.OutboundConfigs) == 1 {
if idx := c.findOutboundTag(o.OutboundConfigs[0].Tag); idx > -1 { if idx := c.findOutboundTag(o.OutboundConfigs[0].Tag); idx > -1 {
c.OutboundConfigs[idx] = o.OutboundConfigs[0] c.OutboundConfigs[idx] = o.OutboundConfigs[0]
newError("<", fn, "> updated outbound with tag: ", o.OutboundConfigs[0].Tag).AtInfo().WriteToLog()
} else { } else {
c.OutboundConfigs = append(c.OutboundConfigs, o.OutboundConfigs[0]) c.OutboundConfigs = append(c.OutboundConfigs, o.OutboundConfigs[0])
newError("<", fn, "> updated outbound with tag: ", o.OutboundConfigs[0].Tag).AtInfo().WriteToLog()
} }
} else { } else {
c.OutboundConfigs = o.OutboundConfigs c.OutboundConfigs = o.OutboundConfigs

View File

@ -5,6 +5,7 @@ import (
"net/url" "net/url"
"os" "os"
"strings" "strings"
"time"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
@ -23,46 +24,53 @@ func (c *FetchCommand) Description() Description {
} }
} }
func (c *FetchCommand) isValidScheme(scheme string) bool {
scheme = strings.ToLower(scheme)
return scheme == "http" || scheme == "https"
}
func (c *FetchCommand) Execute(args []string) error { func (c *FetchCommand) Execute(args []string) error {
if len(args) < 1 { if len(args) < 1 {
return newError("empty url") return newError("empty url")
} }
target := args[0] content, err := FetchHTTPContent(args[0])
parsedTarget, err := url.Parse(target)
if err != nil { if err != nil {
return newError("invalid URL: ", target).Base(err) return newError("failed to read HTTP response").Base(err)
}
if !c.isValidScheme(parsedTarget.Scheme) {
return newError("invalid scheme: ", parsedTarget.Scheme)
} }
client := &http.Client{} os.Stdout.Write(content)
return nil
}
func FetchHTTPContent(target string) ([]byte, error) {
parsedTarget, err := url.Parse(target)
if err != nil {
return nil, newError("invalid URL: ", target).Base(err)
}
if s := strings.ToLower(parsedTarget.Scheme); s != "http" && s != "https" {
return nil, newError("invalid scheme: ", parsedTarget.Scheme)
}
client := &http.Client{
Timeout: 30 * time.Second,
}
resp, err := client.Do(&http.Request{ resp, err := client.Do(&http.Request{
Method: "GET", Method: "GET",
URL: parsedTarget, URL: parsedTarget,
Close: true, Close: true,
}) })
if err != nil { if err != nil {
return newError("failed to dial to ", target).Base(err) return nil, newError("failed to dial to ", target).Base(err)
} }
defer resp.Body.Close()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
return newError("unexpected HTTP status code: ", resp.StatusCode) return nil, newError("unexpected HTTP status code: ", resp.StatusCode)
} }
content, err := buf.ReadAllToBytes(resp.Body) content, err := buf.ReadAllToBytes(resp.Body)
if err != nil { if err != nil {
return newError("failed to read HTTP response").Base(err) return nil, newError("failed to read HTTP response").Base(err)
} }
os.Stdout.Write(content) return content, nil
return nil
} }
func init() { func init() {

View File

@ -5,7 +5,8 @@ import (
"fmt" "fmt"
"os" "os"
_ "v2ray.com/core/infra/conf/command" commlog "v2ray.com/core/common/log"
// _ "v2ray.com/core/infra/conf/command"
"v2ray.com/core/infra/control" "v2ray.com/core/infra/control"
) )
@ -17,6 +18,8 @@ func getCommandName() string {
} }
func main() { func main() {
// let the v2ctl prints log at stderr
commlog.RegisterHandler(commlog.NewLogger(commlog.CreateStderrLogWriter()))
name := getCommandName() name := getCommandName()
cmd := control.GetCommand(name) cmd := control.GetCommand(name)
if cmd == nil { if cmd == nil {

78
infra/control/mconfig.go Normal file
View File

@ -0,0 +1,78 @@
package control
import (
"bytes"
"io"
"io/ioutil"
"os"
"strings"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common"
"v2ray.com/core/infra/conf"
"v2ray.com/core/infra/conf/serial"
)
type MconfigCommand struct{}
func (c *MconfigCommand) Name() string {
return "mconfig"
}
func (c *MconfigCommand) Description() Description {
return Description{
Short: "merge multiple json config",
Usage: []string{"v2ctl mconfig 1.json 2.json <url>.json"},
}
}
func (c *MconfigCommand) Execute(args []string) error {
if len(args) < 1 {
return newError("empty config list")
}
conf := &conf.Config{}
for _, arg := range args {
r, err := c.LoadArg(arg)
common.Must(err)
c, err := serial.DecodeJSONConfig(r)
common.Must(err)
conf.Override(c, arg)
}
pbConfig, err := conf.Build()
if err != nil {
return err
}
bytesConfig, err := proto.Marshal(pbConfig)
if err != nil {
return newError("failed to marshal proto config").Base(err)
}
if _, err := os.Stdout.Write(bytesConfig); err != nil {
return newError("failed to write proto config").Base(err)
}
return nil
}
func (c *MconfigCommand) LoadArg(arg string) (out io.Reader, err error) {
var data []byte
if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") {
data, err = FetchHTTPContent(arg)
} else {
data, err = ioutil.ReadFile(arg)
}
if err != nil {
return
}
out = bytes.NewBuffer(data)
return
}
func init() {
common.Must(RegisterCommand(&MconfigCommand{}))
}