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

     1  package server
     2  
     3  import (
     4  	"bytes"
     5  	"sync"
     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/transport"
    15  	"github.com/oxtoacart/bpool"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  type rpcCodec struct {
    20  	socket   transport.Socket
    21  	codec    codec.Codec
    22  	protocol string
    23  
    24  	req *transport.Message
    25  	buf *readWriteCloser
    26  
    27  	// check if we're the first
    28  	sync.RWMutex
    29  	first chan bool
    30  }
    31  
    32  type readWriteCloser struct {
    33  	sync.RWMutex
    34  	wbuf *bytes.Buffer
    35  	rbuf *bytes.Buffer
    36  }
    37  
    38  var (
    39  	DefaultContentType = "application/protobuf"
    40  
    41  	DefaultCodecs = map[string]codec.NewCodec{
    42  		"application/grpc":         grpc.NewCodec,
    43  		"application/grpc+json":    grpc.NewCodec,
    44  		"application/grpc+proto":   grpc.NewCodec,
    45  		"application/json":         json.NewCodec,
    46  		"application/json-rpc":     jsonrpc.NewCodec,
    47  		"application/protobuf":     proto.NewCodec,
    48  		"application/proto-rpc":    protorpc.NewCodec,
    49  		"application/octet-stream": raw.NewCodec,
    50  	}
    51  
    52  	// TODO: remove legacy codec list
    53  	defaultCodecs = map[string]codec.NewCodec{
    54  		"application/json":         jsonrpc.NewCodec,
    55  		"application/json-rpc":     jsonrpc.NewCodec,
    56  		"application/protobuf":     protorpc.NewCodec,
    57  		"application/proto-rpc":    protorpc.NewCodec,
    58  		"application/octet-stream": protorpc.NewCodec,
    59  	}
    60  
    61  	// the local buffer pool
    62  	bufferPool = bpool.NewSizedBufferPool(32, 1)
    63  )
    64  
    65  func (rwc *readWriteCloser) Read(p []byte) (n int, err error) {
    66  	rwc.RLock()
    67  	defer rwc.RUnlock()
    68  	return rwc.rbuf.Read(p)
    69  }
    70  
    71  func (rwc *readWriteCloser) Write(p []byte) (n int, err error) {
    72  	rwc.Lock()
    73  	defer rwc.Unlock()
    74  	return rwc.wbuf.Write(p)
    75  }
    76  
    77  func (rwc *readWriteCloser) Close() error {
    78  	return nil
    79  }
    80  
    81  func getHeader(hdr string, md map[string]string) string {
    82  	if hd := md[hdr]; len(hd) > 0 {
    83  		return hd
    84  	}
    85  	return md["X-"+hdr]
    86  }
    87  
    88  func getHeaders(m *codec.Message) {
    89  	set := func(v, hdr string) string {
    90  		if len(v) > 0 {
    91  			return v
    92  		}
    93  		return m.Header[hdr]
    94  	}
    95  
    96  	m.Id = set(m.Id, "Micro-Id")
    97  	m.Error = set(m.Error, "Micro-Error")
    98  	m.Endpoint = set(m.Endpoint, "Micro-Endpoint")
    99  	m.Method = set(m.Method, "Micro-Method")
   100  	m.Target = set(m.Target, "Micro-Service")
   101  
   102  	// TODO: remove this cruft
   103  	if len(m.Endpoint) == 0 {
   104  		m.Endpoint = m.Method
   105  	}
   106  }
   107  
   108  func setHeaders(m, r *codec.Message) {
   109  	set := func(hdr, v string) {
   110  		if len(v) == 0 {
   111  			return
   112  		}
   113  		m.Header[hdr] = v
   114  		m.Header["X-"+hdr] = v
   115  	}
   116  
   117  	// set headers
   118  	set("Micro-Id", r.Id)
   119  	set("Micro-Service", r.Target)
   120  	set("Micro-Method", r.Method)
   121  	set("Micro-Endpoint", r.Endpoint)
   122  	set("Micro-Error", r.Error)
   123  }
   124  
   125  // setupProtocol sets up the old protocol
   126  func setupProtocol(msg *transport.Message) codec.NewCodec {
   127  	service := getHeader("Micro-Service", msg.Header)
   128  	method := getHeader("Micro-Method", msg.Header)
   129  	endpoint := getHeader("Micro-Endpoint", msg.Header)
   130  	protocol := getHeader("Micro-Protocol", msg.Header)
   131  	target := getHeader("Micro-Target", msg.Header)
   132  	topic := getHeader("Micro-Topic", msg.Header)
   133  
   134  	// if the protocol exists (mucp) do nothing
   135  	if len(protocol) > 0 {
   136  		return nil
   137  	}
   138  
   139  	// newer method of processing messages over transport
   140  	if len(topic) > 0 {
   141  		return nil
   142  	}
   143  
   144  	// if no service/method/endpoint then it's the old protocol
   145  	if len(service) == 0 && len(method) == 0 && len(endpoint) == 0 {
   146  		return defaultCodecs[msg.Header["Content-Type"]]
   147  	}
   148  
   149  	// old target method specified
   150  	if len(target) > 0 {
   151  		return defaultCodecs[msg.Header["Content-Type"]]
   152  	}
   153  
   154  	// no method then set to endpoint
   155  	if len(method) == 0 {
   156  		msg.Header["Micro-Method"] = endpoint
   157  	}
   158  
   159  	// no endpoint then set to method
   160  	if len(endpoint) == 0 {
   161  		msg.Header["Micro-Endpoint"] = method
   162  	}
   163  
   164  	return nil
   165  }
   166  
   167  func newRpcCodec(req *transport.Message, socket transport.Socket, c codec.NewCodec) codec.Codec {
   168  	rwc := &readWriteCloser{
   169  		rbuf: bufferPool.Get(),
   170  		wbuf: bufferPool.Get(),
   171  	}
   172  
   173  	r := &rpcCodec{
   174  		buf:      rwc,
   175  		codec:    c(rwc),
   176  		req:      req,
   177  		socket:   socket,
   178  		protocol: "mucp",
   179  		first:    make(chan bool),
   180  	}
   181  
   182  	// if grpc pre-load the buffer
   183  	// TODO: remove this terrible hack
   184  	switch r.codec.String() {
   185  	case "grpc":
   186  		// write the body
   187  		rwc.rbuf.Write(req.Body)
   188  		// set the protocol
   189  		r.protocol = "grpc"
   190  	default:
   191  		// first is not preloaded
   192  		close(r.first)
   193  	}
   194  
   195  	return r
   196  }
   197  
   198  func (c *rpcCodec) ReadHeader(r *codec.Message, t codec.MessageType) error {
   199  	// the initial message
   200  	m := codec.Message{
   201  		Header: c.req.Header,
   202  		Body:   c.req.Body,
   203  	}
   204  
   205  	// first message could be pre-loaded
   206  	select {
   207  	case <-c.first:
   208  		// not the first
   209  		var tm transport.Message
   210  
   211  		// read off the socket
   212  		if err := c.socket.Recv(&tm); err != nil {
   213  			return err
   214  		}
   215  		// reset the read buffer
   216  		c.buf.rbuf.Reset()
   217  
   218  		// write the body to the buffer
   219  		if _, err := c.buf.rbuf.Write(tm.Body); err != nil {
   220  			return err
   221  		}
   222  
   223  		// set the message header
   224  		m.Header = tm.Header
   225  		// set the message body
   226  		m.Body = tm.Body
   227  
   228  		// set req
   229  		c.req = &tm
   230  	default:
   231  		// we need to lock here to prevent race conditions
   232  		// and we make use of a channel otherwise because
   233  		// this does not result in a context switch
   234  		// locking to check c.first on every call to ReadHeader
   235  		// would otherwise drastically slow the code execution
   236  		c.Lock()
   237  		// recheck before closing because the select statement
   238  		// above is not thread safe, so thread safety here is
   239  		// mandatory
   240  		select {
   241  		case <-c.first:
   242  		default:
   243  			// disable first
   244  			close(c.first)
   245  		}
   246  		// now unlock and we never need this again
   247  		c.Unlock()
   248  	}
   249  
   250  	// set some internal things
   251  	getHeaders(&m)
   252  
   253  	// read header via codec
   254  	if err := c.codec.ReadHeader(&m, codec.Request); err != nil {
   255  		return err
   256  	}
   257  
   258  	// fallback for 0.14 and older
   259  	if len(m.Endpoint) == 0 {
   260  		m.Endpoint = m.Method
   261  	}
   262  
   263  	// set message
   264  	*r = m
   265  
   266  	return nil
   267  }
   268  
   269  func (c *rpcCodec) ReadBody(b interface{}) error {
   270  	// don't read empty body
   271  	if len(c.req.Body) == 0 {
   272  		return nil
   273  	}
   274  	// read raw data
   275  	if v, ok := b.(*raw.Frame); ok {
   276  		v.Data = c.req.Body
   277  		return nil
   278  	}
   279  	// decode the usual way
   280  	return c.codec.ReadBody(b)
   281  }
   282  
   283  func (c *rpcCodec) Write(r *codec.Message, b interface{}) error {
   284  	c.buf.wbuf.Reset()
   285  
   286  	// create a new message
   287  	m := &codec.Message{
   288  		Target:   r.Target,
   289  		Method:   r.Method,
   290  		Endpoint: r.Endpoint,
   291  		Id:       r.Id,
   292  		Error:    r.Error,
   293  		Type:     r.Type,
   294  		Header:   r.Header,
   295  	}
   296  
   297  	if m.Header == nil {
   298  		m.Header = map[string]string{}
   299  	}
   300  
   301  	setHeaders(m, r)
   302  
   303  	// the body being sent
   304  	var body []byte
   305  
   306  	// is it a raw frame?
   307  	if v, ok := b.(*raw.Frame); ok {
   308  		body = v.Data
   309  		// if we have encoded data just send it
   310  	} else if len(r.Body) > 0 {
   311  		body = r.Body
   312  		// write the body to codec
   313  	} else if err := c.codec.Write(m, b); err != nil {
   314  		c.buf.wbuf.Reset()
   315  
   316  		// write an error if it failed
   317  		m.Error = errors.Wrapf(err, "Unable to encode body").Error()
   318  		m.Header["Micro-Error"] = m.Error
   319  		// no body to write
   320  		if err := c.codec.Write(m, nil); err != nil {
   321  			return err
   322  		}
   323  	} else {
   324  		// set the body
   325  		body = c.buf.wbuf.Bytes()
   326  	}
   327  
   328  	// Set content type if theres content
   329  	if len(body) > 0 {
   330  		m.Header["Content-Type"] = c.req.Header["Content-Type"]
   331  	}
   332  
   333  	// send on the socket
   334  	return c.socket.Send(&transport.Message{
   335  		Header: m.Header,
   336  		Body:   body,
   337  	})
   338  }
   339  
   340  func (c *rpcCodec) Close() error {
   341  	// close the codec
   342  	c.codec.Close()
   343  	// close the socket
   344  	err := c.socket.Close()
   345  	// put back the buffers
   346  	bufferPool.Put(c.buf.rbuf)
   347  	bufferPool.Put(c.buf.wbuf)
   348  	// return the error
   349  	return err
   350  }
   351  
   352  func (c *rpcCodec) String() string {
   353  	return c.protocol
   354  }