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 }