go-micro.dev/v5@v5.12.0/client/rpc_codec.go (about) 1 package client 2 3 import ( 4 "bytes" 5 errs "errors" 6 7 "go-micro.dev/v5/codec" 8 raw "go-micro.dev/v5/codec/bytes" 9 "go-micro.dev/v5/codec/grpc" 10 "go-micro.dev/v5/codec/json" 11 "go-micro.dev/v5/codec/jsonrpc" 12 "go-micro.dev/v5/codec/proto" 13 "go-micro.dev/v5/codec/protorpc" 14 "go-micro.dev/v5/errors" 15 "go-micro.dev/v5/registry" 16 "go-micro.dev/v5/transport" 17 "go-micro.dev/v5/transport/headers" 18 ) 19 20 const ( 21 lastStreamResponseError = "EOS" 22 ) 23 24 // serverError represents an error that has been returned from 25 // the remote side of the RPC connection. 26 type serverError string 27 28 func (e serverError) Error() string { 29 return string(e) 30 } 31 32 // errShutdown holds the specific error for closing/closed connections. 33 var ( 34 errShutdown = errs.New("connection is shut down") 35 ) 36 37 type rpcCodec struct { 38 client transport.Client 39 codec codec.Codec 40 41 req *transport.Message 42 buf *readWriteCloser 43 44 // signify if its a stream 45 stream string 46 } 47 48 type readWriteCloser struct { 49 wbuf *bytes.Buffer 50 rbuf *bytes.Buffer 51 } 52 53 var ( 54 // DefaultContentType header. 55 DefaultContentType = "application/json" 56 57 // DefaultCodecs map. 58 DefaultCodecs = map[string]codec.NewCodec{ 59 "application/grpc": grpc.NewCodec, 60 "application/grpc+json": grpc.NewCodec, 61 "application/grpc+proto": grpc.NewCodec, 62 "application/protobuf": proto.NewCodec, 63 "application/json": json.NewCodec, 64 "application/json-rpc": jsonrpc.NewCodec, 65 "application/proto-rpc": protorpc.NewCodec, 66 "application/octet-stream": raw.NewCodec, 67 } 68 69 // TODO: remove legacy codec list. 70 defaultCodecs = map[string]codec.NewCodec{ 71 "application/json": jsonrpc.NewCodec, 72 "application/json-rpc": jsonrpc.NewCodec, 73 "application/protobuf": protorpc.NewCodec, 74 "application/proto-rpc": protorpc.NewCodec, 75 "application/octet-stream": protorpc.NewCodec, 76 } 77 ) 78 79 func (rwc *readWriteCloser) Read(p []byte) (n int, err error) { 80 return rwc.rbuf.Read(p) 81 } 82 83 func (rwc *readWriteCloser) Write(p []byte) (n int, err error) { 84 return rwc.wbuf.Write(p) 85 } 86 87 func (rwc *readWriteCloser) Close() error { 88 rwc.rbuf.Reset() 89 rwc.wbuf.Reset() 90 91 return nil 92 } 93 94 func getHeaders(m *codec.Message) { 95 set := func(v, hdr string) string { 96 if len(v) > 0 { 97 return v 98 } 99 100 return m.Header[hdr] 101 } 102 103 // check error in header 104 m.Error = set(m.Error, headers.Error) 105 106 // check endpoint in header 107 m.Endpoint = set(m.Endpoint, headers.Endpoint) 108 109 // check method in header 110 m.Method = set(m.Method, headers.Method) 111 112 // set the request id 113 m.Id = set(m.Id, headers.ID) 114 } 115 116 func setHeaders(m *codec.Message, stream string) { 117 set := func(hdr, v string) { 118 if len(v) == 0 { 119 return 120 } 121 122 m.Header[hdr] = v 123 } 124 125 set(headers.ID, m.Id) 126 set(headers.Request, m.Target) 127 set(headers.Method, m.Method) 128 set(headers.Endpoint, m.Endpoint) 129 set(headers.Error, m.Error) 130 131 if len(stream) > 0 { 132 set(headers.Stream, stream) 133 } 134 } 135 136 // setupProtocol sets up the old protocol. 137 func setupProtocol(msg *transport.Message, node *registry.Node) codec.NewCodec { 138 protocol := node.Metadata["protocol"] 139 140 // got protocol 141 if len(protocol) > 0 { 142 return nil 143 } 144 145 // processing topic publishing 146 if len(msg.Header[headers.Message]) > 0 { 147 return nil 148 } 149 150 // no protocol use old codecs 151 switch msg.Header["Content-Type"] { 152 case "application/json": 153 msg.Header["Content-Type"] = "application/json-rpc" 154 case "application/protobuf": 155 msg.Header["Content-Type"] = "application/proto-rpc" 156 } 157 158 return defaultCodecs[msg.Header["Content-Type"]] 159 } 160 161 func newRPCCodec(req *transport.Message, client transport.Client, c codec.NewCodec, stream string) codec.Codec { 162 rwc := &readWriteCloser{ 163 wbuf: bytes.NewBuffer(nil), 164 rbuf: bytes.NewBuffer(nil), 165 } 166 167 return &rpcCodec{ 168 buf: rwc, 169 client: client, 170 codec: c(rwc), 171 req: req, 172 stream: stream, 173 } 174 } 175 176 func (c *rpcCodec) Write(message *codec.Message, body interface{}) error { 177 c.buf.wbuf.Reset() 178 179 // create header 180 if message.Header == nil { 181 message.Header = map[string]string{} 182 } 183 184 // copy original header 185 for k, v := range c.req.Header { 186 message.Header[k] = v 187 } 188 189 // set the mucp headers 190 setHeaders(message, c.stream) 191 192 // if body is bytes Frame don't encode 193 if body != nil { 194 if b, ok := body.(*raw.Frame); ok { 195 // set body 196 message.Body = b.Data 197 } else { 198 // write to codec 199 if err := c.codec.Write(message, body); err != nil { 200 return errors.InternalServerError("go.micro.client.codec", err.Error()) 201 } 202 // set body 203 message.Body = c.buf.wbuf.Bytes() 204 } 205 } 206 207 // create new transport message 208 msg := transport.Message{ 209 Header: message.Header, 210 Body: message.Body, 211 } 212 213 // send the request 214 if err := c.client.Send(&msg); err != nil { 215 return errors.InternalServerError("go.micro.client.transport", err.Error()) 216 } 217 218 return nil 219 } 220 221 func (c *rpcCodec) ReadHeader(msg *codec.Message, r codec.MessageType) error { 222 var tm transport.Message 223 224 // read message from transport 225 if err := c.client.Recv(&tm); err != nil { 226 return errors.InternalServerError("go.micro.client.transport", err.Error()) 227 } 228 229 c.buf.rbuf.Reset() 230 c.buf.rbuf.Write(tm.Body) 231 232 // set headers from transport 233 msg.Header = tm.Header 234 235 // read header 236 err := c.codec.ReadHeader(msg, r) 237 238 // get headers 239 getHeaders(msg) 240 241 // return header error 242 if err != nil { 243 return errors.InternalServerError("go.micro.client.codec", err.Error()) 244 } 245 246 return nil 247 } 248 249 func (c *rpcCodec) ReadBody(b interface{}) error { 250 // read body 251 // read raw data 252 if v, ok := b.(*raw.Frame); ok { 253 v.Data = c.buf.rbuf.Bytes() 254 return nil 255 } 256 257 if err := c.codec.ReadBody(b); err != nil { 258 return errors.InternalServerError("go.micro.client.codec", err.Error()) 259 } 260 261 return nil 262 } 263 264 func (c *rpcCodec) Close() error { 265 if err := c.buf.Close(); err != nil { 266 return err 267 } 268 269 if err := c.codec.Close(); err != nil { 270 return err 271 } 272 273 if err := c.client.Close(); err != nil { 274 return errors.InternalServerError("go.micro.client.transport", err.Error()) 275 } 276 277 return nil 278 } 279 280 func (c *rpcCodec) String() string { 281 return "rpc" 282 }