/Main/src/DynamicDataDisplay.Maps/Servers/Network/NetworkTileServer.cs

# · C# · 256 lines · 192 code · 46 blank · 18 comment · 24 complexity · 8a3c3cde53b1fea837daafd75695f483 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Net;
  6. using System.Diagnostics;
  7. using System.Windows.Media.Imaging;
  8. using System.Windows.Media;
  9. using System.IO;
  10. using System.Runtime.CompilerServices;
  11. using Microsoft.Research.DynamicDataDisplay.Maps.Servers.Network;
  12. using Microsoft.Research.DynamicDataDisplay;
  13. using Microsoft.Research.DynamicDataDisplay.Common;
  14. using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
  15. using System.Net.NetworkInformation;
  16. //using System.Threading.Collections;
  17. //using System.Threading.Tasks;
  18. using Microsoft.Research.DynamicDataDisplay.Maps;
  19. using System.Windows;
  20. using Microsoft.Research.DynamicDataDisplay.Maps.Servers;
  21. using System.Threading;
  22. namespace Microsoft.Research.DynamicDataDisplay.Charts.Maps
  23. {
  24. public abstract class NetworkTileServer : SourceTileServer, IWeakEventListener
  25. {
  26. protected NetworkTileServer()
  27. {
  28. NetworkAvailabilityManager.AddListener(this);
  29. isNetworkAvailable = NetworkInterface.GetIsNetworkAvailable();
  30. }
  31. private bool isNetworkAvailable = false;
  32. protected sealed override string GetCustomName()
  33. {
  34. return "Network " + ServerName;
  35. }
  36. #region ITileServer Members
  37. public override bool Contains(TileIndex id)
  38. {
  39. return isNetworkAvailable && MinLevel <= id.Level && id.Level <= MaxLevel;
  40. }
  41. private int runningDownloadsNum = 0;
  42. protected int RunningDownloadsNum
  43. {
  44. get { return runningDownloadsNum; }
  45. }
  46. //private readonly ConcurrentStack<TileIndex> waitingIDs = new ConcurrentStack<TileIndex>();
  47. private readonly Stack<TileIndex> waitingIDs = new Stack<TileIndex>();
  48. private bool firstCall = true;
  49. public override void BeginLoadImage(TileIndex id)
  50. {
  51. VerifyTileIndex(id);
  52. string uri = CreateRequestUriCore(MapTileProvider.NormalizeIndex(id));
  53. bool useMultipleServers = ServersNum != 0;
  54. if (useMultipleServers)
  55. {
  56. CurrentServer++;
  57. if (CurrentServer >= MinServer + ServersNum)
  58. {
  59. CurrentServer = MinServer;
  60. }
  61. }
  62. if (runningDownloadsNum >= MaxConcurrentDownloads)
  63. {
  64. lock(waitingIDs)
  65. waitingIDs.Push(id);
  66. return;
  67. }
  68. MapsTraceSource.Instance.ServerInformationTraceSource.TraceInformation("\"{0}\" - began to load url=\"{1}\"", GetCustomName(), uri);
  69. WebRequest request = WebRequest.Create(uri);
  70. AdjustRequest(request);
  71. runningDownloadsNum++;
  72. // this is hack to prevent freezing when request.BeginGetResponse was called
  73. // at the 1st time
  74. if (!firstCall)
  75. {
  76. request.BeginGetResponse(ResponseReadyCallback,
  77. new ResponseCallbackInfo { ID = id, Request = request });
  78. }
  79. else
  80. {
  81. ThreadPool.QueueUserWorkItem(new WaitCallback(dummy => {
  82. //Task.Create(o =>
  83. //{
  84. request.BeginGetResponse(ResponseReadyCallback, new ResponseCallbackInfo { ID = id, Request = request });
  85. //}).WithExceptionThrowingInDispatcher(Dispatcher);
  86. }));
  87. }
  88. }
  89. protected override void ReportFailure(TileIndex id)
  90. {
  91. runningDownloadsNum--;
  92. BeginLoadImageFromQueue();
  93. base.ReportFailure(id);
  94. }
  95. private void BeginLoadImageFromQueue()
  96. {
  97. if (runningDownloadsNum < MaxConcurrentDownloads)
  98. {
  99. TileIndex id = new TileIndex();
  100. lock (waitingIDs)
  101. if (waitingIDs.Count > 0)
  102. id = waitingIDs.Pop();
  103. else
  104. return;
  105. BeginLoadImage(id);
  106. // commented by bs
  107. //if (waitingIDs.TryPop(out id))
  108. //{
  109. // //Debug.WriteLine("ID = " + id + " removed from queue");
  110. // BeginLoadImage(id);
  111. //}
  112. }
  113. }
  114. protected override void ReportSuccess(Stream stream, BitmapSource bmp, TileIndex id)
  115. {
  116. runningDownloadsNum--;
  117. BeginLoadImageFromQueue();
  118. base.ReportSuccess(stream, bmp, id);
  119. }
  120. protected virtual void AdjustRequest(WebRequest request)
  121. {
  122. HttpWebRequest r = (HttpWebRequest)request;
  123. r.UserAgent = UserAgent;
  124. if (!String.IsNullOrEmpty(Referer))
  125. {
  126. r.Referer = Referer;
  127. }
  128. }
  129. private void VerifyTileIndex(TileIndex id)
  130. {
  131. if (id.Level < MinLevel || id.Level > MaxLevel)
  132. throw new ArgumentException(
  133. String.Format(
  134. DynamicDataDisplay.Maps.Properties.Resources.InvalidTileLevel,
  135. id.Level, MinLevel, MaxLevel),
  136. "id");
  137. }
  138. private void ResponseReadyCallback(IAsyncResult ar)
  139. {
  140. ResponseCallbackInfo info = (ResponseCallbackInfo)ar.AsyncState;
  141. firstCall = false;
  142. try
  143. {
  144. var response = info.Request.EndGetResponse(ar);
  145. bool goodTile = IsGoodTileResponse(response);
  146. if (goodTile)
  147. {
  148. UpdateStatistics(() =>
  149. {
  150. Statistics.LongValues["DownloadedBytes"] += response.ContentLength;
  151. Statistics.IntValues["ImagesLoaded"]++;
  152. });
  153. // this emulates wrong response from server
  154. //byte[] bytes = new byte[] { 0, 1, 2 };
  155. //MemoryStream stream = new MemoryStream(bytes);
  156. //BeginLoadBitmapImpl(stream, info.ID);
  157. BeginLoadBitmapImpl(response.GetResponseStream(), info.ID);
  158. }
  159. else
  160. {
  161. ReportFailure(info.ID);
  162. }
  163. }
  164. catch (WebException exc)
  165. {
  166. string responseUri = exc.Response != null ? exc.Response.ResponseUri.ToString() : "Response=null";
  167. MapsTraceSource.Instance.ServerInformationTraceSource.TraceInformation("{0} Network \"{1}\" Failure: url=\"{2}\": {3}", DateTime.Now, ServerName, responseUri, exc.Message);
  168. ReportFailure(info.ID);
  169. }
  170. }
  171. protected virtual bool IsGoodTileResponse(WebResponse response)
  172. {
  173. var contentType = response.ContentType.ToLower();
  174. if (contentType == "image/jpeg" || contentType == "image/png" || contentType == "image/bmp" || contentType == "image/gif")
  175. return true;
  176. else
  177. return false;
  178. }
  179. public string CreateRequestUri(TileIndex id)
  180. {
  181. return CreateRequestUriCore(id);
  182. }
  183. protected abstract string CreateRequestUriCore(TileIndex index);
  184. #endregion
  185. private sealed class ResponseCallbackInfo
  186. {
  187. public WebRequest Request { get; set; }
  188. public TileIndex ID { get; set; }
  189. }
  190. #region IWeakEventListener Members
  191. public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
  192. {
  193. if (managerType != typeof(NetworkAvailabilityManager))
  194. return false;
  195. Dispatcher.BeginInvoke(() =>
  196. {
  197. isNetworkAvailable = NetworkInterface.GetIsNetworkAvailable();
  198. RaiseChangedEvent();
  199. });
  200. return true;
  201. }
  202. #endregion
  203. #region IDisposable Members
  204. public override void Dispose()
  205. {
  206. NetworkAvailabilityManager.RemoveListener(this);
  207. }
  208. #endregion
  209. }
  210. }