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