github.com/nyan233/littlerpc@v0.4.6-0.20230316182519-0c8d5c48abaf/cmd/lrpcurl/rpcurl.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"github.com/nyan233/littlerpc/cmd/lrpcurl/proxy"
     8  	"github.com/nyan233/littlerpc/core/client"
     9  	"github.com/nyan233/littlerpc/core/common/logger"
    10  	"github.com/nyan233/littlerpc/core/server"
    11  	"github.com/nyan233/littlerpc/core/utils/convert"
    12  	flag "github.com/spf13/pflag"
    13  	"io"
    14  	"log"
    15  	"os"
    16  	"os/signal"
    17  	"strings"
    18  	"syscall"
    19  	"unsafe"
    20  )
    21  
    22  type Caller interface {
    23  	RawCall(service string, opts []client.CallOption, args ...interface{}) (reps []interface{}, err error)
    24  }
    25  
    26  type OutType string
    27  
    28  const (
    29  	FormatJson OutType = "format_json"
    30  	Json       OutType = "json"
    31  	Text       OutType = "text"
    32  )
    33  
    34  const (
    35  	GetAllSupportOption = "get_all_support_option"
    36  	GetAllInstance      = "get_all_instance"
    37  	GetAllCodec         = "get_all_codec"
    38  	GetAllPacker        = "get_all_packer"
    39  	GetMethodTable      = "get_method_table"
    40  	GetArgumentType     = "get_argument_type"
    41  	CallFunc            = "call_func"
    42  )
    43  
    44  var (
    45  	allSupportOption = []string{
    46  		GetAllCodec, GetAllPacker, GetAllInstance, GetMethodTable, GetArgumentType, CallFunc,
    47  	}
    48  )
    49  
    50  var (
    51  	serverAddr = flag.StringP("address", "a", "127.0.0.1:9090", "服务器地址,Example: 127.0.0.1:9090")
    52  	source     = flag.StringP("source", "i", server.ReflectionSource, "资源的名称,注册方法时指定的实例名称")
    53  	option     = flag.StringP("option", "o", "get_all_instance", "操作, get_all_support_option -> 获取所有支持的操作了解更多")
    54  	service    = flag.StringP("service", "s", "Hello.Hello", "调用的目标: InstanceName.MethodName")
    55  	outType    = flag.StringP("out_type", "t", string(FormatJson), "输出的信息的格式(format_json/json/text)")
    56  	call       = flag.StringP("call", "c", "null", "调用传递的参数(不包括context/stream): [100,\"hh\"]")
    57  )
    58  
    59  func main() {
    60  	flag.Parse()
    61  	logger.SetOpenLogger(false)
    62  	c := dial()
    63  	defer c.Close()
    64  	ctx, cancel := context.WithCancel(context.Background())
    65  	channel := make(chan os.Signal)
    66  	signal.Notify(channel, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM)
    67  	go func() {
    68  		select {
    69  		case <-channel:
    70  			cancel()
    71  		}
    72  	}()
    73  	parserOption(ctx, proxy.NewLittleRpcReflection(c), c)
    74  }
    75  
    76  func parserOption(ctx context.Context, proxy proxy.LittleRpcReflectionProxy, caller Caller) {
    77  	switch *option {
    78  	case GetAllSupportOption:
    79  		getAllSupportOption(OutType(*outType), os.Stdout)
    80  	case GetAllCodec:
    81  		getAllCodec(ctx, proxy, OutType(*outType), os.Stdout)
    82  	case GetAllPacker:
    83  		getAllPacker(ctx, proxy, OutType(*outType), os.Stdout)
    84  	case GetAllInstance:
    85  		getAllInstance(ctx, proxy, OutType(*outType), os.Stdout)
    86  	case GetArgumentType:
    87  		getArgType(ctx, proxy, *service, OutType(*outType), os.Stdout)
    88  	case GetMethodTable:
    89  		getMethodTable(ctx, proxy, *source, OutType(*outType), os.Stdout)
    90  	case CallFunc:
    91  		var rawArgs []json.RawMessage
    92  		err := json.Unmarshal(convert.StringToBytes(*call), &rawArgs)
    93  		if err != nil {
    94  			log.Fatalln(err)
    95  		}
    96  		callFunc(ctx, caller, *service, *(*[][]byte)(unsafe.Pointer(&rawArgs)), OutType(*outType), os.Stdout)
    97  	default:
    98  		log.Fatalln("no implement option")
    99  	}
   100  }
   101  
   102  func dial() *client.Client {
   103  	c, err := client.New(
   104  		client.WithCustomLogger(logger.NilLogger{}),
   105  		client.WithNoMuxWriter(),
   106  		client.WithMuxConnection(false),
   107  		client.WithProtocol("std_tcp"),
   108  		client.WithStackTrace(),
   109  		client.WithAddress(*serverAddr),
   110  	)
   111  	*call = strings.TrimPrefix(*call, "\xef\xbb\xbf")
   112  	if err != nil {
   113  		panic(err)
   114  	}
   115  	return c
   116  }
   117  
   118  func getAllSupportOption(ot OutType, w io.Writer) {
   119  	switch ot {
   120  	case Text:
   121  		for _, option := range allSupportOption {
   122  			_, _ = fmt.Fprintln(w, option)
   123  		}
   124  	default:
   125  		anyOutFromJson(allSupportOption, ot, w)
   126  	}
   127  }
   128  
   129  func getAllInstance(ctx context.Context, proxy proxy.LittleRpcReflectionProxy, ot OutType, w io.Writer) {
   130  	instances, err := proxy.AllInstance(ctx)
   131  	if err != nil {
   132  		log.Fatalln(err)
   133  	}
   134  	switch ot {
   135  	case Text:
   136  		for k, v := range instances {
   137  			_, _ = fmt.Fprintf(w, "%s --> %s\n", k, v)
   138  		}
   139  	default:
   140  		anyOutFromJson(instances, ot, w)
   141  	}
   142  }
   143  
   144  func getArgType(ctx context.Context, proxy proxy.LittleRpcReflectionProxy, service string, ot OutType, w io.Writer) {
   145  	argType, err := proxy.MethodArgumentType(ctx, service)
   146  	if err != nil {
   147  		log.Fatalln(err)
   148  	}
   149  	switch ot {
   150  	case Text:
   151  		if argType == nil || len(argType) == 0 {
   152  			return
   153  		}
   154  		for _, v := range argType {
   155  			anyOutFromJson(v, Json, w)
   156  		}
   157  	default:
   158  		anyOutFromJson(argType, ot, w)
   159  	}
   160  }
   161  
   162  func getMethodTable(ctx context.Context, proxy proxy.LittleRpcReflectionProxy, sourceName string, ot OutType, w io.Writer) {
   163  	tab, err := proxy.MethodTable(ctx, sourceName)
   164  	if err != nil {
   165  		log.Fatalln(err)
   166  	}
   167  	if tab == nil {
   168  		return
   169  	}
   170  	switch ot {
   171  	case Text:
   172  		break
   173  	default:
   174  		anyOutFromJson(tab, ot, w)
   175  	}
   176  }
   177  
   178  func getAllPacker(ctx context.Context, proxy proxy.LittleRpcReflectionProxy, ot OutType, w io.Writer) {
   179  	packers, err := proxy.AllPacker(ctx)
   180  	if err != nil {
   181  		log.Fatalln(err)
   182  	}
   183  	switch ot {
   184  	case Text:
   185  		if packers == nil {
   186  			return
   187  		}
   188  		for _, packer := range packers {
   189  			_, _ = fmt.Fprintln(w, packer)
   190  		}
   191  	default:
   192  		anyOutFromJson(packers, ot, w)
   193  	}
   194  }
   195  
   196  func getAllCodec(ctx context.Context, proxy proxy.LittleRpcReflectionProxy, ot OutType, w io.Writer) {
   197  	codecs, err := proxy.AllCodec(ctx)
   198  	if err != nil {
   199  		log.Fatalln(err)
   200  	}
   201  	switch ot {
   202  	case Text:
   203  		if codecs == nil {
   204  			return
   205  		}
   206  		for _, codec := range codecs {
   207  			_, _ = fmt.Fprintln(w, codec)
   208  		}
   209  	default:
   210  		anyOutFromJson(codecs, ot, w)
   211  	}
   212  }
   213  
   214  func anyOutFromJson(data any, ot OutType, w io.Writer) {
   215  	switch ot {
   216  	case FormatJson:
   217  		bytes, err := json.MarshalIndent(data, "", "\t")
   218  		if err != nil {
   219  			log.Fatalln(err)
   220  		}
   221  		_, _ = fmt.Fprintln(w, string(bytes))
   222  	case Json:
   223  		bytes, err := json.Marshal(data)
   224  		if err != nil {
   225  			log.Fatalln(err)
   226  		}
   227  		_, _ = fmt.Fprintln(w, string(bytes))
   228  	default:
   229  		log.Fatalln("invalid output format")
   230  	}
   231  }
   232  
   233  func callFunc(ctx context.Context, c Caller, service string, argsBytes [][]byte, ot OutType, w io.Writer) {
   234  	args := make([]interface{}, len(argsBytes)+1)
   235  	args[0] = ctx
   236  	for k, rawArg := range argsBytes {
   237  		err := json.Unmarshal(rawArg, &args[k+1])
   238  		if err != nil {
   239  			log.Fatalln(err)
   240  		}
   241  	}
   242  	reps, err := c.RawCall(service, nil, args...)
   243  	reps = append(reps, err)
   244  	switch ot {
   245  	case Text:
   246  		for _, rep := range reps {
   247  			bytes, err := json.Marshal(rep)
   248  			if err != nil {
   249  				log.Fatalln(err)
   250  			}
   251  			_, _ = fmt.Fprintln(w, string(bytes))
   252  		}
   253  	default:
   254  		anyOutFromJson(reps, ot, w)
   255  	}
   256  }