wasStitchNET – Blame information for rev 13

Subversion Repositories:
Rev:
Rev Author Line No. Line
13 office 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 //
3 // Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
4 // rights of fair usage, the disclaimer and warranty conditions. //
5 ///////////////////////////////////////////////////////////////////////////
6  
7 using System;
8 using System.Collections.Generic;
9 using System.IO;
10 using System.Linq;
11 using System.Net;
12 using MaxMind.GeoIP2.Responses;
13 using wasDAVClient;
14 using wasSharp.Geo;
15 using wasStitchNET.GeoIP;
16 using wasStitchNET.Structures;
17  
18 namespace wasStitchNET.Repository
19 {
20 public static class Mirrors
21 {
22 /// <summary>
23 /// Returns a list of valid Stitch mirrors.
24 /// </summary>
25 /// <param name="localCity">the local city from where the method is invoked</param>
26 /// <param name="mirror">the mirror to get the distance to</param>
27 /// <param name="client">the was DAV client to use</param>
28 /// <param name="server">the Stitch server to query</param>
29 /// <returns>a list of discovered Stitch mirrors</returns>
30 public static IEnumerable<StitchMirror> InitializeMirrors(CityResponse localCity, Client client, string server)
31 {
32 Func<string, StitchMirror> computeMirrorDistance = o =>
33 {
34 var mirrorDistance = GetMirrorDistance(localCity, o);
35 if (mirrorDistance.Equals(default(KeyValuePair<string, Distance>)))
36 return default(StitchMirror);
37 return new StitchMirror(mirrorDistance.Key, mirrorDistance.Value);
38 };
39  
40 var mirrors = new List<string> {server};
41 yield return computeMirrorDistance(server);
42  
43 foreach (var stitchMirror in mirrors.AsParallel().SelectMany(
44 mirror => FetchStitchMirrors(client, mirror)
45 .AsParallel()
46 .Where(o => !string.IsNullOrEmpty(o) && !mirrors.Contains(o))
47 .Select(computeMirrorDistance)))
48 {
49 if (stitchMirror.Equals(default(StitchMirror)))
50 continue;
51 mirrors.Add(stitchMirror.Address);
52 yield return stitchMirror;
53 }
54 }
55  
56 /// <summary>
57 /// Retrieves a list of mirrors from a Stitch repository.
58 /// </summary>
59 /// <param name="client">the was DAV client to use</param>
60 /// <param name="server">the Stitch server to retrieve the mirrors from</param>
61 /// <returns>a list of mirrors</returns>
62 public static IEnumerable<string> FetchStitchMirrors(Client client, string server)
63 {
64 // Set the server.
65 client.Server = server;
66  
67 // Set the mirror path
68 var mirrorsPath = @"/" +
69 string.Join(@"/", STITCH_CONSTANTS.UPDATE_PATH, STITCH_CONSTANTS.PROGRESSIVE_PATH,
70 STITCH_CONSTANTS.UPDATE_MIRRORS_FILE);
71  
72 using (var stream = client.Download(mirrorsPath).Result)
73 {
74 if (stream == null)
75 yield break;
76  
77 using (var streamReader = new StreamReader(stream))
78 {
79 string mirror;
80 do
81 {
82 mirror = streamReader.ReadLine();
83  
84 if (string.IsNullOrEmpty(mirror))
85 continue;
86  
87 yield return mirror;
88 } while (!string.IsNullOrEmpty(mirror));
89 }
90 }
91 }
92  
93 /// <summary>
94 /// Gets the distance to a mirror.
95 /// </summary>
96 /// <param name="localCity">the local city from where the method is invoked</param>
97 /// <param name="mirror">the mirror to get the distance to</param>
98 /// <returns>a key-value pair of mirror by distance</returns>
99 public static KeyValuePair<string, Distance> GetMirrorDistance(CityResponse localCity, string mirror)
100 {
101 // Check that the mirror has a proper URI.
102 Uri mirrorUri;
103 if (!Uri.TryCreate(mirror, UriKind.Absolute, out mirrorUri))
104 return default(KeyValuePair<string, Distance>);
105  
106 // If we do not know the local city, then just return the mirror.
107 if (localCity == null)
108 return new KeyValuePair<string, Distance>(mirror, null);
109  
110 // Resolve the mirror hostname to an IP address.
111 IPAddress address;
112 try
113 {
114 address = Dns.GetHostAddresses(mirrorUri.Host).FirstOrDefault();
115 }
116 catch (Exception)
117 {
118 return
119 new KeyValuePair<string, Distance>(mirror, null);
120 }
121  
122 // Resolve the IP address to a city response.
123 var remoteCity = address.GeoIPGetCity();
124 if (remoteCity == null)
125 return new KeyValuePair<string, Distance>(mirror, null);
126  
127 // Compute the distance to the mirror.
128 switch (remoteCity.Location.HasCoordinates)
129 {
130 case true:
131 var local = new GeographicCoordinate(localCity.Location.Latitude.Value,
132 localCity.Location.Longitude.Value);
133 var remote = new GeographicCoordinate(remoteCity.Location.Latitude.Value,
134 remoteCity.Location.Longitude.Value);
135 return
136 new KeyValuePair<string, Distance>(mirror, local.HaversineDistanceTo(remote));
137 default:
138 return
139 new KeyValuePair<string, Distance>(mirror, null);
140 }
141 }
142 }
143 }