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  }