/// <summary> /// Constructor /// </summary> /// <param name="options">options to initialize</param> public EtcdClient(EtcdClientOpitions options) { if (options == null) throw new ArgumentNullException("options"); if (options.Urls == null || options.Urls.Length == 0) throw new ArgumentException("`EtcdClientOpitions.Urls` does not contain valid url"); WebRequestHandler handler = new WebRequestHandler() { UseProxy = options.UseProxy, AllowAutoRedirect = false, AllowPipelining = true, CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore), }; if (options.X509Certificate != null) handler.ClientCertificates.Add(options.X509Certificate); AuthenticationHeaderValue authenticationHeaderValue = null; if( !string.IsNullOrWhiteSpace(options.Username) && !string.IsNullOrWhiteSpace(options.Password) ) { string auth = string.Format("{0}:{1}", options.Username, options.Password); authenticationHeaderValue = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(auth))); } _jsonDeserializer = options.JsonDeserializer == null ? new DefaultJsonDeserializer() : options.JsonDeserializer; if (options.IgnoreCertificateError) handler.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; }; HttpClientEx [] httpClients = options.Urls.Select(u => { if (string.IsNullOrWhiteSpace(u)) throw new ArgumentNullException("`urls` array contains empty url"); HttpClientEx httpClient = new HttpClientEx(handler); httpClient.BaseAddress = new Uri(u); httpClient.DefaultRequestHeaders.Authorization = authenticationHeaderValue; return httpClient; }).ToArray(); // make the clients as a ring, so that we can try the next one when one fails if( httpClients.Length > 1 ) { for( int i = httpClients.Length - 2; i >= 0; i--) { httpClients[i].Next = httpClients[i + 1]; } } httpClients[httpClients.Length - 1].Next = httpClients[0]; // pick a client randomly _currentClient = httpClients[DateTime.UtcNow.Ticks % httpClients.Length]; }
/// <summary> /// Constructor /// </summary> /// <param name="options">options to initialize</param> public EtcdClient(EtcdClientOpitions options) { if (options == null) { throw new ArgumentNullException("options"); } if (options.Urls == null || options.Urls.Length == 0) { throw new ArgumentException("`EtcdClientOpitions.Urls` does not contain valid url"); } #if NET45 WebRequestHandler handler = new WebRequestHandler() { UseProxy = options.UseProxy, AllowAutoRedirect = false, AllowPipelining = true, CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore), }; if (options.X509Certificate != null) { handler.ClientCertificates.Add(options.X509Certificate); } #endif AuthenticationHeaderValue authenticationHeaderValue = null; if (!string.IsNullOrWhiteSpace(options.Username) && !string.IsNullOrWhiteSpace(options.Password)) { string auth = string.Format("{0}:{1}", options.Username, options.Password); authenticationHeaderValue = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(auth))); } _jsonDeserializer = options.JsonDeserializer == null ? new DefaultJsonDeserializer() : options.JsonDeserializer; #if NET45 if (options.IgnoreCertificateError) { handler.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return(true); } } ; #endif HttpClientEx [] httpClients = options.Urls.Select(u => { if (string.IsNullOrWhiteSpace(u)) { throw new ArgumentNullException("`urls` array contains empty url"); } #if NET45 HttpClientEx httpClient = new HttpClientEx(handler); #else HttpClientEx httpClient = new HttpClientEx(); #endif httpClient.BaseAddress = new Uri(u); httpClient.DefaultRequestHeaders.Authorization = authenticationHeaderValue; return(httpClient); }).ToArray(); // make the clients as a ring, so that we can try the next one when one fails if (httpClients.Length > 1) { for (int i = httpClients.Length - 2; i >= 0; i--) { httpClients[i].Next = httpClients[i + 1]; } } httpClients[httpClients.Length - 1].Next = httpClients[0]; // pick a client randomly _currentClient = httpClients[DateTime.UtcNow.Ticks % httpClients.Length]; }
private async Task <EtcdResponse> SendRequest(HttpMethod method, string requestUri, IEnumerable <KeyValuePair <string, string> > formFields = null) { HttpClientEx startClient = _currentClient; HttpClientEx currentClient = _currentClient; for (; ;) { try { using (HttpRequestMessage requestMessage = new HttpRequestMessage(method, requestUri)) { if (formFields != null) { requestMessage.Content = new FormUrlEncodedContent(formFields); } using (HttpResponseMessage responseMessage = await currentClient.SendAsync(requestMessage)) { string json = null; if (responseMessage.Content != null) { json = await responseMessage.Content.ReadAsStringAsync(); } if (!responseMessage.IsSuccessStatusCode) { if (!string.IsNullOrWhiteSpace(json)) { ErrorResponse errorResponse = null; try { errorResponse = _jsonDeserializer.Deserialize <ErrorResponse>(json); } catch { } if (errorResponse != null) { throw EtcdGenericException.Create(requestMessage, errorResponse); } } currentClient = currentClient.Next; if (currentClient != startClient) { // try the next continue; } else { responseMessage.EnsureSuccessStatusCode(); } } // if currentClient != _currentClient, update _currentClient if (currentClient != startClient) { Interlocked.CompareExchange(ref _currentClient, currentClient, startClient); } if (!string.IsNullOrWhiteSpace(json)) { EtcdResponse resp = _jsonDeserializer.Deserialize <EtcdResponse>(json); resp.EtcdServer = currentClient.BaseAddress.OriginalString; resp.EtcdClusterID = GetStringHeader(responseMessage, "X-Etcd-Cluster-Id"); resp.EtcdIndex = GetLongHeader(responseMessage, "X-Etcd-Index"); resp.RaftIndex = GetLongHeader(responseMessage, "X-Raft-Index"); resp.RaftTerm = GetLongHeader(responseMessage, "X-Raft-Term"); long previousIndex = _lastIndex; if (resp.EtcdIndex > previousIndex) { Interlocked.CompareExchange(ref _lastIndex, resp.EtcdIndex, previousIndex); } this.ClusterID = resp.EtcdClusterID; return(resp); } return(null); } } } catch (EtcdRaftException) { currentClient = currentClient.Next; if (currentClient != startClient) { continue; // try the next } else { throw; // tried all clients, all failed } } catch (EtcdGenericException) { throw; } catch (Exception) { currentClient = currentClient.Next; if (currentClient != startClient) { continue; // try the next } else { throw; // tried all clients, all failed } } } }