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