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