Skip to content

Commit 98bf169

Browse files
committed
Feature: Visual Traceroute (PoC)
1 parent 9d85c86 commit 98bf169

18 files changed

Lines changed: 1863 additions & 19 deletions

Scripts/Create-WorldMapFromWeb.ps1

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Filepath in the resources
2+
[string]$OutFilePath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath "Source\NETworkManager\Resources\Maps\world-map.json"
3+
[string]$CitiesOutFilePath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath "Source\NETworkManager\Resources\Maps\world-cities.json"
4+
5+
# Resolution of the Natural Earth admin-0 countries / populated places dataset (110m, 50m or 10m - higher detail = larger file)
6+
[string]$Resolution = "50m"
7+
8+
# A city is included if it's a national capital, or its population is at least this high
9+
[int]$CityMinPopulation = 500000
10+
11+
# Download countries as plain GeoJSON (pre-converted from Natural Earth shapefiles, no TopoJSON decoding required)
12+
$GeoJson = (Invoke-WebRequest -Uri "https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/$Resolution/cultural/ne_${Resolution}_admin_0_countries.json").Content | ConvertFrom-Json
13+
14+
# Rounds [lon, lat] pairs to 2 decimal places (~1.1 km), which is enough detail for an abstract, non-navigational map
15+
function Get-RoundedRing {
16+
param($Ring)
17+
18+
$Points = [System.Collections.Generic.List[object]]::new()
19+
20+
foreach ($Point in $Ring) {
21+
$Points.Add(@([Math]::Round([double]$Point[0], 2), [Math]::Round([double]$Point[1], 2)))
22+
}
23+
24+
# Unary comma prevents PowerShell from unrolling the list when there is only a single ring/point
25+
, $Points
26+
}
27+
28+
# Keeps only the outer ring of every polygon part (holes like inland lakes are not relevant for an abstract map)
29+
function Get-OuterRings {
30+
param($Geometry)
31+
32+
$Rings = [System.Collections.Generic.List[object]]::new()
33+
34+
switch ($Geometry.type) {
35+
"Polygon" {
36+
$Rings.Add((Get-RoundedRing -Ring $Geometry.coordinates[0]))
37+
}
38+
"MultiPolygon" {
39+
foreach ($Part in $Geometry.coordinates) {
40+
$Rings.Add((Get-RoundedRing -Ring $Part[0]))
41+
}
42+
}
43+
}
44+
45+
, $Rings
46+
}
47+
48+
$Countries = [System.Collections.Generic.List[object]]::new()
49+
50+
foreach ($Feature in $GeoJson.features) {
51+
$Countries.Add([PSCustomObject]@{
52+
n = $Feature.properties.ADMIN
53+
r = Get-OuterRings -Geometry $Feature.geometry
54+
})
55+
}
56+
57+
ConvertTo-Json -InputObject $Countries -Depth 10 -Compress | Set-Content -Path $OutFilePath -Encoding utf8NoBOM
58+
59+
# Download populated places (cities) as plain GeoJSON
60+
$PlacesGeoJson = (Invoke-WebRequest -Uri "https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/$Resolution/cultural/ne_${Resolution}_populated_places_simple.json").Content | ConvertFrom-Json
61+
62+
$Cities = [System.Collections.Generic.List[object]]::new()
63+
64+
foreach ($Feature in $PlacesGeoJson.features) {
65+
$Properties = $Feature.properties
66+
67+
# Keep national capitals regardless of population, plus every other city above the threshold
68+
if ($Properties.adm0cap -ne 1 -and $Properties.pop_max -lt $CityMinPopulation) {
69+
continue
70+
}
71+
72+
$Cities.Add([PSCustomObject]@{
73+
n = $Properties.name
74+
lat = [Math]::Round([double]$Properties.latitude, 2)
75+
lon = [Math]::Round([double]$Properties.longitude, 2)
76+
})
77+
}
78+
79+
ConvertTo-Json -InputObject $Cities -Depth 5 -Compress | Set-Content -Path $CitiesOutFilePath -Encoding utf8NoBOM

Source/NETworkManager.Documentation/ResourceManager.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,22 @@ public static class ResourceManager
1111
/// <summary>
1212
/// Static list with all resources that are used.
1313
/// </summary>
14-
public static List<ResourceInfo> List => new()
15-
{
16-
new ResourceInfo("Organizationally unique identifier", "https://standards-oui.ieee.org/oui/oui.txt",
14+
public static List<ResourceInfo> List =>
15+
[
16+
new("Organizationally unique identifier", "https://standards-oui.ieee.org/oui/oui.txt",
1717
Strings.Resource_OUI_Description),
18-
new ResourceInfo("Service names and port numbers",
18+
19+
new("Service names and port numbers",
1920
"https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml",
2021
Strings.Resource_ServiceNamePortNumber_Description),
21-
new ResourceInfo("flag-icon-css", "https://github.com/lipis/flag-icon-css",
22+
23+
new("flag-icon-css", "https://github.com/lipis/flag-icon-css",
2224
Strings.Resource_Flag_Description),
23-
new ResourceInfo("List of Top-Level-Domains", "https://data.iana.org/TLD/tlds-alpha-by-domain.txt",
24-
Strings.Resource_ListTLD_Description)
25-
};
25+
26+
new("List of Top-Level-Domains", "https://data.iana.org/TLD/tlds-alpha-by-domain.txt",
27+
Strings.Resource_ListTLD_Description),
28+
29+
new("natural-earth-geojson", "https://github.com/martynafford/natural-earth-geojson",
30+
Strings.Resource_NaturalEarth_Description)
31+
];
2632
}

Source/NETworkManager.Localization/Resources/Strings.Designer.cs

Lines changed: 31 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Source/NETworkManager.Localization/Resources/Strings.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,9 @@
573573
<data name="IPv6DefaultGateway" xml:space="preserve">
574574
<value>IPv6-Default-Gateway</value>
575575
</data>
576+
<data name="Map" xml:space="preserve">
577+
<value>Map</value>
578+
</data>
576579
<data name="Maximum" xml:space="preserve">
577580
<value>Maximum</value>
578581
</data>
@@ -2985,6 +2988,9 @@ Error message:
29852988
<data name="Resource_ListTLD_Description" xml:space="preserve">
29862989
<value>List of Top-Level-Domains from iana.org, which is used to query whois servers of the TLD from whois.iana.org via port 43</value>
29872990
</data>
2991+
<data name="Resource_NaturalEarth_Description" xml:space="preserve">
2992+
<value>GeoJSON conversion of Natural Earth vector map data (CC0-1.0).</value>
2993+
</data>
29882994
<data name="Resource_OUI_Description" xml:space="preserve">
29892995
<value>OUI data from ieee.org.</value>
29902996
</data>
@@ -3823,6 +3829,9 @@ Try again in a few seconds.</value>
38233829
<data name="ExpandHostView" xml:space="preserve">
38243830
<value>Expand host view</value>
38253831
</data>
3832+
<data name="ExpandMapView" xml:space="preserve">
3833+
<value>Expand map view</value>
3834+
</data>
38263835
<data name="CannotSetHostWhileRunningMessage" xml:space="preserve">
38273836
<value>Host cannot be set while other hosts are being added. Please wait until the process is complete and try again.</value>
38283837
</data>

Source/NETworkManager.Settings/GlobalStaticConfiguration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ public static class GlobalStaticConfiguration
166166
public static int Traceroute_Buffer => 32;
167167
public static bool Traceroute_ResolveHostname => true;
168168
public static bool Traceroute_CheckIPApiIPGeolocation => false;
169+
public static bool Traceroute_ExpandMapView => true;
169170
public static ExportFileType Traceroute_ExportFileType => ExportFileType.Csv;
170171

171172
// Application: DNS Lookup

Source/NETworkManager.Settings/SettingsInfo.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,6 +1749,19 @@ public bool Traceroute_CheckIPApiIPGeolocation
17491749
}
17501750
} = GlobalStaticConfiguration.Traceroute_CheckIPApiIPGeolocation;
17511751

1752+
public bool Traceroute_ExpandMapView
1753+
{
1754+
get;
1755+
set
1756+
{
1757+
if (value == field)
1758+
return;
1759+
1760+
field = value;
1761+
OnPropertyChanged();
1762+
}
1763+
} = GlobalStaticConfiguration.Traceroute_ExpandMapView;
1764+
17521765
public bool Traceroute_ExpandProfileView
17531766
{
17541767
get;

Source/NETworkManager/NETworkManager.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@
102102
<Resource Include="NETworkManager.ico" />
103103
<Resource Include="SplashScreen.png" />
104104
</ItemGroup>
105+
<ItemGroup>
106+
<EmbeddedResource Include="Resources\Maps\world-map.json" />
107+
<EmbeddedResource Include="Resources\Maps\world-cities.json" />
108+
</ItemGroup>
105109
<ItemGroup>
106110
<Compile Update="Properties\Resources.Designer.cs">
107111
<DesignTime>True</DesignTime>

Source/NETworkManager/Resources/Maps/world-cities.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

Source/NETworkManager/Resources/Maps/world-map.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

Source/NETworkManager/Resources/Styles/GridSplitterStyles.xaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,18 @@
1212
<Setter Property="VerticalAlignment" Value="Stretch" />
1313
</Style>
1414

15+
<!-- Same look as ProfileGridSplitter, but for resizing rows instead of columns. -->
16+
<Style x:Key="HorizontalGridSplitter" TargetType="{x:Type GridSplitter}">
17+
<Setter Property="Height" Value="7" />
18+
<Setter Property="Margin" Value="-3,-3" />
19+
<Setter Property="BorderThickness" Value="3" />
20+
<Setter Property="BorderBrush" Value="Transparent" />
21+
<Setter Property="Panel.ZIndex" Value="1" />
22+
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Gray8}" />
23+
<Setter Property="ShowsPreview" Value="True" />
24+
<Setter Property="HorizontalAlignment" Value="Stretch" />
25+
<Setter Property="VerticalAlignment" Value="Center" />
26+
<Setter Property="ResizeDirection" Value="Rows" />
27+
</Style>
28+
1529
</ResourceDictionary>

0 commit comments

Comments
 (0)