github.com/xraypb/Xray-core@v1.8.1/main/commands/all/api/shared.go (about)

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"net/url"
    10  	"os"
    11  	"reflect"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/xraypb/Xray-core/common/buf"
    16  	"github.com/xraypb/Xray-core/main/commands/base"
    17  	"google.golang.org/grpc"
    18  	"google.golang.org/protobuf/encoding/protojson"
    19  	"google.golang.org/protobuf/proto"
    20  )
    21  
    22  type serviceHandler func(ctx context.Context, conn *grpc.ClientConn, cmd *base.Command, args []string) string
    23  
    24  var (
    25  	apiServerAddrPtr string
    26  	apiTimeout       int
    27  )
    28  
    29  func setSharedFlags(cmd *base.Command) {
    30  	cmd.Flag.StringVar(&apiServerAddrPtr, "s", "127.0.0.1:8080", "")
    31  	cmd.Flag.StringVar(&apiServerAddrPtr, "server", "127.0.0.1:8080", "")
    32  	cmd.Flag.IntVar(&apiTimeout, "t", 3, "")
    33  	cmd.Flag.IntVar(&apiTimeout, "timeout", 3, "")
    34  }
    35  
    36  func dialAPIServer() (conn *grpc.ClientConn, ctx context.Context, close func()) {
    37  	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(apiTimeout)*time.Second)
    38  	conn, err := grpc.DialContext(ctx, apiServerAddrPtr, grpc.WithInsecure(), grpc.WithBlock())
    39  	if err != nil {
    40  		base.Fatalf("failed to dial %s", apiServerAddrPtr)
    41  	}
    42  	close = func() {
    43  		cancel()
    44  		conn.Close()
    45  	}
    46  	return
    47  }
    48  
    49  // loadArg loads one arg, maybe an remote url, or local file path
    50  func loadArg(arg string) (out io.Reader, err error) {
    51  	var data []byte
    52  	switch {
    53  	case strings.HasPrefix(arg, "http://"), strings.HasPrefix(arg, "https://"):
    54  		data, err = fetchHTTPContent(arg)
    55  
    56  	case arg == "stdin:":
    57  		data, err = io.ReadAll(os.Stdin)
    58  
    59  	default:
    60  		data, err = os.ReadFile(arg)
    61  	}
    62  
    63  	if err != nil {
    64  		return
    65  	}
    66  	out = bytes.NewBuffer(data)
    67  	return
    68  }
    69  
    70  // fetchHTTPContent dials https for remote content
    71  func fetchHTTPContent(target string) ([]byte, error) {
    72  	parsedTarget, err := url.Parse(target)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	if s := strings.ToLower(parsedTarget.Scheme); s != "http" && s != "https" {
    78  		return nil, fmt.Errorf("invalid scheme: %s", parsedTarget.Scheme)
    79  	}
    80  
    81  	client := &http.Client{
    82  		Timeout: 30 * time.Second,
    83  	}
    84  	resp, err := client.Do(&http.Request{
    85  		Method: "GET",
    86  		URL:    parsedTarget,
    87  		Close:  true,
    88  	})
    89  	if err != nil {
    90  		return nil, fmt.Errorf("failed to dial to %s", target)
    91  	}
    92  	defer resp.Body.Close()
    93  
    94  	if resp.StatusCode != 200 {
    95  		return nil, fmt.Errorf("unexpected HTTP status code: %d", resp.StatusCode)
    96  	}
    97  
    98  	content, err := buf.ReadAllToBytes(resp.Body)
    99  	if err != nil {
   100  		return nil, fmt.Errorf("failed to read HTTP response")
   101  	}
   102  
   103  	return content, nil
   104  }
   105  
   106  func protoToJSONString(m proto.Message, _, indent string) (string, error) {
   107  	ops := protojson.MarshalOptions{
   108  		Indent:          indent,
   109  		EmitUnpopulated: true,
   110  	}
   111  	b, err := ops.Marshal(m)
   112  	return string(b), err
   113  }
   114  
   115  func showJSONResponse(m proto.Message) {
   116  	if isNil(m) {
   117  		return
   118  	}
   119  	output, err := protoToJSONString(m, "", "    ")
   120  	if err != nil {
   121  		fmt.Fprintf(os.Stdout, "%v\n", m)
   122  		base.Fatalf("error encode json: %s", err)
   123  	}
   124  	fmt.Println(output)
   125  }
   126  
   127  func isNil(i interface{}) bool {
   128  	vi := reflect.ValueOf(i)
   129  	if vi.Kind() == reflect.Ptr {
   130  		return vi.IsNil()
   131  	}
   132  	return i == nil
   133  }