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