dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/dubbo/dubbo_codec.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package dubbo 19 20 import ( 21 "bytes" 22 "strconv" 23 "time" 24 ) 25 26 import ( 27 hessian "github.com/apache/dubbo-go-hessian2" 28 29 "github.com/dubbogo/gost/log/logger" 30 31 perrors "github.com/pkg/errors" 32 ) 33 34 import ( 35 "dubbo.apache.org/dubbo-go/v3/common/constant" 36 "dubbo.apache.org/dubbo-go/v3/protocol" 37 "dubbo.apache.org/dubbo-go/v3/protocol/dubbo/impl" 38 invct "dubbo.apache.org/dubbo-go/v3/protocol/invocation" 39 "dubbo.apache.org/dubbo-go/v3/remoting" 40 ) 41 42 // SerialID serial ID 43 type SerialID byte 44 45 func init() { 46 codec := &DubboCodec{} 47 remoting.RegistryCodec("dubbo", codec) 48 } 49 50 // DubboCodec implements remoting.Codec 51 type DubboCodec struct{} 52 53 // EncodeRequest encodes request for transport 54 func (c *DubboCodec) EncodeRequest(request *remoting.Request) (*bytes.Buffer, error) { 55 if request.Event { 56 return c.encodeHeartbeartReqeust(request) 57 } 58 59 invoc, ok := request.Data.(*protocol.Invocation) 60 if !ok { 61 err := perrors.Errorf("encode request failed for parameter type :%+v", request) 62 logger.Errorf(err.Error()) 63 return nil, err 64 } 65 invocation := *invoc 66 67 svc := impl.Service{} 68 svc.Path = invocation.GetAttachmentWithDefaultValue(constant.PathKey, "") 69 svc.Interface = invocation.GetAttachmentWithDefaultValue(constant.InterfaceKey, "") 70 svc.Version = invocation.GetAttachmentWithDefaultValue(constant.VersionKey, "") 71 svc.Group = invocation.GetAttachmentWithDefaultValue(constant.GroupKey, "") 72 svc.Method = invocation.MethodName() 73 timeout, err := strconv.Atoi(invocation.GetAttachmentWithDefaultValue(constant.TimeoutKey, strconv.Itoa(constant.DefaultRemotingTimeout))) 74 if err != nil { 75 // it will be wrapped in readwrite.Write . 76 return nil, perrors.WithStack(err) 77 } 78 svc.Timeout = time.Duration(timeout) 79 80 header := impl.DubboHeader{} 81 serialization := invocation.GetAttachmentWithDefaultValue(constant.SerializationKey, constant.Hessian2Serialization) 82 if serialization == constant.ProtobufSerialization { 83 header.SerialID = constant.SProto 84 } else { 85 header.SerialID = constant.SHessian2 86 } 87 header.ID = request.ID 88 if request.TwoWay { 89 header.Type = impl.PackageRequest_TwoWay 90 } else { 91 header.Type = impl.PackageRequest 92 } 93 94 pkg := &impl.DubboPackage{ 95 Header: header, 96 Service: svc, 97 Body: impl.NewRequestPayload(invocation.Arguments(), invocation.Attachments()), 98 Err: nil, 99 Codec: impl.NewDubboCodec(nil), 100 } 101 102 if err := impl.LoadSerializer(pkg); err != nil { 103 return nil, perrors.WithStack(err) 104 } 105 106 return pkg.Marshal() 107 } 108 109 // encode heartbeat request 110 func (c *DubboCodec) encodeHeartbeartReqeust(request *remoting.Request) (*bytes.Buffer, error) { 111 header := impl.DubboHeader{ 112 Type: impl.PackageHeartbeat, 113 SerialID: constant.SHessian2, 114 ID: request.ID, 115 } 116 117 pkg := &impl.DubboPackage{ 118 Header: header, 119 Service: impl.Service{}, 120 Body: impl.NewRequestPayload([]interface{}{}, nil), 121 Err: nil, 122 Codec: impl.NewDubboCodec(nil), 123 } 124 125 if err := impl.LoadSerializer(pkg); err != nil { 126 return nil, err 127 } 128 return pkg.Marshal() 129 } 130 131 // EncodeResponse encodes response 132 func (c *DubboCodec) EncodeResponse(response *remoting.Response) (*bytes.Buffer, error) { 133 ptype := impl.PackageResponse 134 if response.IsHeartbeat() { 135 ptype = impl.PackageHeartbeat 136 } 137 resp := &impl.DubboPackage{ 138 Header: impl.DubboHeader{ 139 SerialID: response.SerialID, 140 Type: ptype, 141 ID: response.ID, 142 ResponseStatus: response.Status, 143 }, 144 } 145 if !response.IsHeartbeat() { 146 resp.Body = &impl.ResponsePayload{ 147 RspObj: response.Result.(protocol.RPCResult).Rest, 148 Exception: response.Result.(protocol.RPCResult).Err, 149 Attachments: response.Result.(protocol.RPCResult).Attrs, 150 } 151 } 152 153 codec := impl.NewDubboCodec(nil) 154 155 pkg, err := codec.Encode(*resp) 156 if err != nil { 157 return nil, perrors.WithStack(err) 158 } 159 160 return bytes.NewBuffer(pkg), nil 161 } 162 163 // Decode data, including request and response. 164 func (c *DubboCodec) Decode(data []byte) (*remoting.DecodeResult, int, error) { 165 dataLen := len(data) 166 if dataLen < impl.HEADER_LENGTH { // check whether header bytes is enough or not 167 return nil, 0, nil 168 } 169 if c.isRequest(data) { 170 req, length, err := c.decodeRequest(data) 171 if err != nil { 172 return nil, length, perrors.WithStack(err) 173 } 174 if req == ((*remoting.Request)(nil)) { 175 return nil, length, err 176 } 177 return &remoting.DecodeResult{IsRequest: true, Result: req}, length, perrors.WithStack(err) 178 } 179 180 rsp, length, err := c.decodeResponse(data) 181 if err != nil { 182 return nil, length, perrors.WithStack(err) 183 } 184 if rsp == ((*remoting.Response)(nil)) { 185 return nil, length, err 186 } 187 return &remoting.DecodeResult{IsRequest: false, Result: rsp}, length, perrors.WithStack(err) 188 } 189 190 func (c *DubboCodec) isRequest(data []byte) bool { 191 return data[2]&byte(0x80) != 0x00 192 } 193 194 // decode request 195 func (c *DubboCodec) decodeRequest(data []byte) (*remoting.Request, int, error) { 196 var request *remoting.Request 197 buf := bytes.NewBuffer(data) 198 pkg := impl.NewDubboPackage(buf) 199 pkg.SetBody(make([]interface{}, 7)) 200 err := pkg.Unmarshal() 201 if err != nil { 202 originErr := perrors.Cause(err) 203 if originErr == hessian.ErrHeaderNotEnough { // this is impossible, as dubbo_codec.go:DubboCodec::Decode() line 167 204 return nil, 0, nil 205 } 206 if originErr == hessian.ErrBodyNotEnough { 207 return nil, hessian.HEADER_LENGTH + pkg.GetBodyLen(), nil 208 } 209 logger.Errorf("pkg.Unmarshal(len(@data):%d) = error:%+v", buf.Len(), err) 210 211 return request, 0, perrors.WithStack(err) 212 } 213 request = &remoting.Request{ 214 ID: pkg.Header.ID, 215 SerialID: pkg.Header.SerialID, 216 TwoWay: pkg.Header.Type&impl.PackageRequest_TwoWay != 0x00, 217 Event: pkg.Header.Type&impl.PackageHeartbeat != 0x00, 218 } 219 if (pkg.Header.Type & impl.PackageHeartbeat) == 0x00 { 220 // convert params of request 221 req := pkg.Body.(map[string]interface{}) 222 223 // invocation := request.Data.(*invocation.RPCInvocation) 224 var methodName string 225 var args []interface{} 226 attachments := make(map[string]interface{}) 227 if req[impl.DubboVersionKey] != nil { 228 // dubbo version 229 request.Version = req[impl.DubboVersionKey].(string) 230 } 231 // path 232 attachments[constant.PathKey] = pkg.Service.Path 233 // version 234 attachments[constant.VersionKey] = pkg.Service.Version 235 // method 236 methodName = pkg.Service.Method 237 args = req[impl.ArgsKey].([]interface{}) 238 attachments = req[impl.AttachmentsKey].(map[string]interface{}) 239 invoc := invct.NewRPCInvocationWithOptions(invct.WithAttachments(attachments), 240 invct.WithArguments(args), invct.WithMethodName(methodName)) 241 request.Data = invoc 242 243 } 244 return request, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil 245 } 246 247 // decode response 248 func (c *DubboCodec) decodeResponse(data []byte) (*remoting.Response, int, error) { 249 buf := bytes.NewBuffer(data) 250 pkg := impl.NewDubboPackage(buf) 251 err := pkg.Unmarshal() 252 if err != nil { 253 originErr := perrors.Cause(err) 254 // if the data is very big, so the receive need much times. 255 if originErr == hessian.ErrHeaderNotEnough { // this is impossible, as dubbo_codec.go:DubboCodec::Decode() line 167 256 return nil, 0, nil 257 } 258 if originErr == hessian.ErrBodyNotEnough { 259 return nil, hessian.HEADER_LENGTH + pkg.GetBodyLen(), nil 260 } 261 262 logger.Warnf("pkg.Unmarshal(len(@data):%d) = error:%+v", buf.Len(), err) 263 return nil, 0, perrors.WithStack(err) 264 } 265 response := &remoting.Response{ 266 ID: pkg.Header.ID, 267 // Version: pkg.Header., 268 SerialID: pkg.Header.SerialID, 269 Status: pkg.Header.ResponseStatus, 270 Event: (pkg.Header.Type & impl.PackageHeartbeat) != 0, 271 } 272 var pkgerr error 273 if pkg.Header.Type&impl.PackageHeartbeat != 0x00 { 274 if pkg.Header.Type&impl.PackageResponse != 0x00 { 275 logger.Debugf("get rpc heartbeat response{header: %#v, body: %#v}", pkg.Header, pkg.Body) 276 if pkg.Err != nil { 277 logger.Errorf("rpc heartbeat response{error: %#v}", pkg.Err) 278 pkgerr = pkg.Err 279 } 280 } else { 281 logger.Debugf("get rpc heartbeat request{header: %#v, service: %#v, body: %#v}", pkg.Header, pkg.Service, pkg.Body) 282 response.Status = hessian.Response_OK 283 // reply(session, p, hessian.PackageHeartbeat) 284 } 285 return response, hessian.HEADER_LENGTH + pkg.Header.BodyLen, pkgerr 286 } 287 logger.Debugf("get rpc response{header: %#v, body: %#v}", pkg.Header, pkg.Body) 288 rpcResult := &protocol.RPCResult{} 289 response.Result = rpcResult 290 if pkg.Header.Type&impl.PackageRequest == 0x00 { 291 if pkg.Err != nil { 292 rpcResult.Err = pkg.Err 293 } else if pkg.Body.(*impl.ResponsePayload).Exception != nil { 294 rpcResult.Err = pkg.Body.(*impl.ResponsePayload).Exception 295 response.Error = rpcResult.Err 296 } 297 rpcResult.Attrs = pkg.Body.(*impl.ResponsePayload).Attachments 298 rpcResult.Rest = pkg.Body.(*impl.ResponsePayload).RspObj 299 } 300 301 return response, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil 302 }