dubbo.apache.org/dubbo-go/v3@v3.1.1/remoting/exchange_client.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 "errors" 22 "time" 23 ) 24 25 import ( 26 "github.com/dubbogo/gost/log/logger" 27 28 uatomic "go.uber.org/atomic" 29 ) 30 31 import ( 32 "dubbo.apache.org/dubbo-go/v3/common" 33 "dubbo.apache.org/dubbo-go/v3/protocol" 34 ) 35 36 // Client is the interface that wraps SetExchangeClient、 Connect、Close、Request and 37 // IsAvailable method. It is interface of client for network communication. If you 38 // use getty as network communication, you should define GettyClient that implements 39 // this interface. 40 // 41 // SetExchangeClient method sets a ExchangeClient instance. 42 // 43 // Connect method is to connect url. 44 // 45 // Close method is for destroy. 46 // 47 // Request method is sending request to server. 48 // 49 // IsAvailable method checks whether the client is still available. 50 type Client interface { 51 SetExchangeClient(client *ExchangeClient) 52 Connect(url *common.URL) error 53 Close() 54 Request(request *Request, timeout time.Duration, response *PendingResponse) error 55 IsAvailable() bool 56 } 57 58 // ExchangeClient is abstraction level. it is like facade. 59 type ExchangeClient struct { 60 ConnectTimeout time.Duration // timeout for connecting server 61 address string // server address for dialing. The format: ip:port 62 client Client // dealing with the transport 63 init bool // the tag for init. 64 activeNum uatomic.Uint32 // the number of service using the exchangeClient 65 } 66 67 // NewExchangeClient returns a ExchangeClient. 68 func NewExchangeClient(url *common.URL, client Client, connectTimeout time.Duration, lazyInit bool) *ExchangeClient { 69 exchangeClient := &ExchangeClient{ 70 ConnectTimeout: connectTimeout, 71 address: url.Location, 72 client: client, 73 } 74 if !lazyInit { 75 if err := exchangeClient.doInit(url); err != nil { 76 return nil 77 } 78 } 79 exchangeClient.IncreaseActiveNumber() 80 return exchangeClient 81 } 82 83 func (cl *ExchangeClient) doInit(url *common.URL) error { 84 if cl.init { 85 return nil 86 } 87 if cl.client.Connect(url) != nil { 88 // retry for a while 89 time.Sleep(100 * time.Millisecond) 90 if cl.client.Connect(url) != nil { 91 logger.Errorf("Failed to connect server %+v " + url.Location) 92 return errors.New("Failed to connect server " + url.Location) 93 } 94 } 95 // FIXME atomic operation 96 cl.init = true 97 return nil 98 } 99 100 // IncreaseActiveNumber increase number of service using client. 101 func (client *ExchangeClient) IncreaseActiveNumber() uint32 { 102 return client.activeNum.Add(1) 103 } 104 105 // DecreaseActiveNumber decrease number of service using client. 106 func (client *ExchangeClient) DecreaseActiveNumber() uint32 { 107 return client.activeNum.Sub(1) 108 } 109 110 // GetActiveNumber get number of service using client. 111 func (client *ExchangeClient) GetActiveNumber() uint32 { 112 return client.activeNum.Load() 113 } 114 115 // Request means two way request. 116 func (client *ExchangeClient) Request(invocation *protocol.Invocation, url *common.URL, timeout time.Duration, 117 result *protocol.RPCResult) error { 118 if er := client.doInit(url); er != nil { 119 return er 120 } 121 request := NewRequest("2.0.2") 122 request.Data = invocation 123 request.Event = false 124 request.TwoWay = true 125 126 rsp := NewPendingResponse(request.ID) 127 rsp.response = NewResponse(request.ID, "2.0.2") 128 rsp.Reply = (*invocation).Reply() 129 AddPendingResponse(rsp) 130 131 err := client.client.Request(request, timeout, rsp) 132 // request error 133 if err != nil { 134 result.Err = err 135 return err 136 } 137 if resultTmp, ok := rsp.response.Result.(*protocol.RPCResult); ok { 138 result.Rest = resultTmp.Rest 139 result.Attrs = resultTmp.Attrs 140 result.Err = resultTmp.Err 141 } else { 142 logger.Warnf("[ExchangeClient.Request] The type of result is unexpected, we want *protocol.RPCResult, "+ 143 "but we got %T", rsp.response.Result) 144 } 145 return nil 146 } 147 148 // AsyncRequest async two way request. 149 func (client *ExchangeClient) AsyncRequest(invocation *protocol.Invocation, url *common.URL, timeout time.Duration, 150 callback common.AsyncCallback, result *protocol.RPCResult) error { 151 if er := client.doInit(url); er != nil { 152 return er 153 } 154 request := NewRequest("2.0.2") 155 request.Data = invocation 156 request.Event = false 157 request.TwoWay = true 158 159 rsp := NewPendingResponse(request.ID) 160 rsp.response = NewResponse(request.ID, "2.0.2") 161 rsp.Callback = callback 162 rsp.Reply = (*invocation).Reply() 163 AddPendingResponse(rsp) 164 165 err := client.client.Request(request, timeout, rsp) 166 if err != nil { 167 result.Err = err 168 return err 169 } 170 result.Rest = rsp.response 171 return nil 172 } 173 174 // Send sends oneway request. 175 func (client *ExchangeClient) Send(invocation *protocol.Invocation, url *common.URL, timeout time.Duration) error { 176 if er := client.doInit(url); er != nil { 177 return er 178 } 179 request := NewRequest("2.0.2") 180 request.Data = invocation 181 request.Event = false 182 request.TwoWay = false 183 184 rsp := NewPendingResponse(request.ID) 185 rsp.response = NewResponse(request.ID, "2.0.2") 186 187 err := client.client.Request(request, timeout, rsp) 188 if err != nil { 189 return err 190 } 191 return nil 192 } 193 194 // Close close the client. 195 func (client *ExchangeClient) Close() { 196 client.client.Close() 197 client.init = false 198 } 199 200 // IsAvailable to check if the underlying network client is available yet. 201 func (client *ExchangeClient) IsAvailable() bool { 202 return client.client.IsAvailable() 203 }