1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-10 18:00:43 +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.
func CreateFileLogWriter(path string) (WriterCreator, error) {
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)
}
if !errBuffer.IsEmpty() {
newError("v2ctl > ", errBuffer.String()).AtInfo().WriteToLog()
}
return outBuffer.MultiBuffer, nil
}

View File

@ -38,7 +38,7 @@ func findOffset(b []byte, o int) *offset {
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{}
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 jsonConfig, nil
}
func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
jsonConfig, err := DecodeJSONConfig(reader)
if err != nil {
return nil, err
}
pbConfig, err := jsonConfig.Build()
if err != nil {
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
func (c *Config) Override(o *Config) {
func (c *Config) Override(o *Config, fn string) {
// 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 idx := c.findInboundTag(o.InboundConfigs[0].Tag); idx > -1 {
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 {
c.InboundConfigs = append(c.InboundConfigs, o.InboundConfigs[0])
newError("<", fn, "> appended inbound with tag: ", o.InboundConfigs[0].Tag).AtInfo().WriteToLog()
}
} else {
c.InboundConfigs = o.InboundConfigs
@ -375,8 +376,10 @@ func (c *Config) Override(o *Config) {
if len(c.OutboundConfigs) > 0 && len(o.OutboundConfigs) == 1 {
if idx := c.findOutboundTag(o.OutboundConfigs[0].Tag); idx > -1 {
c.OutboundConfigs[idx] = o.OutboundConfigs[0]
newError("<", fn, "> updated outbound with tag: ", o.OutboundConfigs[0].Tag).AtInfo().WriteToLog()
} else {
c.OutboundConfigs = append(c.OutboundConfigs, o.OutboundConfigs[0])
newError("<", fn, "> updated outbound with tag: ", o.OutboundConfigs[0].Tag).AtInfo().WriteToLog()
}
} else {
c.OutboundConfigs = o.OutboundConfigs

View File

@ -5,6 +5,7 @@ import (
"net/url"
"os"
"strings"
"time"
"v2ray.com/core/common"
"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 {
if len(args) < 1 {
return newError("empty url")
}
target := args[0]
parsedTarget, err := url.Parse(target)
content, err := FetchHTTPContent(args[0])
if err != nil {
return newError("invalid URL: ", target).Base(err)
}
if !c.isValidScheme(parsedTarget.Scheme) {
return newError("invalid scheme: ", parsedTarget.Scheme)
return newError("failed to read HTTP response").Base(err)
}
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{
Method: "GET",
URL: parsedTarget,
Close: true,
})
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 {
return newError("unexpected HTTP status code: ", resp.StatusCode)
return nil, newError("unexpected HTTP status code: ", resp.StatusCode)
}
content, err := buf.ReadAllToBytes(resp.Body)
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 nil
return content, nil
}
func init() {

View File

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