github.com/annwntech/go-micro/v2@v2.9.5/client/rpc_codec.go (about)

     1  package client
     2  
     3  import (
     4  	"bytes"
     5  	errs "errors"
     6  
     7  	"github.com/annwntech/go-micro/v2/codec"
     8  	raw "github.com/annwntech/go-micro/v2/codec/bytes"
     9  	"github.com/annwntech/go-micro/v2/codec/grpc"
    10  	"github.com/annwntech/go-micro/v2/codec/json"
    11  	"github.com/annwntech/go-micro/v2/codec/jsonrpc"
    12  	"github.com/annwntech/go-micro/v2/codec/proto"
    13  	"github.com/annwntech/go-micro/v2/codec/protorpc"
    14  	"github.com/annwntech/go-micro/v2/errors"
    15  	"github.com/annwntech/go-micro/v2/registry"
    16  	"github.com/annwntech/go-micro/v2/transport"
    17  )
    18  
    19  const (
    20  	lastStreamResponseError = "EOS"
    21  )
    22  
    23  // serverError represents an error that has been returned from
    24  // the remote side of the RPC connection.
    25  type serverError string
    26  
    27  func (e serverError) Error() string {
    28  	return string(e)
    29  }
    30  
    31  // errShutdown holds the specific error for closing/closed connections
    32  var (
    33  	errShutdown = errs.New("connection is shut down")
    34  )
    35  
    36  type rpcCodec struct {
    37  	client transport.Client
    38  	codec  codec.Codec
    39  
    40  	req *transport.Message
    41  	buf *readWriteCloser
    42  
    43  	// signify if its a stream
    44  	stream string
    45  }
    46  
    47  type readWriteCloser struct {
    48  	wbuf *bytes.Buffer
    49  	rbuf *bytes.Buffer
    50  }
    51  
    52  var (
    53  	DefaultContentType = "application/protobuf"
    54  
    55  	DefaultCodecs = map[string]codec.NewCodec{
    56  		"application/grpc":         grpc.NewCodec,
    57  		"application/grpc+json":    grpc.NewCodec,
    58  		"application/grpc+proto":   grpc.NewCodec,
    59  		"application/protobuf":     proto.NewCodec,
    60  		"application/json":         json.NewCodec,
    61  		"application/json-rpc":     jsonrpc.NewCodec,
    62  		"application/proto-rpc":    protorpc.NewCodec,
    63  		"application/octet-stream": raw.NewCodec,
    64  	}
    65  
    66  	// TODO: remove legacy codec list
    67  	defaultCodecs = map[string]codec.NewCodec{
    68  		"application/json":         jsonrpc.NewCodec,
    69  		"application/json-rpc":     jsonrpc.NewCodec,
    70  		"application/protobuf":     protorpc.NewCodec,
    71  		"application/proto-rpc":    protorpc.NewCodec,
    72  		"application/octet-stream": protorpc.NewCodec,
    73  	}
    74  )
    75  
    76  func (rwc *readWriteCloser) Read(p []byte) (n int, err error) {
    77  	return rwc.rbuf.Read(p)
    78  }
    79  
    80  func (rwc *readWriteCloser) Write(p []byte) (n int, err error) {
    81  	return rwc.wbuf.Write(p)
    82  }
    83  
    84  func (rwc *readWriteCloser) Close() error {
    85  	rwc.rbuf.Reset()
    86  	rwc.wbuf.Reset()
    87  	return nil
    88  }
    89  
    90  func getHeaders(m *codec.Message) {
    91  	set := func(v, hdr string) string {
    92  		if len(v) > 0 {
    93  			return v
    94  		}
    95  		return m.Header[hdr]
    96  	}
    97  
    98  	// check error in header
    99  	m.Error = set(m.Error, "Micro-Error")
   100  
   101  	// check endpoint in header
   102  	m.Endpoint = set(m.Endpoint, "Micro-Endpoint")
   103  
   104  	// check method in header
   105  	m.Method = set(m.Method, "Micro-Method")
   106  
   107  	// set the request id
   108  	m.Id = set(m.Id, "Micro-Id")
   109  }
   110  
   111  func setHeaders(m *codec.Message, stream string) {
   112  	set := func(hdr, v string) {
   113  		if len(v) == 0 {
   114  			return
   115  		}
   116  		m.Header[hdr] = v
   117  	}
   118  
   119  	set("Micro-Id", m.Id)
   120  	set("Micro-Service", m.Target)
   121  	set("Micro-Method", m.Method)
   122  	set("Micro-Endpoint", m.Endpoint)
   123  	set("Micro-Error", m.Error)
   124  
   125  	if len(stream) > 0 {
   126  		set("Micro-Stream", stream)
   127  	}
   128  }
   129  
   130  // setupProtocol sets up the old protocol
   131  func setupProtocol(msg *transport.Message, node *registry.Node) codec.NewCodec {
   132  	protocol := node.Metadata["protocol"]
   133  
   134  	// got protocol
   135  	if len(protocol) > 0 {
   136  		return nil
   137  	}
   138  
   139  	// processing topic publishing
   140  	if len(msg.Header["Micro-Topic"]) > 0 {
   141  		return nil
   142  	}
   143  
   144  	// no protocol use old codecs
   145  	switch msg.Header["Content-Type"] {
   146  	case "application/json":
   147  		msg.Header["Content-Type"] = "application/json-rpc"
   148  	case "application/protobuf":
   149  		msg.Header["Content-Type"] = "application/proto-rpc"
   150  	}
   151  
   152  	// now return codec
   153  	return defaultCodecs[msg.Header["Content-Type"]]
   154  }
   155  
   156  func newRpcCodec(req *transport.Message, client transport.Client, c codec.NewCodec, stream string) codec.Codec {
   157  	rwc := &readWriteCloser{
   158  		wbuf: bytes.NewBuffer(nil),
   159  		rbuf: bytes.NewBuffer(nil),
   160  	}
   161  	r := &rpcCodec{
   162  		buf:    rwc,
   163  		client: client,
   164  		codec:  c(rwc),
   165  		req:    req,
   166  		stream: stream,
   167  	}
   168  	return r
   169  }
   170  
   171  func (c *rpcCodec) Write(m *codec.Message, body interface{}) error {
   172  	c.buf.wbuf.Reset()
   173  
   174  	// create header
   175  	if m.Header == nil {
   176  		m.Header = map[string]string{}
   177  	}
   178  
   179  	// copy original header
   180  	for k, v := range c.req.Header {
   181  		m.Header[k] = v
   182  	}
   183  
   184  	// set the mucp headers
   185  	setHeaders(m, c.stream)
   186  
   187  	// if body is bytes Frame don't encode
   188  	if body != nil {
   189  		if b, ok := body.(*raw.Frame); ok {
   190  			// set body
   191  			m.Body = b.Data
   192  		} else {
   193  			// write to codec
   194  			if err := c.codec.Write(m, body); err != nil {
   195  				return errors.InternalServerError("go.micro.client.codec", err.Error())
   196  			}
   197  			// set body
   198  			m.Body = c.buf.wbuf.Bytes()
   199  		}
   200  	}
   201  
   202  	// create new transport message
   203  	msg := transport.Message{
   204  		Header: m.Header,
   205  		Body:   m.Body,
   206  	}
   207  
   208  	// send the request
   209  	if err := c.client.Send(&msg); err != nil {
   210  		return errors.InternalServerError("go.micro.client.transport", err.Error())
   211  	}
   212  
   213  	return nil
   214  }
   215  
   216  func (c *rpcCodec) ReadHeader(m *codec.Message, r codec.MessageType) error {
   217  	var tm transport.Message
   218  
   219  	// read message from transport
   220  	if err := c.client.Recv(&tm); err != nil {
   221  		return errors.InternalServerError("go.micro.client.transport", err.Error())
   222  	}
   223  
   224  	c.buf.rbuf.Reset()
   225  	c.buf.rbuf.Write(tm.Body)
   226  
   227  	// set headers from transport
   228  	m.Header = tm.Header
   229  
   230  	// read header
   231  	err := c.codec.ReadHeader(m, r)
   232  
   233  	// get headers
   234  	getHeaders(m)
   235  
   236  	// return header error
   237  	if err != nil {
   238  		return errors.InternalServerError("go.micro.client.codec", err.Error())
   239  	}
   240  
   241  	return nil
   242  }
   243  
   244  func (c *rpcCodec) ReadBody(b interface{}) error {
   245  	// read body
   246  	// read raw data
   247  	if v, ok := b.(*raw.Frame); ok {
   248  		v.Data = c.buf.rbuf.Bytes()
   249  		return nil
   250  	}
   251  
   252  	if err := c.codec.ReadBody(b); err != nil {
   253  		return errors.InternalServerError("go.micro.client.codec", err.Error())
   254  	}
   255  	return nil
   256  }
   257  
   258  func (c *rpcCodec) Close() error {
   259  	c.buf.Close()
   260  	c.codec.Close()
   261  	if err := c.client.Close(); err != nil {
   262  		return errors.InternalServerError("go.micro.client.transport", err.Error())
   263  	}
   264  	return nil
   265  }
   266  
   267  func (c *rpcCodec) String() string {
   268  	return "rpc"
   269  }