github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/client/mucp/codec.go (about)

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