trpc.group/trpc-go/trpc-go@v1.0.3/transport/example_test.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package transport_test
    15  
    16  import (
    17  	"bytes"
    18  	"context"
    19  	"encoding/binary"
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"log"
    25  	"time"
    26  
    27  	"trpc.group/trpc-go/trpc-go/errs"
    28  
    29  	"trpc.group/trpc-go/trpc-go/codec"
    30  	"trpc.group/trpc-go/trpc-go/transport"
    31  )
    32  
    33  var defaultStreamID uint32 = 100
    34  
    35  func clientInvokeServer(network string) {
    36  	go func() {
    37  		err := transport.ListenAndServe(
    38  			transport.WithListenNetwork(network),
    39  			transport.WithListenAddress(":8888"),
    40  			transport.WithHandler(&simpleHandler{}),
    41  			transport.WithServerFramerBuilder(&framerBuilder{}),
    42  		)
    43  
    44  		if err != nil {
    45  			log.Fatalln(err)
    46  		}
    47  	}()
    48  
    49  	time.Sleep(time.Millisecond * 10)
    50  
    51  	ctx, f := context.WithTimeout(context.Background(), 3*time.Second)
    52  	defer f()
    53  	req := &helloRequest{
    54  		Name: "trpc",
    55  		Msg:  "HelloWorld",
    56  	}
    57  
    58  	data, err := json.Marshal(req)
    59  	if err != nil {
    60  		log.Fatalln(err)
    61  	}
    62  	lenData := make([]byte, 4)
    63  	binary.BigEndian.PutUint32(lenData, uint32(len(data)))
    64  
    65  	reqData := append(lenData, data...)
    66  
    67  	rspData, err := transport.RoundTrip(ctx, reqData, transport.WithDialNetwork(network),
    68  		transport.WithDialAddress(":8888"),
    69  		transport.WithClientFramerBuilder(&framerBuilder{}))
    70  	if nil != err {
    71  		log.Fatalf("RoundTip Error : %v", err)
    72  	}
    73  
    74  	length := binary.BigEndian.Uint32(rspData[:4])
    75  
    76  	helloRsp := &helloResponse{}
    77  	err = json.Unmarshal(rspData[4:4+length], helloRsp)
    78  	if err != nil {
    79  		log.Fatalln(err)
    80  	}
    81  
    82  	fmt.Println(helloRsp)
    83  
    84  }
    85  
    86  func UDP4TransportExample() {
    87  	clientInvokeServer("udp4")
    88  	// Output:
    89  	// &{trpc HelloWorld 0}
    90  }
    91  
    92  func TCPTransportExample() {
    93  	clientInvokeServer("tcp")
    94  	// Output:
    95  	// &{trpc HelloWorld 0}
    96  }
    97  
    98  type helloRequest struct {
    99  	Name string
   100  	Msg  string
   101  }
   102  
   103  type helloResponse struct {
   104  	Name string
   105  	Msg  string
   106  	Code int
   107  }
   108  
   109  // timeoutError simulates network timeout error.
   110  type timeoutError struct {
   111  }
   112  
   113  // Error implements error.
   114  func (t *timeoutError) Error() string {
   115  	return "Timeout"
   116  }
   117  
   118  // Timeout checks whether is it a timeout error.
   119  func (t *timeoutError) Timeout() bool {
   120  	return true
   121  }
   122  
   123  // Temporary checks whether is it a temporary error.
   124  func (t *timeoutError) Temporary() bool {
   125  	return true
   126  }
   127  
   128  type framerBuilder struct {
   129  	errSet bool
   130  	err    error
   131  	safe   bool
   132  }
   133  
   134  // SetError sets frameBuilder error.
   135  func (fb *framerBuilder) SetError(err error) {
   136  	fb.errSet = true
   137  	fb.err = err
   138  }
   139  
   140  func (fb *framerBuilder) ClearError() {
   141  	fb.errSet = false
   142  	fb.err = nil
   143  }
   144  
   145  func (fb *framerBuilder) New(r io.Reader) codec.Framer {
   146  	return &framer{r: r, fb: fb}
   147  }
   148  
   149  type framer struct {
   150  	fb *framerBuilder
   151  	r  io.Reader
   152  }
   153  
   154  func (f *framer) ReadFrame() ([]byte, error) {
   155  	if f.fb.errSet {
   156  		return nil, f.fb.err
   157  	}
   158  	var lenData [4]byte
   159  
   160  	_, err := io.ReadFull(f.r, lenData[:])
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	length := binary.BigEndian.Uint32(lenData[:])
   166  
   167  	msg := make([]byte, len(lenData)+int(length))
   168  	copy(msg, lenData[:])
   169  
   170  	_, err = io.ReadFull(f.r, msg[len(lenData):])
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	return msg, nil
   176  }
   177  
   178  func (f *framer) IsSafe() bool {
   179  	return f.fb.safe
   180  }
   181  
   182  type errorHandler struct{}
   183  
   184  func (h *errorHandler) Handle(ctx context.Context, req []byte) ([]byte, error) {
   185  	return nil, errors.New("handle error")
   186  }
   187  
   188  type simpleHandler struct{}
   189  
   190  func (h *simpleHandler) Handle(ctx context.Context, reqdata []byte) ([]byte, error) {
   191  
   192  	helloReq := &helloRequest{}
   193  	helloRsp := &helloResponse{}
   194  
   195  	if len(reqdata) < 4 {
   196  		return nil, errors.New("reqData format error")
   197  	}
   198  
   199  	json.Unmarshal(reqdata[4:], helloReq)
   200  
   201  	helloRsp.Name = helloReq.Name
   202  	helloRsp.Msg = helloReq.Msg
   203  	data, _ := json.Marshal(helloRsp)
   204  	buf := new(bytes.Buffer)
   205  	binary.Write(buf, binary.BigEndian, uint32(len(data)))
   206  	binary.Write(buf, binary.BigEndian, data)
   207  	return buf.Bytes(), nil
   208  }
   209  
   210  type echoHandler struct{}
   211  
   212  func (h *echoHandler) Handle(ctx context.Context, req []byte) ([]byte, error) {
   213  	rsp := make([]byte, len(req))
   214  	copy(rsp, req)
   215  	return rsp, nil
   216  }
   217  
   218  type echoStreamHandler struct{}
   219  
   220  func (h *echoStreamHandler) Handle(ctx context.Context, req []byte) ([]byte, error) {
   221  	rsp := make([]byte, len(req))
   222  	copy(rsp, req)
   223  	return rsp, errs.ErrServerNoResponse
   224  }