ProxySharp

Форк
0
/
ProxyManager.cs 
174 строки · 5.1 Кб
1
using ProxySharp.Providers.Selectors;
2
using System;
3
using System.Net.Http;
4
using System.Threading.Tasks;
5

6
namespace ProxySharp
7
{
8
    /// <summary>
9
    /// Provides methods to run requests through proxy by the current selector.
10
    /// </summary>
11
    public sealed class ProxyManager : IProxyManager<HttpClient, HttpResponseMessage>
12
    {
13
        private readonly IProxySelector _selector;
14
        private Func<HttpResponseMessage, Task<bool>> _validateAsync;
15
        private Action<HttpClient> _configure;
16
        private HttpClient _httpClient;
17
        private HttpClientHandler _httpClientHandler;
18

19
        /// <summary>
20
        /// Create new instance.
21
        /// </summary>
22
        /// <param name="selector">Proxy selector.</param>
23
        public ProxyManager(IProxySelector selector)
24
        {
25
            _selector = selector;
26
            
27
            _selector.CurrentChanged += SetWebProxy;
28

29
            _selector.SetCurrent();
30
        }
31

32
        /// <summary>
33
        /// Set next proxy by current selector.
34
        /// </summary>
35
        /// <returns>This instance.</returns>
36
        public IProxyManager<HttpClient, HttpResponseMessage> ChangeProxy()
37
        {
38
            _selector.SetCurrentToNext();
39

40
            return this;
41
        }
42

43
        /// <summary>
44
        /// Set validator to check query response.
45
        /// </summary>
46
        /// <param name="func">Validator.</param>
47
        /// <returns>This instance.</returns>
48
        public IProxyManager<HttpClient, HttpResponseMessage> UseValidator(Func<HttpResponseMessage, Task<bool>> func)
49
        {
50
            _validateAsync = func;
51

52
            return this;
53
        }
54

55
        /// <summary>
56
        /// Configure HttpClient used by the query.
57
        /// </summary>
58
        /// <param name="func">Setup function.</param>
59
        /// <returns>This instance.</returns>
60
        public IProxyManager<HttpClient, HttpResponseMessage> Configure(Action<HttpClient> func)
61
        {
62
            _configure = func;
63

64
            CreateAndConfigureClient();
65

66
            return this;
67
        }
68

69
        /// <summary>
70
        /// Run request to get the result.
71
        /// </summary>
72
        /// <remarks>
73
        /// If the request fails or the validator return <c>False</c>, will try to run the request through the next proxy.
74
        /// </remarks>
75
        /// <param name="func">Request.</param>
76
        /// <returns>Response.</returns>
77
        /// <exception cref="InvalidOperationException">Has no valid proxies.</exception>
78
        /// <exception cref="ArgumentNullException">Has no HTTP client.</exception>
79
        public async Task<HttpResponseMessage> RequestAsync(Func<HttpClient, Task<HttpResponseMessage>> func)
80
        {
81
            while (true)
82
            {
83
                ++_selector.Current.UsedCount;
84

85
                HttpResponseMessage response;
86

87
                try
88
                {
89
                    if (_httpClient == null)
90
                        throw new ArgumentNullException(nameof(_httpClient));
91

92
                    response = await func(_httpClient);
93
                }
94
                catch (Exception error)
95
                {
96
                    error.LogError();
97

98
                    ++_selector.Current.FailsCount;
99
                    _selector.Current.LastException = error;
100

101
                    _selector.SetCurrentToNext();
102

103
                    continue;
104
                }
105

106
                if (_validateAsync == null)
107
                    return response;
108

109
                try
110
                {
111
                    if (!await _validateAsync(response))
112
                    {
113
                        ++_selector.Current.FailsCount;
114

115
                        _selector.SetCurrentToNext();
116

117
                        continue;
118
                    }
119
                }
120
                catch (Exception error)
121
                {
122
                    error.LogError();
123

124
                    throw;
125
                }
126

127
                return response;
128
            }
129
        }
130

131
        /// <summary>
132
        /// Set current proxy.
133
        /// </summary>
134
        /// <param name="sender">Sender.</param>
135
        /// <param name="e">New proxy.</param>
136
        private void SetWebProxy(object sender, ProxyInfo e)
137
        {
138
            _httpClientHandler?.Dispose();
139

140
            _httpClientHandler = new HttpClientHandler
141
            {
142
                Proxy = e.ToWebProxy()
143
            };
144

145
            CreateAndConfigureClient();
146
        }
147

148
        /// <summary>
149
        /// Creates and configures an HTTP client.
150
        /// </summary>
151
        /// <exception cref="ArgumentNullException">Fires when the proxy is not set.</exception>
152
        private void CreateAndConfigureClient()
153
        {
154
            if (_httpClientHandler == null)
155
                throw new ArgumentNullException(nameof(_httpClientHandler));
156

157
            _httpClient?.Dispose();
158

159
            _httpClient = new HttpClient
160
            (
161
                handler: _httpClientHandler, 
162
                disposeHandler: false
163
            );
164

165
            _configure?.Invoke(_httpClient);
166
        }
167

168
        public void Dispose()
169
        {
170
            _httpClient?.Dispose();
171
            _httpClientHandler?.Dispose();
172
        }
173
    }
174
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.