mirror of https://github.com/v2ray/v2ray-core
				
				
				
			mconfig subcommand ready
							parent
							
								
									7b289d16cf
								
							
						
					
					
						commit
						904db6bd61
					
				| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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{}))
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue