gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/client/rpc_codec.go (about)

     1  package client
     2  
     3  import (
     4  	"bytes"
     5  	errs "errors"
     6  
     7  	"gitee.com/liuxuezhan/go-micro-v1.18.0/codec"
     8  	raw "gitee.com/liuxuezhan/go-micro-v1.18.0/codec/bytes"
     9  	"gitee.com/liuxuezhan/go-micro-v1.18.0/codec/grpc"
    10  	"gitee.com/liuxuezhan/go-micro-v1.18.0/codec/json"
    11  	"gitee.com/liuxuezhan/go-micro-v1.18.0/codec/jsonrpc"
    12  	"gitee.com/liuxuezhan/go-micro-v1.18.0/codec/proto"
    13  	"gitee.com/liuxuezhan/go-micro-v1.18.0/codec/protorpc"
    14  	"gitee.com/liuxuezhan/go-micro-v1.18.0/errors"
    15  	"gitee.com/liuxuezhan/go-micro-v1.18.0/registry"
    16  	"gitee.com/liuxuezhan/go-micro-v1.18.0/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  		b, ok := body.(*raw.Frame)
   190  		if ok {
   191  			// set body
   192  			m.Body = b.Data
   193  			body = nil
   194  		}
   195  	}
   196  
   197  	if len(m.Body) == 0 {
   198  		// write to codec
   199  		if err := c.codec.Write(m, body); err != nil {
   200  			return errors.InternalServerError("go.micro.client.codec", err.Error())
   201  		}
   202  		// set body
   203  		m.Body = c.buf.wbuf.Bytes()
   204  	}
   205  
   206  	// create new transport message
   207  	msg := transport.Message{
   208  		Header: m.Header,
   209  		Body:   m.Body,
   210  	}
   211  	// send the request
   212  	if err := c.client.Send(&msg); err != nil {
   213  		return errors.InternalServerError("go.micro.client.transport", err.Error())
   214  	}
   215  	return nil
   216  }
   217  
   218  func (c *rpcCodec) ReadHeader(m *codec.Message, r codec.MessageType) error {
   219  	var tm transport.Message
   220  
   221  	// read message from transport
   222  	if err := c.client.Recv(&tm); err != nil {
   223  		return errors.InternalServerError("go.micro.client.transport", err.Error())
   224  	}
   225  
   226  	c.buf.rbuf.Reset()
   227  	c.buf.rbuf.Write(tm.Body)
   228  
   229  	// set headers from transport
   230  	m.Header = tm.Header
   231  
   232  	// read header
   233  	err := c.codec.ReadHeader(m, r)
   234  
   235  	// get headers
   236  	getHeaders(m)
   237  
   238  	// return header error
   239  	if err != nil {
   240  		return errors.InternalServerError("go.micro.client.codec", err.Error())
   241  	}
   242  
   243  	return nil
   244  }
   245  
   246  func (c *rpcCodec) ReadBody(b interface{}) error {
   247  	// read body
   248  	// read raw data
   249  	if v, ok := b.(*raw.Frame); ok {
   250  		v.Data = c.buf.rbuf.Bytes()
   251  		return nil
   252  	}
   253  
   254  	if err := c.codec.ReadBody(b); err != nil {
   255  		return errors.InternalServerError("go.micro.client.codec", err.Error())
   256  	}
   257  	return nil
   258  }
   259  
   260  func (c *rpcCodec) Close() error {
   261  	c.buf.Close()
   262  	c.codec.Close()
   263  	if err := c.client.Close(); err != nil {
   264  		return errors.InternalServerError("go.micro.client.transport", err.Error())
   265  	}
   266  	return nil
   267  }
   268  
   269  func (c *rpcCodec) String() string {
   270  	return "rpc"
   271  }