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 }