OSDN Git Service

HttpConnection.GlobalHttpClientを追加, MyCommon.CreateHttpClient()をHttpConnectionクラスに移動
authorKimura Youichi <kim.upsilon@bucyou.net>
Sat, 28 Jun 2014 20:34:59 +0000 (05:34 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Mon, 30 Jun 2014 10:26:38 +0000 (19:26 +0900)
 * プロキシ設定の変更を反映するため、新たに追加した HttpConnection.GlobalHttpClient
   を積極的に使用する。
 * パフォーマンス上の理由でも HttpClient を頻繁に生成・破棄すべきでない。
   参照: stackoverflow.com/questions/22560971/22561368#22561368

OpenTween/Connection/HttpConnection.cs
OpenTween/Connection/Imgur.cs
OpenTween/MyCommon.cs
OpenTween/ShortUrl.cs
OpenTween/Thumbnail/ThumbnailInfo.cs
OpenTween/Tween.cs
OpenTween/TweetThumbnail.cs
OpenTween/UserInfoDialog.cs

index f3419da..fe3000e 100644 (file)
@@ -27,7 +27,9 @@
 using System.Collections.Specialized;
 using System.IO;
 using System.Net;
+using System.Net.Http;
 using System.Text;
+using System.Threading;
 using System;
 using System.Collections.Generic;
 using System.IO.Compression;
@@ -47,12 +49,12 @@ namespace OpenTween
         ///<summary>
         ///プロキシ
         ///</summary>
-        internal static WebProxy proxy = null;
+        private static IWebProxy proxy = null;
 
         ///<summary>
         ///ユーザーが選択したプロキシの方式
         ///</summary>
-        internal static ProxyType proxyKind = ProxyType.IE;
+        private static ProxyType proxyKind = ProxyType.IE;
 
         ///<summary>
         ///初期化済みフラグ
@@ -610,6 +612,21 @@ namespace OpenTween
         }
         #endregion
 
+        /// <summary>
+        /// OpenTween 内で共通して使用する HttpClient インスタンス
+        /// </summary>
+        public static HttpClient GlobalHttpClient
+        {
+            get { return globalHttpClient; }
+        }
+
+        /// <summary>
+        /// Webプロキシの設定が変更された場合に発生します
+        /// </summary>
+        public static event EventHandler WebProxyChanged;
+
+        private static HttpClient globalHttpClient = CreateHttpClient(new HttpClientHandler());
+
         ///<summary>
         ///通信クラスの初期化処理。タイムアウト値とプロキシを設定する
         ///</summary>
@@ -622,34 +639,80 @@ namespace OpenTween
         ///<param name="proxyPort">プロキシのポート番号</param>
         ///<param name="proxyUser">プロキシ認証が必要な場合のユーザ名。不要なら空文字</param>
         ///<param name="proxyPassword">プロキシ認証が必要な場合のパスワード。不要なら空文字</param>
-        public static void InitializeConnection(
-                int timeout,
-                ProxyType proxyType,
-                string proxyAddress,
-                int proxyPort,
-                string proxyUser,
-                string proxyPassword)
+        public static void InitializeConnection(int timeout,
+            ProxyType proxyType, string proxyAddress, int proxyPort,
+            string proxyUser, string proxyPassword)
         {
-            isInitialize = true;
+            HttpConnection.isInitialize = true;
+            HttpConnection.DefaultTimeout = timeout * 1000; // s -> ms
+
             ServicePointManager.Expect100Continue = false;
-            DefaultTimeout = timeout * 1000;     //s -> ms
+
+            SetWebProxy(proxyType, proxyAddress, proxyPort, proxyUser, proxyPassword);
+        }
+
+        public static void SetWebProxy(ProxyType proxyType, string proxyAddress, int proxyPort,
+            string proxyUser, string proxyPassword)
+        {
+            IWebProxy proxy;
             switch (proxyType)
             {
                 case ProxyType.None:
                     proxy = null;
                     break;
                 case ProxyType.Specified:
-                    proxy = new WebProxy("http://" + proxyAddress + ":" + proxyPort);
-                    if (!String.IsNullOrEmpty(proxyUser) || !String.IsNullOrEmpty(proxyPassword))
+                    proxy = new WebProxy(proxyAddress, proxyPort);
+                    if (!string.IsNullOrEmpty(proxyUser) || !string.IsNullOrEmpty(proxyPassword))
                         proxy.Credentials = new NetworkCredential(proxyUser, proxyPassword);
                     break;
                 case ProxyType.IE:
-                    //IE設定(システム設定)はデフォルト値なので処理しない
+                default:
+                    proxy = WebRequest.GetSystemWebProxy();
                     break;
             }
-            proxyKind = proxyType;
+
+            HttpConnection.proxyKind = proxyType;
+            HttpConnection.proxy = proxy;
 
             Win32Api.SetProxy(proxyType, proxyAddress, proxyPort, proxyUser, proxyPassword);
+
+            OnWebProxyChanged(EventArgs.Empty);
+        }
+
+        /// <summary>
+        /// プロキシ等の設定を施した HttpClient インスタンスを生成します
+        /// </summary>
+        /// <remarks>
+        /// 通常は HttpConnection.GlobalHttpClient を使用すべきです。
+        /// このメソッドを使用する場合は、WebProxyChanged イベントが発生する度に HttpClient を生成し直すように実装してください。
+        /// </remarks>
+        public static HttpClient CreateHttpClient(HttpClientHandler handler)
+        {
+            if (HttpConnection.proxy != null)
+            {
+                handler.UseProxy = true;
+                handler.Proxy = HttpConnection.proxy;
+            }
+            else
+            {
+                handler.UseProxy = false;
+            }
+
+            var client = new HttpClient(handler);
+            client.Timeout = TimeSpan.FromMilliseconds(HttpConnection.DefaultTimeout);
+            client.DefaultRequestHeaders.Add("User-Agent", MyCommon.GetUserAgentString());
+
+            return client;
+        }
+
+        private static void OnWebProxyChanged(EventArgs e)
+        {
+            var newClient = HttpConnection.CreateHttpClient(new HttpClientHandler());
+            var oldClient = Interlocked.Exchange(ref globalHttpClient, newClient);
+            oldClient.Dispose();
+
+            if (WebProxyChanged != null)
+                WebProxyChanged(null, e);
         }
     }
 }
\ No newline at end of file
index a01c82a..ba7fc08 100644 (file)
@@ -147,16 +147,13 @@ namespace OpenTween.Connection
                 content.Add(fileContent, "image", file.Name);
                 content.Add(titleContent, "title");
 
-                using (var http = MyCommon.CreateHttpClient())
                 using (var request = new HttpRequestMessage(HttpMethod.Post, UploadEndpoint))
                 {
-                    http.Timeout = TimeSpan.FromMinutes(1);
-
                     request.Headers.Authorization =
                         new AuthenticationHeaderValue("Client-ID", ApplicationSettings.ImgurClientID);
                     request.Content = content;
 
-                    using (var response = await http.SendAsync(request).ConfigureAwait(false))
+                    using (var response = await HttpConnection.GlobalHttpClient.SendAsync(request).ConfigureAwait(false))
                     {
                         response.EnsureSuccessStatusCode();
 
index cb0adc1..c5bf352 100644 (file)
@@ -976,41 +976,6 @@ namespace OpenTween
         }
 
         /// <summary>
-        /// OpenTween 内で共通して使う設定を施した HttpClient インスタンスを作成します
-        /// </summary>
-        public static HttpClient CreateHttpClient()
-        {
-            return CreateHttpClient(new HttpClientHandler());
-        }
-
-        /// <summary>
-        /// OpenTween 内で共通して使う設定を施した HttpClient インスタンスを作成します
-        /// </summary>
-        public static HttpClient CreateHttpClient(HttpClientHandler handler)
-        {
-            switch (HttpConnection.proxyKind)
-            {
-                case HttpConnection.ProxyType.None:
-                    handler.UseProxy = false;
-                    break;
-                case HttpConnection.ProxyType.Specified:
-                    handler.UseProxy = true;
-                    handler.Proxy = HttpConnection.proxy;
-                    break;
-                case HttpConnection.ProxyType.IE:
-                default:
-                    handler.UseProxy = true;
-                    handler.Proxy = WebRequest.GetSystemWebProxy();
-                    break;
-            }
-
-            var client = new HttpClient(handler);
-            client.DefaultRequestHeaders.Add("User-Agent", MyCommon.GetUserAgentString());
-
-            return client;
-        }
-
-        /// <summary>
         /// 指定された IDictionary を元にクエリ文字列を生成します
         /// </summary>
         /// <param name="param">生成するクエリの key-value コレクション</param>
index bf89cd9..4250c47 100644 (file)
@@ -31,6 +31,7 @@ using System.Linq;
 using System.Net.Http;
 using System.Text;
 using System.Text.RegularExpressions;
+using System.Threading;
 using System.Threading.Tasks;
 using System.Web;
 
@@ -122,18 +123,18 @@ namespace OpenTween
 
         static ShortUrl()
         {
-            _instance = new Lazy<ShortUrl>(() =>
-            {
-                var handler = new HttpClientHandler
-                {
-                    AllowAutoRedirect = false,
-                };
-
-                var http = MyCommon.CreateHttpClient(handler);
-                http.Timeout = new TimeSpan(0, 0, seconds: 5);
+            _instance = new Lazy<ShortUrl>(() => new ShortUrl(), true);
+        }
 
-                return new ShortUrl(http);
-            }, true);
+        internal ShortUrl()
+            : this(CreateDefaultHttpClient())
+        {
+            HttpConnection.WebProxyChanged += (o, e) =>
+            {
+                var newClient = CreateDefaultHttpClient();
+                var oldClient = Interlocked.Exchange(ref this.http, newClient);
+                oldClient.Dispose();
+            };
         }
 
         internal ShortUrl(HttpClient http)
@@ -488,5 +489,18 @@ namespace OpenTween
                 return response.Headers.Location;
             }
         }
+
+        private static HttpClient CreateDefaultHttpClient()
+        {
+            var handler = new HttpClientHandler
+            {
+                AllowAutoRedirect = false,
+            };
+
+            var http = HttpConnection.CreateHttpClient(handler);
+            http.Timeout = TimeSpan.FromSeconds(5);
+
+            return http;
+        }
     }
 }
index 67090aa..c9940da 100644 (file)
@@ -43,14 +43,7 @@ namespace OpenTween.Thumbnail
 
         public Task<MemoryImage> LoadThumbnailImageAsync(CancellationToken cancellationToken)
         {
-            return Task.Run(async () =>
-            {
-                using (var http = MyCommon.CreateHttpClient())
-                {
-                    return await this.LoadThumbnailImageAsync(http, cancellationToken)
-                        .ConfigureAwait(false);
-                }
-            }, cancellationToken);
+            return this.LoadThumbnailImageAsync(HttpConnection.GlobalHttpClient, cancellationToken);
         }
 
         public async virtual Task<MemoryImage> LoadThumbnailImageAsync(HttpClient http, CancellationToken cancellationToken)
index 6ebcdc2..88f9162 100644 (file)
@@ -53,7 +53,7 @@ namespace OpenTween
 {
     public partial class TweenMain : OTBaseForm
     {
-        private readonly HttpClient http;
+        private HttpClient http;
 
         //各種設定
         private Size _mySize;           //画面サイズ
@@ -12289,7 +12289,14 @@ namespace OpenTween
         private HookGlobalHotkey _hookGlobalHotkey;
         public TweenMain()
         {
-            this.http = MyCommon.CreateHttpClient();
+            this.http = HttpConnection.CreateHttpClient(new HttpClientHandler());
+            HttpConnection.WebProxyChanged += (o, e) =>
+            {
+                var newClient = HttpConnection.CreateHttpClient(new HttpClientHandler());
+                var oldClient = Interlocked.Exchange(ref this.http, newClient);
+                oldClient.Dispose();
+            };
+
             _hookGlobalHotkey = new HookGlobalHotkey(this);
 
             // この呼び出しは、Windows フォーム デザイナで必要です。
index 27ffcdc..39d2bb4 100644 (file)
@@ -44,8 +44,6 @@ namespace OpenTween
         public event EventHandler<ThumbnailDoubleClickEventArgs> ThumbnailDoubleClick;
         public event EventHandler<ThumbnailImageSearchEventArgs> ThumbnailImageSearchClick;
 
-        private readonly HttpClient http = MyCommon.CreateHttpClient();
-
         private object uiLockObj = new object();
 
         public ThumbnailInfo Thumbnail
@@ -92,7 +90,7 @@ namespace OpenTween
                 picbox.Tag = thumb;
                 picbox.ContextMenuStrip = this.contextMenuStrip;
 
-                var loadTask = picbox.SetImageFromTask(() => thumb.LoadThumbnailImageAsync(this.http, cancelToken));
+                var loadTask = picbox.SetImageFromTask(() => thumb.LoadThumbnailImageAsync(cancelToken));
                 loadTasks.Add(loadTask);
 
                 var tooltipText = thumb.TooltipText;
index 9acfca8..4a695c6 100644 (file)
@@ -163,14 +163,13 @@ namespace OpenTween
 
             await this.UserPicture.SetImageFromTask(async () =>
             {
-                using (var http = MyCommon.CreateHttpClient())
-                {
-                    var imageStream = await http.GetStreamAsync(imageUri.Replace("_normal", "_bigger"))
-                        .ConfigureAwait(false);
+                var uri = imageUri.Replace("_normal", "_bigger");
 
-                    return await MemoryImage.CopyFromStreamAsync(imageStream)
-                        .ConfigureAwait(false);
-                }
+                var imageStream = await HttpConnection.GlobalHttpClient.GetStreamAsync(uri)
+                    .ConfigureAwait(false);
+
+                return await MemoryImage.CopyFromStreamAsync(imageStream)
+                    .ConfigureAwait(false);
             });
         }