Eigene Dateien/Visual Studio 2005/Projects/DCPlusPlus/DCPlusPlus/HubList.cs

Go to the documentation of this file.
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 // todo :
00014 // maybe change it to not clear hubs on a fetch ..so hublists can add up
00015 // maybe name,address,columns better be put in list< >
00016 // maybe not ;-)
00017 
00018 // add checks so we can use uncompressed lists too ;-)
00019 // add async readxml handler
00020 // maybe a fetching queue ... but why the heck.. an client app can handle that with multiple hublists
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); //our new error handler
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                 //hubs.Clear();
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                 //Console.WriteLine("Error:"+e.Error.Data.Values.ToString());
00294                 //if its a bz2 uncompress the data stream
00295                 //Stream input = new StreamReader(e.Result);
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             //string hubs_string = ascii.GetString(out_data);
00366 
00367             string hubs_string = System.Text.Encoding.Default.GetString(out_data);
00368             //string hubs_string = utf.GetString(out_data);
00369             int end = hubs_string.IndexOf((char)0);
00370             if (end != -1) hubs_string = hubs_string.Remove(end);
00371             //string hubs_string = unicode.GetString(out_data);
00372             for (int i = 0; i < 0x1f; i++)
00373                 if (i != 0x09 && i != 0x0a && i != 0x0d) hubs_string = hubs_string.Replace((char)i, ' ');//"&#x00"+i+";"
00374 
00375             hubs_string = hubs_string.Replace("&", "&amp;");
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, "&lt;");
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, "&gt;");
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             //hubs_string = hubs_string.Replace("&", "&amp;");
00408             //Console.WriteLine(hubs_string);
00409             //File.WriteAllText("hublist.uncompressed.xml", hubs_string);
00410             //output.Position = 0;
00411             ReadXmlStringAsync(hubs_string);
00412             /*busy = false;
00413             if (Completed != null)
00414                 Completed(this);*/
00415 
00416         }
00423         private void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
00424         {
00425             percentage = e.ProgressPercentage;// TODO scale down to something like 70% if download has finished
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                 //Console.WriteLine("Starting to parse xml data.");
00446                 doc.LoadXml(xml);
00447                 //Console.WriteLine("Finished parsing.");
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                             //int line = xe.LineNumber;
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                     //Console.WriteLine("Starting to parse xml data for a second time.");
00496                     doc.LoadXml(xml);
00497                     //Console.WriteLine("Finished parsing.");
00498 
00499                 }
00500                 catch (XmlException xe)
00501                 {
00502                     Console.WriteLine("xml exception:" + xe.Message);
00503                     return (false);
00504                 }
00505 
00506 
00507             }
00508 
00509             //TODO change this to a non xpath workarround version
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                     //Console.WriteLine("attr:" + attr.Name + " - " + attr.Value);
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             //Console.WriteLine("Reading Hubs Tree");
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);//simple way to decrease cpu lag of this large loop but at cost of time
00603                     }
00604                 }
00605 
00606             return (true);
00607        }
00613         private bool ReadColumns(XmlNode node)
00614         {
00615             //Console.WriteLine("Reading Columns Tree");
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             //Console.WriteLine("Reading Column information");
00634             Column column = new Column();
00635             foreach (XmlAttribute attr in node.Attributes)
00636             {
00637                 //Console.WriteLine("attr:" + attr.Name + " - " + attr.Value);
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             //Console.WriteLine("Reading Hub information");
00652             Hub hub = new Hub();
00653             foreach (XmlAttribute attr in node.Attributes)
00654             {
00655                 try
00656                 {
00657                     //Console.WriteLine("attr:" + attr.Name + " - " + attr.Value);
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                     //Console.WriteLine("duplicate hub entry found: "+hub.Name);
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             //HubList hublist = new HubList("http://www.hublist.org/PublicHubList.xml.bz2");
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             //hublist.FetchHubs("http://www.hublist.org/PublicHubList.xml.bz2"); 
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             //HubList hublist = new HubList("http://www.hublist.org/PublicHubList.xml.bz2");
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             //hublist.FetchHubs("http://www.hublist.org/PublicHubList.xml.bz2"); 
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 }

Generated on Wed Mar 7 19:09:20 2007 for DCPlusPlus by  doxygen 1.5.1-p1