PageRenderTime 26ms CodeModel.GetById 18ms app.highlight 6ms RepoModel.GetById 0ms app.codeStats 1ms

/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}