00001 using System;
00002 using System.Collections.Generic;
00003 using System.Text;
00004 using NUnit.Framework;
00005 using System.Threading;
00006 using System.Net;
00007 using System.Net.Sockets;
00008 using System.Xml;
00009 using ICSharpCode.SharpZipLib;
00010 using System.IO;
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 namespace DCPlusPlus
00023 {
00030 [TestFixture]
00031 public class HubList
00032 {
00037 public delegate void CompletedEventHandler(HubList hub_list);
00042 public delegate void ProgressChangedEventHandler(HubList hub_list);
00047 public delegate void UnableToFetchEventHandler(HubList hub_list);
00048 protected Connection.ErrorCodes error_code = Connection.ErrorCodes.NoErrorYet;
00052 public Connection.ErrorCodes ErrorCode
00053 {
00054 get
00055 {
00056 return (error_code);
00057 }
00058 }
00059 protected int percentage=0;
00063 public int Percentage
00064 {
00065 get
00066 {
00067 return (percentage);
00068 }
00069 }
00070 protected string url;
00074 public string Url
00075 {
00076 get
00077 {
00078 return (url);
00079 }
00080 set
00081 {
00082 url = value;
00083 }
00084
00085 }
00086 protected List<Hub> hubs = new List<Hub>();
00090 public List<Hub> Hubs
00091 {
00092 get
00093 {
00094 return (hubs);
00095 }
00096
00097 }
00098 protected bool busy = false;
00102 public bool IsBusy
00103 {
00104 get
00105 {
00106 return (busy);
00107 }
00108 }
00109 protected string name = "";
00113 public string Name
00114 {
00115 get
00116 {
00117 return (name);
00118 }
00119 }
00120 protected string address = "";
00124 public string Address
00125 {
00126 get
00127 {
00128 return (address);
00129 }
00130 }
00134 public class Column
00135 {
00136 protected string name;
00140 public string Name
00141 {
00142 get
00143 {
00144 return (name);
00145 }
00146 set
00147 {
00148 name = value;
00149 }
00150 }
00151
00152 protected string type;
00156 public string Type
00157 {
00158 get
00159 {
00160 return (type);
00161 }
00162 set
00163 {
00164 type = value;
00165 }
00166 }
00167 }
00168 protected List<Column> columns= new List<Column>();
00172 public List<Column> Columns
00173 {
00174 get
00175 {
00176 return (columns);
00177 }
00178
00179 }
00184 public event CompletedEventHandler Completed;
00189 public event ProgressChangedEventHandler ProgressChanged;
00194 public event UnableToFetchEventHandler UnableToFetch;
00198 private WebClient wc = new WebClient();
00202 public HubList()
00203 {
00204 Url = "";
00205 wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
00206 wc.DownloadDataCompleted += new DownloadDataCompletedEventHandler(DownloadFileCallback);
00207 }
00212 public HubList(string HubListUrl)
00213 {
00214 Url = HubListUrl;
00215 wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
00216 wc.DownloadDataCompleted += new DownloadDataCompletedEventHandler(DownloadFileCallback);
00217 }
00223 public void FetchHubs()
00224 {
00225 if (!busy && !string.IsNullOrEmpty(url))
00226 {
00227 busy = true;
00228
00229 columns.Clear();
00230 percentage = 0;
00231 if (ProgressChanged != null)
00232 ProgressChanged(this);
00233 try
00234 {
00235 wc.DownloadDataAsync(new Uri(url));
00236 }
00237 catch (Exception ex)
00238 {
00239 Console.WriteLine("Exception occured during download: " + ex.Message);
00240 error_code = Connection.ErrorCodes.Exception;
00241 if (UnableToFetch != null)
00242 UnableToFetch(this);
00243 busy = false;
00244 }
00245 }
00246 }
00252 public void FetchHubs(string url)
00253 {
00254 this.url = url;
00255 FetchHubs();
00256 }
00260 public void AbortFetch()
00261 {
00262 try
00263 {
00264 wc.CancelAsync();
00265 }
00266 catch (Exception ex)
00267 {
00268 Console.WriteLine("Exception occured during abort: " + ex.Message);
00269 }
00270
00271 busy = false;
00272
00273 }
00280 private void DownloadFileCallback(object sender, DownloadDataCompletedEventArgs e)
00281 {
00282 try
00283 {
00284 if (e.Cancelled) return;
00285 if (e.Result == null || e.Result.Length == 0)
00286 {
00287 error_code = Connection.ErrorCodes.UrlNotFound;
00288 Console.WriteLine("Error downloading hublist.");
00289 if (UnableToFetch != null)
00290 UnableToFetch(this);
00291 return;
00292 }
00293
00294
00295
00296 byte[] input_bytes = e.Result;
00297 ProcessDownloadedBytes(input_bytes);
00298 }
00299 catch (Exception ex)
00300 {
00301 error_code = Connection.ErrorCodes.Exception;
00302 Console.WriteLine("exception during hublist fetch: " + ex.Message);
00303 if (UnableToFetch != null)
00304 UnableToFetch(this);
00305 busy = false;
00306 }
00307
00308 }
00315 private void ProcessDownloadedBytes(byte[] input_bytes)
00316 {
00317 ProcessDownloadedBytesHandler pdbh = new ProcessDownloadedBytesHandler(ProcessDownloadedBytesAsync);
00318 IAsyncResult result = pdbh.BeginInvoke(input_bytes, new AsyncCallback(ProcessDownloadedBytesFinished), pdbh);
00319 }
00324 private delegate void ProcessDownloadedBytesHandler(byte[] input_bytes);
00329 private void ProcessDownloadedBytesFinished(IAsyncResult result)
00330 {
00331 ProcessDownloadedBytesHandler pdbh = (ProcessDownloadedBytesHandler)result.AsyncState;
00332 pdbh.EndInvoke(result);
00333 busy = false;
00334 if (Completed != null)
00335 Completed(this);
00336 }
00342 private void ProcessDownloadedBytesAsync(byte[] input_bytes)
00343 {
00344 MemoryStream input = new MemoryStream(input_bytes);
00345 MemoryStream output = new MemoryStream();
00346 ASCIIEncoding ascii = new ASCIIEncoding();
00347 UTF8Encoding utf = new UTF8Encoding();
00348 UnicodeEncoding unicode = new UnicodeEncoding();
00349
00350 try
00351 {
00352 ICSharpCode.SharpZipLib.BZip2.BZip2.Decompress(input, output);
00353 }
00354 catch (Exception ex)
00355 {
00356 error_code = Connection.ErrorCodes.Exception;
00357 Console.WriteLine("Error uncompressing hublist: " + ex.Message);
00358 if (UnableToFetch != null)
00359 UnableToFetch(this);
00360 busy = false;
00361 return;
00362 }
00363 input.Flush();
00364 byte[] out_data = output.GetBuffer();
00365
00366
00367 string hubs_string = System.Text.Encoding.Default.GetString(out_data);
00368
00369 int end = hubs_string.IndexOf((char)0);
00370 if (end != -1) hubs_string = hubs_string.Remove(end);
00371
00372 for (int i = 0; i < 0x1f; i++)
00373 if (i != 0x09 && i != 0x0a && i != 0x0d) hubs_string = hubs_string.Replace((char)i, ' ');
00374
00375 hubs_string = hubs_string.Replace("&", "&");
00376 bool inside_quotes = false;
00377 for (int i = 0; i < hubs_string.Length; i++)
00378 {
00379 if (hubs_string[i] == '\"' && inside_quotes == false)
00380 {
00381 inside_quotes = true;
00382 }
00383 else if (hubs_string[i] == '\"' && inside_quotes == true)
00384 {
00385 inside_quotes = false;
00386 }
00387
00388 if (inside_quotes && hubs_string[i] == '<')
00389 {
00390 hubs_string = hubs_string.Remove(i, 1);
00391 hubs_string = hubs_string.Insert(i, "<");
00392 }
00393
00394 if (inside_quotes && hubs_string[i] == '>')
00395 {
00396 hubs_string = hubs_string.Remove(i, 1);
00397 hubs_string = hubs_string.Insert(i, ">");
00398 }
00399
00400 if (inside_quotes && hubs_string[i] == '')
00401 {
00402 hubs_string = hubs_string.Remove(i, 1);
00403 hubs_string = hubs_string.Insert(i, " ");
00404 }
00405
00406 }
00407
00408
00409
00410
00411 ReadXmlStringAsync(hubs_string);
00412
00413
00414
00415
00416 }
00423 private void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
00424 {
00425 percentage = e.ProgressPercentage;
00426 if (ProgressChanged != null)
00427 ProgressChanged(this);
00428
00429 }
00434 private delegate bool ReadXmlStringHandler(string xml);
00439 private bool ReadXmlStringAsync(string xml)
00440 {
00441 XmlDocument doc = new XmlDocument();
00442 bool try_again = false;
00443 try
00444 {
00445
00446 doc.LoadXml(xml);
00447
00448
00449 }
00450 catch (XmlException xe)
00451 {
00452
00453 string error_message = "Unexpected end of file has occurred. The following elements are not closed: ";
00454 if (xe.Message.StartsWith(error_message))
00455 {
00456 string tags = xe.Message.Substring(error_message.Length);
00457 int end = tags.IndexOf(".");
00458 if (end != -1)
00459 {
00460 tags = tags.Substring(0, end);
00461 int last = 0;
00462 int split = 0;
00463 while ((split = tags.IndexOf(",", split)) != -1)
00464 {
00465 string tag = tags.Substring(last, split);
00466 last = split + 1;
00467 split++;
00468
00469 tag = tag.Trim();
00470 xml = xml + "</" + tag + ">\r\n";
00471 }
00472 string last_tag = tags.Substring(last);
00473 last_tag = last_tag.Trim();
00474 xml = xml + "</" + last_tag + ">\r\n";
00475
00476 }
00477 try_again = true;
00478 }
00479 else
00480 {
00481 error_code = Connection.ErrorCodes.Exception;
00482 Console.WriteLine("xml exception:" + xe.Message);
00483 if (UnableToFetch != null)
00484 UnableToFetch(this);
00485 busy = false;
00486 return (false);
00487 }
00488
00489 }
00490
00491 if (try_again)
00492 {
00493 try
00494 {
00495
00496 doc.LoadXml(xml);
00497
00498
00499 }
00500 catch (XmlException xe)
00501 {
00502 Console.WriteLine("xml exception:" + xe.Message);
00503 return (false);
00504 }
00505
00506
00507 }
00508
00509
00510 try
00511 {
00512 XmlNodeList nodelist = doc.SelectNodes("/");
00513 foreach (XmlNode node in nodelist)
00514 {
00515 if (node.HasChildNodes)
00516 {
00517 foreach (XmlNode child in node.ChildNodes)
00518 {
00519 if (child.Name.Equals("Hublist")) ReadHubList(child);
00520 }
00521 }
00522
00523 }
00524
00525 }
00526 catch (XmlException xmle)
00527 {
00528 error_code = Connection.ErrorCodes.Exception;
00529 Console.WriteLine(xmle.Message);
00530 if (UnableToFetch != null)
00531 UnableToFetch(this);
00532 busy = false;
00533 return (false);
00534
00535 }
00536
00537 return (true);
00538 }
00545 public void ReadXmlString(string xml)
00546 {
00547 ReadXmlStringHandler rxsh = new ReadXmlStringHandler(ReadXmlStringAsync);
00548 IAsyncResult result = rxsh.BeginInvoke(xml, new AsyncCallback(ReadXmlStringFinished), rxsh);
00549 }
00554 private void ReadXmlStringFinished(IAsyncResult result)
00555 {
00556 ReadXmlStringHandler rxsh = (ReadXmlStringHandler)result.AsyncState;
00557 bool ret = rxsh.EndInvoke(result);
00558 busy = false;
00559 if (Completed != null)
00560 Completed(this);
00561 }
00568 private bool ReadHubList(XmlNode node)
00569 {
00570 foreach (XmlAttribute attr in node.Attributes)
00571 {
00572
00573 if (attr.Name.Equals("Name")) name = attr.Value;
00574 if (attr.Name.Equals("Address")) address = attr.Value;
00575 }
00576
00577 if (node.HasChildNodes)
00578 {
00579 foreach (XmlNode child in node.ChildNodes)
00580 {
00581 if (child.Name.Equals("Hubs")) ReadHubs(child);
00582 }
00583 }
00584
00585 return (true);
00586 }
00593 private bool ReadHubs(XmlNode node)
00594 {
00595
00596 if (node.HasChildNodes)
00597 {
00598 foreach (XmlNode child in node.ChildNodes)
00599 {
00600 if (child.Name.Equals("Hub")) ReadHub(child);
00601 if (child.Name.Equals("Columns")) ReadColumns(child);
00602 Thread.Sleep(1);
00603 }
00604 }
00605
00606 return (true);
00607 }
00613 private bool ReadColumns(XmlNode node)
00614 {
00615
00616 if (node.HasChildNodes)
00617 {
00618 foreach (XmlNode child in node.ChildNodes)
00619 {
00620 if (child.Name.Equals("Column")) ReadColumn(child);
00621 }
00622 }
00623
00624 return (true);
00625 }
00631 private bool ReadColumn(XmlNode node)
00632 {
00633
00634 Column column = new Column();
00635 foreach (XmlAttribute attr in node.Attributes)
00636 {
00637
00638 if (attr.Name.Equals("Name")) column.Name = attr.Value;
00639 if (attr.Name.Equals("Type")) column.Type = attr.Value;
00640 }
00641 columns.Add(column);
00642 return (true);
00643 }
00649 private bool ReadHub(XmlNode node)
00650 {
00651
00652 Hub hub = new Hub();
00653 foreach (XmlAttribute attr in node.Attributes)
00654 {
00655 try
00656 {
00657
00658 if (attr.Name.Equals("Name")) hub.Name = attr.Value;
00659 if (attr.Name.Equals("Address")) hub.Address = attr.Value;
00660 if (attr.Name.Equals("Description")) hub.Description = attr.Value;
00661 if (attr.Name.Equals("Country")) hub.Country = attr.Value;
00662 if (attr.Name.Equals("IP")) hub.IP = attr.Value;
00663 if (attr.Name.Equals("Users") && !string.IsNullOrEmpty(attr.Value)) hub.Users = long.Parse(attr.Value);
00664 if (attr.Name.Equals("Shared") && !string.IsNullOrEmpty(attr.Value)) hub.Shared = long.Parse(attr.Value);
00665 if (attr.Name.Equals("Minshare") && !string.IsNullOrEmpty(attr.Value)) hub.MinShare = long.Parse(attr.Value);
00666 if (attr.Name.Equals("Minslots") && !string.IsNullOrEmpty(attr.Value)) hub.MinSlots = int.Parse(attr.Value);
00667 if (attr.Name.Equals("Maxhubs") && !string.IsNullOrEmpty(attr.Value)) hub.MaxHubs = int.Parse(attr.Value);
00668 if (attr.Name.Equals("Maxusers") && !string.IsNullOrEmpty(attr.Value)) hub.MaxUsers = long.Parse(attr.Value);
00669 if (attr.Name.Equals("Port") && !string.IsNullOrEmpty(attr.Value)) hub.Port = int.Parse(attr.Value);
00670 }
00671 catch (Exception e)
00672 {
00673 Console.WriteLine("Exception reading Hub-Values: "+e.Message);
00674 return (false);
00675 }
00676 }
00677 bool unique = true;
00678 foreach (Hub search in hubs)
00679 {
00680 if (search.Address == hub.Address)
00681 {
00682
00683 unique = false;
00684 }
00685 }
00686 if(unique)
00687 hubs.Add(hub);
00688 return (true);
00689 }
00690
00691 #region Unit Testing
00695 [Test]
00696 public void TestHubListDownload()
00697 {
00698 Console.WriteLine("Test to download a hublist.");
00699 bool wait = true;
00700 HubList hublist = new HubList("http://www.hublist.co.uk/hublist.xml.bz2");
00701
00702 hublist.Completed += delegate(HubList hub_list)
00703 {
00704 Console.WriteLine("");
00705 Console.WriteLine("Fetch Completed (Hubs found : " + hub_list.Hubs.Count + ")");
00706 wait = false;
00707 };
00708 hublist.FetchHubs();
00709
00710 Console.WriteLine("Waiting for data");
00711 DateTime start = DateTime.Now;
00712 while (wait)
00713 {
00714 if (DateTime.Now - start > new TimeSpan(0, 0, 30))
00715 {
00716 Console.WriteLine("");
00717 Console.WriteLine("Operation took too long");
00718 wait = false;
00719 Assert.Fail("Operation took too long");
00720 }
00721 Console.Write(".");
00722 Thread.Sleep(250);
00723 }
00724 Console.WriteLine("Hublist Download Test successful.");
00725
00726 }
00731 [Test]
00732 public void TestHubListDownloadFailWrongUrl()
00733 {
00734 Console.WriteLine("Test to download a hublist (wrong url).");
00735 bool wait = true;
00736 HubList hublist = new HubList("http://ww.hublist.co.uk/hublist.xml.bz2");
00737
00738 hublist.Completed += delegate(HubList hub_list)
00739 {
00740 Console.WriteLine("");
00741 Console.WriteLine("Fetch Completed (Hubs found : " + hub_list.Hubs.Count + ")");
00742 Assert.Fail("Failed at failing ;-(");
00743 };
00744
00745 hublist.UnableToFetch += delegate(HubList hub_list_unable)
00746 {
00747 Console.WriteLine("");
00748 Console.WriteLine("Unable to fetch hublist: "+ hub_list_unable.Address);
00749 wait = false;
00750 };
00751 hublist.FetchHubs();
00752
00753 Console.WriteLine("Waiting for data");
00754 DateTime start = DateTime.Now;
00755 while (wait)
00756 {
00757 if (DateTime.Now - start > new TimeSpan(0, 0, 30))
00758 {
00759 Console.WriteLine("");
00760 Console.WriteLine("Operation took too long");
00761 wait = false;
00762 Assert.Fail("Operation took too long");
00763 }
00764 Console.Write(".");
00765 Thread.Sleep(250);
00766 }
00767 Console.WriteLine("Failed Hublist Download Test successful.");
00768
00769 }
00770 #endregion
00771 }
00772 }