dubbo.apache.org/dubbo-go/v3@v3.1.1/remoting/exchange.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 remoting
    19  
    20  import (
    21  	"fmt"
    22  	"sync"
    23  	"time"
    24  )
    25  
    26  import (
    27  	"github.com/dubbogo/gost/log/logger"
    28  
    29  	"go.uber.org/atomic"
    30  )
    31  
    32  import (
    33  	"dubbo.apache.org/dubbo-go/v3/common"
    34  )
    35  
    36  var (
    37  	sequence         atomic.Int64    // generate request ID for global use
    38  	pendingResponses = new(sync.Map) // store requestID and response
    39  )
    40  
    41  type SequenceType int64
    42  
    43  func init() {
    44  	sequence.Store(0)
    45  }
    46  
    47  // SequenceID increase 2 for every request as the same before. We expect that
    48  // the request from client to server, the requestID is even; but from server
    49  // to client, the requestID is odd.
    50  func SequenceID() int64 {
    51  	return sequence.Add(2)
    52  }
    53  
    54  // Request is the request for transport layer.
    55  type Request struct {
    56  	ID       int64
    57  	Version  string // protocol version
    58  	SerialID byte   // serial ID (ignore)
    59  	Data     interface{}
    60  	TwoWay   bool
    61  	Event    bool
    62  }
    63  
    64  // NewRequest aims to create Request. The ID is auto increase.
    65  func NewRequest(version string) *Request {
    66  	return &Request{
    67  		ID:      SequenceID(),
    68  		Version: version,
    69  	}
    70  }
    71  
    72  // Response is the response for transport layer.
    73  type Response struct {
    74  	ID       int64
    75  	Version  string
    76  	SerialID byte
    77  	Status   uint8
    78  	Event    bool
    79  	Error    error
    80  	Result   interface{}
    81  }
    82  
    83  // NewResponse create to a new Response.
    84  func NewResponse(id int64, version string) *Response {
    85  	return &Response{
    86  		ID:      id,
    87  		Version: version,
    88  	}
    89  }
    90  
    91  func (response *Response) IsHeartbeat() bool {
    92  	return response.Event && response.Result == nil
    93  }
    94  
    95  func (response *Response) Handle() {
    96  	pendingResponse := removePendingResponse(SequenceType(response.ID))
    97  	if pendingResponse == nil {
    98  		logger.Errorf("failed to get pending response context for response package %s", *response)
    99  		return
   100  	}
   101  
   102  	pendingResponse.response = response
   103  
   104  	if pendingResponse.Callback == nil {
   105  		pendingResponse.Err = pendingResponse.response.Error
   106  		close(pendingResponse.Done)
   107  	} else {
   108  		pendingResponse.Callback(pendingResponse.GetCallResponse())
   109  	}
   110  }
   111  
   112  func (response *Response) String() string {
   113  	return fmt.Sprintf("&remoting.Response{ID: %d, Version: %s, SerialID: %d, Status: %d, Event: %v, Error: %v, Result: %v}",
   114  		response.ID, response.Version, response.SerialID, response.Status, response.Event, response.Error, response.Result)
   115  }
   116  
   117  type Options struct {
   118  	ConnectTimeout time.Duration
   119  }
   120  
   121  // AsyncCallbackResponse async response for dubbo
   122  type AsyncCallbackResponse struct {
   123  	common.CallbackResponse
   124  	Opts      Options
   125  	Cause     error
   126  	Start     time.Time // invoke(call) start time == write start time
   127  	ReadStart time.Time // read start time, write duration = ReadStart - Start
   128  	Reply     interface{}
   129  }
   130  
   131  // PendingResponse is the client sends request to server, there is one
   132  // pendingResponse at client side to wait the response from server.
   133  type PendingResponse struct {
   134  	seq       int64
   135  	Err       error
   136  	start     time.Time
   137  	ReadStart time.Time
   138  	Callback  common.AsyncCallback
   139  	response  *Response
   140  	Reply     interface{}
   141  	Done      chan struct{}
   142  }
   143  
   144  // NewPendingResponse aims to create PendingResponse.
   145  // ID is always from ID of Request
   146  func NewPendingResponse(id int64) *PendingResponse {
   147  	return &PendingResponse{
   148  		seq:      id,
   149  		start:    time.Now(),
   150  		response: &Response{},
   151  		Done:     make(chan struct{}),
   152  	}
   153  }
   154  
   155  func (r *PendingResponse) SetResponse(response *Response) {
   156  	r.response = response
   157  }
   158  
   159  // GetCallResponse is used for callback of async.
   160  // It is will return AsyncCallbackResponse.
   161  func (r PendingResponse) GetCallResponse() common.CallbackResponse {
   162  	return AsyncCallbackResponse{
   163  		Cause:     r.Err,
   164  		Start:     r.start,
   165  		ReadStart: r.ReadStart,
   166  		Reply:     r.response,
   167  	}
   168  }
   169  
   170  // AddPendingResponse stores the response into map
   171  func AddPendingResponse(pr *PendingResponse) {
   172  	pendingResponses.Store(SequenceType(pr.seq), pr)
   173  }
   174  
   175  // get and remove response
   176  func removePendingResponse(seq SequenceType) *PendingResponse {
   177  	if pendingResponses == nil {
   178  		return nil
   179  	}
   180  	if presp, ok := pendingResponses.Load(seq); ok {
   181  		pendingResponses.Delete(seq)
   182  		return presp.(*PendingResponse)
   183  	}
   184  	return nil
   185  }
   186  
   187  // GetPendingResponse gets the response
   188  func GetPendingResponse(seq SequenceType) *PendingResponse {
   189  	if presp, ok := pendingResponses.Load(seq); ok {
   190  		return presp.(*PendingResponse)
   191  	}
   192  	return nil
   193  }