dubbo.apache.org/dubbo-go/v3@v3.1.1/remoting/getty/dubbo_codec_for_test.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 getty
    19  
    20  // copy from dubbo/dubbo_codec.go .
    21  // it is used to unit test.
    22  import (
    23  	"bytes"
    24  	"strconv"
    25  	"time"
    26  )
    27  
    28  import (
    29  	hessian "github.com/apache/dubbo-go-hessian2"
    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  	"dubbo.apache.org/dubbo-go/v3/protocol/invocation"
    39  	"dubbo.apache.org/dubbo-go/v3/remoting"
    40  )
    41  
    42  func init() {
    43  	codec := &DubboTestCodec{}
    44  	remoting.RegistryCodec("dubbo", codec)
    45  }
    46  
    47  type DubboTestCodec struct{}
    48  
    49  // encode request for transport
    50  func (c *DubboTestCodec) EncodeRequest(request *remoting.Request) (*bytes.Buffer, error) {
    51  	if request.Event {
    52  		return c.encodeHeartbeartReqeust(request)
    53  	}
    54  
    55  	invoc, ok := request.Data.(*invocation.RPCInvocation)
    56  	if !ok {
    57  		return nil, perrors.Errorf("encode request failed for parameter type :%+v", request)
    58  	}
    59  	tmpInvocation := invoc
    60  
    61  	svc := impl.Service{}
    62  	svc.Path = tmpInvocation.GetAttachmentWithDefaultValue(constant.PathKey, "")
    63  	svc.Interface = tmpInvocation.GetAttachmentWithDefaultValue(constant.InterfaceKey, "")
    64  	svc.Version = tmpInvocation.GetAttachmentWithDefaultValue(constant.VersionKey, "")
    65  	svc.Group = tmpInvocation.GetAttachmentWithDefaultValue(constant.GroupKey, "")
    66  	svc.Method = tmpInvocation.MethodName()
    67  	timeout, err := strconv.Atoi(tmpInvocation.GetAttachmentWithDefaultValue(constant.TimeoutKey, strconv.Itoa(constant.DefaultRemotingTimeout)))
    68  	if err != nil {
    69  		// it will be wrapped in readwrite.Write .
    70  		return nil, perrors.WithStack(err)
    71  	}
    72  	svc.Timeout = time.Duration(timeout)
    73  
    74  	header := impl.DubboHeader{}
    75  	serialization := tmpInvocation.GetAttachmentWithDefaultValue(constant.SerializationKey, constant.Hessian2Serialization)
    76  	if serialization == constant.ProtobufSerialization {
    77  		header.SerialID = constant.SProto
    78  	} else {
    79  		header.SerialID = constant.SHessian2
    80  	}
    81  	header.ID = request.ID
    82  	if request.TwoWay {
    83  		header.Type = impl.PackageRequest_TwoWay
    84  	} else {
    85  		header.Type = impl.PackageRequest
    86  	}
    87  
    88  	pkg := &impl.DubboPackage{
    89  		Header:  header,
    90  		Service: svc,
    91  		Body:    impl.NewRequestPayload(tmpInvocation.Arguments(), tmpInvocation.Attachments()),
    92  		Err:     nil,
    93  		Codec:   impl.NewDubboCodec(nil),
    94  	}
    95  
    96  	if err := impl.LoadSerializer(pkg); err != nil {
    97  		return nil, perrors.WithStack(err)
    98  	}
    99  
   100  	return pkg.Marshal()
   101  }
   102  
   103  // encode heartbeat request
   104  func (c *DubboTestCodec) encodeHeartbeartReqeust(request *remoting.Request) (*bytes.Buffer, error) {
   105  	header := impl.DubboHeader{
   106  		Type:     impl.PackageHeartbeat,
   107  		SerialID: constant.SHessian2,
   108  		ID:       request.ID,
   109  	}
   110  
   111  	pkg := &impl.DubboPackage{
   112  		Header:  header,
   113  		Service: impl.Service{},
   114  		Body:    impl.NewRequestPayload([]interface{}{}, nil),
   115  		Err:     nil,
   116  		Codec:   impl.NewDubboCodec(nil),
   117  	}
   118  
   119  	if err := impl.LoadSerializer(pkg); err != nil {
   120  		return nil, err
   121  	}
   122  	return pkg.Marshal()
   123  }
   124  
   125  // encode response
   126  func (c *DubboTestCodec) EncodeResponse(response *remoting.Response) (*bytes.Buffer, error) {
   127  	ptype := impl.PackageResponse
   128  	if response.IsHeartbeat() {
   129  		ptype = impl.PackageHeartbeat
   130  	}
   131  	resp := &impl.DubboPackage{
   132  		Header: impl.DubboHeader{
   133  			SerialID:       response.SerialID,
   134  			Type:           ptype,
   135  			ID:             response.ID,
   136  			ResponseStatus: response.Status,
   137  		},
   138  	}
   139  	if !response.IsHeartbeat() {
   140  		resp.Body = &impl.ResponsePayload{
   141  			RspObj:      response.Result.(protocol.RPCResult).Rest,
   142  			Exception:   response.Result.(protocol.RPCResult).Err,
   143  			Attachments: response.Result.(protocol.RPCResult).Attrs,
   144  		}
   145  	}
   146  
   147  	codec := impl.NewDubboCodec(nil)
   148  
   149  	pkg, err := codec.Encode(*resp)
   150  	if err != nil {
   151  		return nil, perrors.WithStack(err)
   152  	}
   153  
   154  	return bytes.NewBuffer(pkg), nil
   155  }
   156  
   157  // Decode data, including request and response.
   158  func (c *DubboTestCodec) Decode(data []byte) (*remoting.DecodeResult, int, error) {
   159  	if c.isRequest(data) {
   160  		req, len, err := c.decodeRequest(data)
   161  		if err != nil {
   162  			return &remoting.DecodeResult{}, len, perrors.WithStack(err)
   163  		}
   164  		return &remoting.DecodeResult{IsRequest: true, Result: req}, len, perrors.WithStack(err)
   165  	} else {
   166  		resp, len, err := c.decodeResponse(data)
   167  		if err != nil {
   168  			return &remoting.DecodeResult{}, len, perrors.WithStack(err)
   169  		}
   170  		return &remoting.DecodeResult{IsRequest: false, Result: resp}, len, perrors.WithStack(err)
   171  	}
   172  }
   173  
   174  func (c *DubboTestCodec) isRequest(data []byte) bool {
   175  	return data[2]&byte(0x80) != 0x00
   176  }
   177  
   178  // decode request
   179  func (c *DubboTestCodec) decodeRequest(data []byte) (*remoting.Request, int, error) {
   180  	var request *remoting.Request = nil
   181  	buf := bytes.NewBuffer(data)
   182  	pkg := impl.NewDubboPackage(buf)
   183  	pkg.SetBody(make([]interface{}, 7))
   184  	err := pkg.Unmarshal()
   185  	if err != nil {
   186  		originErr := perrors.Cause(err)
   187  		if originErr == hessian.ErrHeaderNotEnough || originErr == hessian.ErrBodyNotEnough {
   188  			// FIXME
   189  			return nil, 0, originErr
   190  		}
   191  		return request, 0, perrors.WithStack(err)
   192  	}
   193  	request = &remoting.Request{
   194  		ID:       pkg.Header.ID,
   195  		SerialID: pkg.Header.SerialID,
   196  		TwoWay:   pkg.Header.Type&impl.PackageRequest_TwoWay != 0x00,
   197  		Event:    pkg.Header.Type&impl.PackageHeartbeat != 0x00,
   198  	}
   199  	if (pkg.Header.Type & impl.PackageHeartbeat) == 0x00 {
   200  		// convert params of request
   201  		req := pkg.Body.(map[string]interface{})
   202  
   203  		// invocation := request.Data.(*invocation.RPCInvocation)
   204  		var methodName string
   205  		var args []interface{}
   206  		attachments := make(map[string]interface{})
   207  		if req[impl.DubboVersionKey] != nil {
   208  			// dubbo version
   209  			request.Version = req[impl.DubboVersionKey].(string)
   210  		}
   211  		// path
   212  		attachments[constant.PathKey] = pkg.Service.Path
   213  		// version
   214  		attachments[constant.VersionKey] = pkg.Service.Version
   215  		// method
   216  		methodName = pkg.Service.Method
   217  		args = req[impl.ArgsKey].([]interface{})
   218  		attachments = req[impl.AttachmentsKey].(map[string]interface{})
   219  		invoc := invocation.NewRPCInvocationWithOptions(invocation.WithAttachments(attachments),
   220  			invocation.WithArguments(args), invocation.WithMethodName(methodName))
   221  		request.Data = invoc
   222  
   223  	}
   224  	return request, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
   225  }
   226  
   227  // decode response
   228  func (c *DubboTestCodec) decodeResponse(data []byte) (*remoting.Response, int, error) {
   229  	buf := bytes.NewBuffer(data)
   230  	pkg := impl.NewDubboPackage(buf)
   231  	err := pkg.Unmarshal()
   232  	if err != nil {
   233  		originErr := perrors.Cause(err)
   234  		// if the data is very big, so the receive need much times.
   235  		if originErr == hessian.ErrHeaderNotEnough || originErr == hessian.ErrBodyNotEnough {
   236  			return nil, 0, originErr
   237  		}
   238  		return nil, 0, perrors.WithStack(err)
   239  	}
   240  	response := &remoting.Response{
   241  		ID: pkg.Header.ID,
   242  		// Version:  pkg.Header.,
   243  		SerialID: pkg.Header.SerialID,
   244  		Status:   pkg.Header.ResponseStatus,
   245  		Event:    (pkg.Header.Type & impl.PackageHeartbeat) != 0,
   246  	}
   247  	var error error
   248  	if pkg.Header.Type&impl.PackageHeartbeat != 0x00 {
   249  		if pkg.Header.Type&impl.PackageResponse != 0x00 {
   250  			if pkg.Err != nil {
   251  				error = pkg.Err
   252  			}
   253  		} else {
   254  			response.Status = hessian.Response_OK
   255  			// reply(session, p, hessian.PackageHeartbeat)
   256  		}
   257  		return response, hessian.HEADER_LENGTH + pkg.Header.BodyLen, error
   258  	}
   259  	rpcResult := &protocol.RPCResult{}
   260  	response.Result = rpcResult
   261  	if pkg.Header.Type&impl.PackageRequest == 0x00 {
   262  		if pkg.Err != nil {
   263  			rpcResult.Err = pkg.Err
   264  		} else if pkg.Body.(*impl.ResponsePayload).Exception != nil {
   265  			rpcResult.Err = pkg.Body.(*impl.ResponsePayload).Exception
   266  			response.Error = rpcResult.Err
   267  		}
   268  		rpcResult.Attrs = pkg.Body.(*impl.ResponsePayload).Attachments
   269  		rpcResult.Rest = pkg.Body.(*impl.ResponsePayload).RspObj
   270  	}
   271  
   272  	return response, hessian.HEADER_LENGTH + pkg.Header.BodyLen, nil
   273  }