go-micro.dev/v5@v5.12.0/client/grpc/codec.go (about)

     1  package grpc
     2  
     3  import (
     4  	b "bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"go-micro.dev/v5/codec"
    10  	"go-micro.dev/v5/codec/bytes"
    11  	"google.golang.org/grpc"
    12  	"google.golang.org/grpc/encoding"
    13  	"google.golang.org/protobuf/encoding/protojson"
    14  	"google.golang.org/protobuf/proto"
    15  	"google.golang.org/protobuf/runtime/protoiface"
    16  	"google.golang.org/protobuf/runtime/protoimpl"
    17  )
    18  
    19  type jsonCodec struct{}
    20  type protoCodec struct{}
    21  type bytesCodec struct{}
    22  type wrapCodec struct{ encoding.Codec }
    23  
    24  var useNumber bool
    25  
    26  var (
    27  	defaultGRPCCodecs = map[string]encoding.Codec{
    28  		"application/json":         jsonCodec{},
    29  		"application/proto":        protoCodec{},
    30  		"application/protobuf":     protoCodec{},
    31  		"application/octet-stream": protoCodec{},
    32  		"application/grpc":         protoCodec{},
    33  		"application/grpc+json":    jsonCodec{},
    34  		"application/grpc+proto":   protoCodec{},
    35  		"application/grpc+bytes":   bytesCodec{},
    36  	}
    37  )
    38  
    39  // UseNumber fix unmarshal Number(8234567890123456789) to interface(8.234567890123457e+18).
    40  func UseNumber() {
    41  	useNumber = true
    42  }
    43  
    44  func (w wrapCodec) String() string {
    45  	return w.Codec.Name()
    46  }
    47  
    48  func (w wrapCodec) Marshal(v interface{}) ([]byte, error) {
    49  	b, ok := v.(*bytes.Frame)
    50  	if ok {
    51  		return b.Data, nil
    52  	}
    53  	return w.Codec.Marshal(v)
    54  }
    55  
    56  func (w wrapCodec) Unmarshal(data []byte, v interface{}) error {
    57  	b, ok := v.(*bytes.Frame)
    58  	if ok {
    59  		b.Data = data
    60  		return nil
    61  	}
    62  	return w.Codec.Unmarshal(data, v)
    63  }
    64  
    65  func (protoCodec) Marshal(v interface{}) ([]byte, error) {
    66  	switch m := v.(type) {
    67  	case *bytes.Frame:
    68  		return m.Data, nil
    69  	case proto.Message:
    70  		return proto.Marshal(m)
    71  	case protoiface.MessageV1:
    72  		// #2333 compatible with etcd legacy proto.Message
    73  		m2 := protoimpl.X.ProtoMessageV2Of(m)
    74  		return proto.Marshal(m2)
    75  	}
    76  	return nil, fmt.Errorf("failed to marshal: %v is not type of *bytes.Frame or proto.Message", v)
    77  }
    78  
    79  func (protoCodec) Unmarshal(data []byte, v interface{}) error {
    80  	switch m := v.(type) {
    81  	case proto.Message:
    82  		return proto.Unmarshal(data, m)
    83  	case protoiface.MessageV1:
    84  		// #2333 compatible with etcd legacy proto.Message
    85  		m2 := protoimpl.X.ProtoMessageV2Of(m)
    86  		return proto.Unmarshal(data, m2)
    87  	}
    88  	return fmt.Errorf("failed to unmarshal: %v is not type of proto.Message", v)
    89  }
    90  
    91  func (protoCodec) Name() string {
    92  	return "proto"
    93  }
    94  
    95  func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
    96  	b, ok := v.(*[]byte)
    97  	if !ok {
    98  		return nil, fmt.Errorf("failed to marshal: %v is not type of *[]byte", v)
    99  	}
   100  	return *b, nil
   101  }
   102  
   103  func (bytesCodec) Unmarshal(data []byte, v interface{}) error {
   104  	b, ok := v.(*[]byte)
   105  	if !ok {
   106  		return fmt.Errorf("failed to unmarshal: %v is not type of *[]byte", v)
   107  	}
   108  	*b = data
   109  	return nil
   110  }
   111  
   112  func (bytesCodec) Name() string {
   113  	return "bytes"
   114  }
   115  
   116  func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
   117  	if b, ok := v.(*bytes.Frame); ok {
   118  		return b.Data, nil
   119  	}
   120  
   121  	if pb, ok := v.(proto.Message); ok {
   122  		bytes, err := protojson.Marshal(pb)
   123  		if err != nil {
   124  			return nil, err
   125  		}
   126  		return bytes, nil
   127  	}
   128  
   129  	return json.Marshal(v)
   130  }
   131  
   132  func (jsonCodec) Unmarshal(data []byte, v interface{}) error {
   133  	if len(data) == 0 {
   134  		return nil
   135  	}
   136  	if b, ok := v.(*bytes.Frame); ok {
   137  		b.Data = data
   138  		return nil
   139  	}
   140  	if pb, ok := v.(proto.Message); ok {
   141  		return protojson.Unmarshal(data, pb)
   142  	}
   143  
   144  	dec := json.NewDecoder(b.NewReader(data))
   145  	if useNumber {
   146  		dec.UseNumber()
   147  	}
   148  	return dec.Decode(v)
   149  }
   150  
   151  func (jsonCodec) Name() string {
   152  	return "json"
   153  }
   154  
   155  type grpcCodec struct {
   156  	// headers
   157  	id       string
   158  	target   string
   159  	method   string
   160  	endpoint string
   161  
   162  	s grpc.ClientStream
   163  	c encoding.Codec
   164  }
   165  
   166  func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
   167  	md, err := g.s.Header()
   168  	if err != nil {
   169  		return err
   170  	}
   171  	if m == nil {
   172  		m = new(codec.Message)
   173  	}
   174  	if m.Header == nil {
   175  		m.Header = make(map[string]string, len(md))
   176  	}
   177  	for k, v := range md {
   178  		m.Header[k] = strings.Join(v, ",")
   179  	}
   180  	m.Id = g.id
   181  	m.Target = g.target
   182  	m.Method = g.method
   183  	m.Endpoint = g.endpoint
   184  	return nil
   185  }
   186  
   187  func (g *grpcCodec) ReadBody(v interface{}) error {
   188  	if f, ok := v.(*bytes.Frame); ok {
   189  		return g.s.RecvMsg(f)
   190  	}
   191  	return g.s.RecvMsg(v)
   192  }
   193  
   194  func (g *grpcCodec) Write(m *codec.Message, v interface{}) error {
   195  	// if we don't have a body
   196  	if v != nil {
   197  		return g.s.SendMsg(v)
   198  	}
   199  	// write the body using the framing codec
   200  	return g.s.SendMsg(&bytes.Frame{Data: m.Body})
   201  }
   202  
   203  func (g *grpcCodec) Close() error {
   204  	return g.s.CloseSend()
   205  }
   206  
   207  func (g *grpcCodec) String() string {
   208  	return g.c.Name()
   209  }