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