Xray-core/main/commands/all/api/shared.go

134 lines
2.8 KiB
Go
Raw Normal View History

2020-12-04 04:36:16 +03:00
package api
import (
"bytes"
"context"
2020-12-04 18:35:08 +03:00
"encoding/json"
2020-12-04 04:36:16 +03:00
"fmt"
"io"
"net/http"
"net/url"
"os"
2020-12-04 18:35:08 +03:00
"reflect"
2020-12-04 04:36:16 +03:00
"strings"
"time"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/main/commands/base"
2022-05-18 10:29:01 +03:00
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
2020-12-04 04:36:16 +03:00
)
type serviceHandler func(ctx context.Context, conn *grpc.ClientConn, cmd *base.Command, args []string) string
var (
apiServerAddrPtr string
apiTimeout int
)
func setSharedFlags(cmd *base.Command) {
cmd.Flag.StringVar(&apiServerAddrPtr, "s", "127.0.0.1:8080", "")
cmd.Flag.StringVar(&apiServerAddrPtr, "server", "127.0.0.1:8080", "")
cmd.Flag.IntVar(&apiTimeout, "t", 3, "")
cmd.Flag.IntVar(&apiTimeout, "timeout", 3, "")
}
func dialAPIServer() (conn *grpc.ClientConn, ctx context.Context, close func()) {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(apiTimeout)*time.Second)
conn, err := grpc.DialContext(ctx, apiServerAddrPtr, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
base.Fatalf("failed to dial %s", apiServerAddrPtr)
}
close = func() {
cancel()
conn.Close()
}
return
}
// loadArg loads one arg, maybe an remote url, or local file path
func loadArg(arg string) (out io.Reader, err error) {
var data []byte
switch {
case strings.HasPrefix(arg, "http://"), strings.HasPrefix(arg, "https://"):
data, err = fetchHTTPContent(arg)
case arg == "stdin:":
data, err = io.ReadAll(os.Stdin)
2020-12-04 04:36:16 +03:00
default:
data, err = os.ReadFile(arg)
2020-12-04 04:36:16 +03:00
}
if err != nil {
return
}
out = bytes.NewBuffer(data)
return
}
// fetchHTTPContent dials https for remote content
func fetchHTTPContent(target string) ([]byte, error) {
parsedTarget, err := url.Parse(target)
if err != nil {
return nil, err
}
if s := strings.ToLower(parsedTarget.Scheme); s != "http" && s != "https" {
return nil, fmt.Errorf("invalid scheme: %s", 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 nil, fmt.Errorf("failed to dial to %s", target)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("unexpected HTTP status code: %d", resp.StatusCode)
}
content, err := buf.ReadAllToBytes(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read HTTP response")
}
return content, nil
}
func showResponese(m proto.Message) {
if isNil(m) {
return
}
2020-12-05 03:36:16 +03:00
b := new(strings.Builder)
e := json.NewEncoder(b)
e.SetIndent("", " ")
e.SetEscapeHTML(false)
err := e.Encode(m)
2020-12-04 04:36:16 +03:00
msg := ""
if err != nil {
msg = fmt.Sprintf("error: %s\n\n%v", err, m)
2020-12-04 04:36:16 +03:00
} else {
msg = strings.TrimSpace(b.String())
2020-12-04 04:36:16 +03:00
}
if msg == "" {
return
}
fmt.Println(msg)
}
func isNil(i interface{}) bool {
vi := reflect.ValueOf(i)
if vi.Kind() == reflect.Ptr {
return vi.IsNil()
}
return i == nil
}