github.com/eagleql/xray-core@v1.4.4/main/commands/all/convert.go (about) 1 package all 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/http" 9 "net/url" 10 "os" 11 "strings" 12 "time" 13 14 "github.com/eagleql/xray-core/common" 15 "github.com/eagleql/xray-core/common/buf" 16 "github.com/eagleql/xray-core/infra/conf" 17 "github.com/eagleql/xray-core/infra/conf/serial" 18 "github.com/eagleql/xray-core/main/commands/base" 19 "google.golang.org/protobuf/proto" 20 ) 21 22 var cmdConvert = &base.Command{ 23 UsageLine: "{{.Exec}} convert [json file] [json file] ...", 24 Short: "Convert multiple json config to protobuf", 25 Long: ` 26 Convert multiple json config to protobuf. 27 28 Examples: 29 30 {{.Exec}} convert config.json c1.json c2.json <url>.json 31 `, 32 } 33 34 func init() { 35 cmdConvert.Run = executeConvert // break init loop 36 } 37 38 func executeConvert(cmd *base.Command, args []string) { 39 unnamedArgs := cmdConvert.Flag.Args() 40 if len(unnamedArgs) < 1 { 41 base.Fatalf("empty config list") 42 } 43 44 conf := &conf.Config{} 45 for _, arg := range unnamedArgs { 46 fmt.Fprintf(os.Stderr, "Read config: %s", arg) 47 r, err := loadArg(arg) 48 common.Must(err) 49 c, err := serial.DecodeJSONConfig(r) 50 if err != nil { 51 base.Fatalf(err.Error()) 52 } 53 conf.Override(c, arg) 54 } 55 56 pbConfig, err := conf.Build() 57 if err != nil { 58 base.Fatalf(err.Error()) 59 } 60 61 bytesConfig, err := proto.Marshal(pbConfig) 62 if err != nil { 63 base.Fatalf("failed to marshal proto config: %s", err) 64 } 65 66 if _, err := os.Stdout.Write(bytesConfig); err != nil { 67 base.Fatalf("failed to write proto config: %s", err) 68 } 69 } 70 71 // loadArg loads one arg, maybe an remote url, or local file path 72 func loadArg(arg string) (out io.Reader, err error) { 73 var data []byte 74 switch { 75 case strings.HasPrefix(arg, "http://"), strings.HasPrefix(arg, "https://"): 76 data, err = FetchHTTPContent(arg) 77 78 case arg == "stdin:": 79 data, err = ioutil.ReadAll(os.Stdin) 80 81 default: 82 data, err = ioutil.ReadFile(arg) 83 } 84 85 if err != nil { 86 return 87 } 88 out = bytes.NewBuffer(data) 89 return 90 } 91 92 // FetchHTTPContent dials https for remote content 93 func FetchHTTPContent(target string) ([]byte, error) { 94 parsedTarget, err := url.Parse(target) 95 if err != nil { 96 return nil, newError("invalid URL: ", target).Base(err) 97 } 98 99 if s := strings.ToLower(parsedTarget.Scheme); s != "http" && s != "https" { 100 return nil, newError("invalid scheme: ", parsedTarget.Scheme) 101 } 102 103 client := &http.Client{ 104 Timeout: 30 * time.Second, 105 } 106 resp, err := client.Do(&http.Request{ 107 Method: "GET", 108 URL: parsedTarget, 109 Close: true, 110 }) 111 if err != nil { 112 return nil, newError("failed to dial to ", target).Base(err) 113 } 114 defer resp.Body.Close() 115 116 if resp.StatusCode != 200 { 117 return nil, newError("unexpected HTTP status code: ", resp.StatusCode) 118 } 119 120 content, err := buf.ReadAllToBytes(resp.Body) 121 if err != nil { 122 return nil, newError("failed to read HTTP response").Base(err) 123 } 124 125 return content, nil 126 }