github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/util/codec/grpc/grpc.go (about)

     1  // Licensed under the Apache License, Version 2.0 (the "License");
     2  // you may not use this file except in compliance with the License.
     3  // You may obtain a copy of the License at
     4  //
     5  //     https://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS,
     9  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  // See the License for the specific language governing permissions and
    11  // limitations under the License.
    12  //
    13  // Original source: github.com/micro/go-micro/v3/codec/grpc/grpc.go
    14  
    15  // Package grpc provides a grpc codec
    16  package grpc
    17  
    18  import (
    19  	"encoding/json"
    20  	"errors"
    21  	"fmt"
    22  	"io"
    23  	"strings"
    24  
    25  	"github.com/golang/protobuf/proto"
    26  	"github.com/tickoalcantara12/micro/v3/util/codec"
    27  )
    28  
    29  type Codec struct {
    30  	Conn        io.ReadWriteCloser
    31  	ContentType string
    32  }
    33  
    34  func (c *Codec) ReadHeader(m *codec.Message, t codec.MessageType) error {
    35  	if ct := m.Header["Content-Type"]; len(ct) > 0 {
    36  		c.ContentType = ct
    37  	}
    38  
    39  	if ct := m.Header["content-type"]; len(ct) > 0 {
    40  		c.ContentType = ct
    41  	}
    42  
    43  	// service method
    44  	path := m.Header[":path"]
    45  	if len(path) == 0 || path[0] != '/' {
    46  		m.Target = m.Header["Micro-Service"]
    47  		m.Endpoint = m.Header["Micro-Endpoint"]
    48  	} else {
    49  		// [ , a.package.Foo, Bar]
    50  		parts := strings.Split(path, "/")
    51  		if len(parts) != 3 {
    52  			return errors.New("Unknown request path")
    53  		}
    54  		service := strings.Split(parts[1], ".")
    55  		m.Endpoint = strings.Join([]string{service[len(service)-1], parts[2]}, ".")
    56  		m.Target = strings.Join(service[:len(service)-1], ".")
    57  	}
    58  
    59  	return nil
    60  }
    61  
    62  func (c *Codec) ReadBody(b interface{}) error {
    63  	// no body
    64  	if b == nil {
    65  		return nil
    66  	}
    67  
    68  	_, buf, err := decode(c.Conn)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	switch c.ContentType {
    74  	case "application/grpc+json":
    75  		return json.Unmarshal(buf, b)
    76  	case "application/grpc+proto", "application/grpc":
    77  		return proto.Unmarshal(buf, b.(proto.Message))
    78  	}
    79  
    80  	return errors.New("Unsupported Content-Type")
    81  }
    82  
    83  func (c *Codec) Write(m *codec.Message, b interface{}) error {
    84  	var buf []byte
    85  	var err error
    86  
    87  	if ct := m.Header["Content-Type"]; len(ct) > 0 {
    88  		c.ContentType = ct
    89  	}
    90  
    91  	if ct := m.Header["content-type"]; len(ct) > 0 {
    92  		c.ContentType = ct
    93  	}
    94  
    95  	switch m.Type {
    96  	case codec.Request:
    97  		parts := strings.Split(m.Endpoint, ".")
    98  		m.Header[":method"] = "POST"
    99  		m.Header[":path"] = fmt.Sprintf("/%s.%s/%s", m.Target, parts[0], parts[1])
   100  		m.Header[":proto"] = "HTTP/2.0"
   101  		m.Header["te"] = "trailers"
   102  		m.Header["user-agent"] = "grpc-go/1.0.0"
   103  		m.Header[":authority"] = m.Target
   104  		m.Header["content-type"] = c.ContentType
   105  	case codec.Response:
   106  		m.Header["Trailer"] = "grpc-status" //, grpc-message"
   107  		m.Header["content-type"] = c.ContentType
   108  		m.Header[":status"] = "200"
   109  		m.Header["grpc-status"] = "0"
   110  		//		m.Header["grpc-message"] = ""
   111  	case codec.Error:
   112  		m.Header["Trailer"] = "grpc-status, grpc-message"
   113  		// micro end of stream
   114  		if m.Error == "EOS" {
   115  			m.Header["grpc-status"] = "0"
   116  		} else {
   117  			m.Header["grpc-message"] = m.Error
   118  			m.Header["grpc-status"] = "13"
   119  		}
   120  
   121  		return nil
   122  	}
   123  
   124  	// marshal content
   125  	switch c.ContentType {
   126  	case "application/grpc+json":
   127  		buf, err = json.Marshal(b)
   128  	case "application/grpc+proto", "application/grpc":
   129  		pb, ok := b.(proto.Message)
   130  		if ok {
   131  			buf, err = proto.Marshal(pb)
   132  		}
   133  	default:
   134  		err = errors.New("Unsupported Content-Type")
   135  	}
   136  	// check error
   137  	if err != nil {
   138  		m.Header["grpc-status"] = "8"
   139  		m.Header["grpc-message"] = err.Error()
   140  		return err
   141  	}
   142  
   143  	if len(buf) == 0 {
   144  		return nil
   145  	}
   146  
   147  	return encode(0, buf, c.Conn)
   148  }
   149  
   150  func (c *Codec) Close() error {
   151  	return c.Conn.Close()
   152  }
   153  
   154  func (c *Codec) String() string {
   155  	return "grpc"
   156  }
   157  
   158  func NewCodec(c io.ReadWriteCloser) codec.Codec {
   159  	return &Codec{
   160  		Conn:        c,
   161  		ContentType: "application/grpc",
   162  	}
   163  }