Skip to content

Commit

Permalink
Updated the Connections page (esp. the bandwidth graph - which still …
Browse files Browse the repository at this point in the history
…needs to be tweaked but is "good enough" for an alpha release).
  • Loading branch information
wokhan committed Oct 29, 2020
1 parent f6a1f3a commit 3842ec1
Show file tree
Hide file tree
Showing 16 changed files with 214 additions and 145 deletions.
7 changes: 1 addition & 6 deletions Common.Tests/Common.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.8" />
<PackageReference Include="MaxMind.GeoIP2">
<Version>3.1.0</Version>
<Version>3.2.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
<Version>2.9.8</Version>
Expand All @@ -29,11 +29,6 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="Microsoft.NetFramework.Analyzers">
<Version>2.9.8</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit.Console" Version="3.11.1" />
<PackageReference Include="NUnit.Extension.VSProjectLoader" Version="3.8.0" />
Expand Down
2 changes: 1 addition & 1 deletion Common/Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.8" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
1 change: 0 additions & 1 deletion Console/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Wokhan.WindowsFirewallNotifier.Common;component/UI/Theme.xaml" />
<ResourceDictionary Source="Resources/Images.xaml" />
<ResourceDictionary Source="pack://application:,,,/LiveCharts.Wpf;component/Themes/Colors/material.xaml" />
</ResourceDictionary.MergedDictionaries>
<BindingConverters:BooleanNegateConverter x:Key="booleanNegator" />
<BindingConverters:UnitFormatConverter x:Key="unitFormatter" />
Expand Down
9 changes: 4 additions & 5 deletions Console/Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,15 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="LiveCharts.Geared" Version="1.2.9" />
<PackageReference Include="LiveCharts.Wpf" Version="0.9.7" />
<PackageReference Include="log4net" Version="2.0.8.0" />
<PackageReference Include="log4net" Version="2.0.11" />
<PackageReference Include="MaxMind.Db" Version="2.6.1" />
<PackageReference Include="MaxMind.GeoIP2" Version="3.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
<PackageReference Include="MaxMind.GeoIP2" Version="3.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Maps.MapControl.WPF" Version="1.0.0.3" />
<PackageReference Include="OxyPlot.Wpf" Version="2.0.0" />
<PackageReference Include="Wokhan.Core" Version="0.9.2-alpha" />
<PackageReference Include="Wokhan.UI" Version="0.9.2-alpha" />
</ItemGroup>
Expand Down
29 changes: 22 additions & 7 deletions Console/Helpers/ViewModels/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ private bool TryEnableStats()
}
catch
{
InboundBandwidth = 0;
OutboundBandwidth = 0;
IsAccessDenied = true;
}

Expand Down Expand Up @@ -168,6 +170,11 @@ internal void UpdateValues(IConnectionOwnerInfo b)
}
EstimateBandwidth();
}
else
{
InboundBandwidth = 0;
OutboundBandwidth = 0;
}

LastSeen = DateTime.Now;
}
Expand Down Expand Up @@ -280,19 +287,27 @@ public Brush Brush
private void EstimateBandwidth()
{
if (!statsEnabled)
{
return;
}

if (rawrow != null && !IsAccessDenied)
try
{
var bandwidth = (rawrow is TCPHelper.MIB_TCPROW ? TCPHelper.GetTCPBandwidth((TCPHelper.MIB_TCPROW)rawrow) : TCP6Helper.GetTCPBandwidth((TCP6Helper.MIB_TCP6ROW)rawrow));
InboundBandwidth = bandwidth.InboundBandwidth;
OutboundBandwidth = bandwidth.OutboundBandwidth;
if (rawrow != null && !IsAccessDenied)
{
var bandwidth = (rawrow is TCPHelper.MIB_TCPROW ? TCPHelper.GetTCPBandwidth((TCPHelper.MIB_TCPROW)rawrow) : TCP6Helper.GetTCPBandwidth((TCP6Helper.MIB_TCP6ROW)rawrow));
InboundBandwidth = bandwidth.InboundBandwidth;
OutboundBandwidth = bandwidth.OutboundBandwidth;
return;
}
}
else
catch
{
InboundBandwidth = 0;
OutboundBandwidth = 0;
//TODO: Add exception log
}

InboundBandwidth = 0;
OutboundBandwidth = 0;
}

}
Expand Down
23 changes: 19 additions & 4 deletions Console/Helpers/ViewModels/GeoConnection2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.IO;
using System;
using System.Net;
using System.Windows.Media;
using System.Threading.Tasks;
using MaxMind.GeoIP2;
using MaxMind.GeoIP2.Responses;
Expand All @@ -25,19 +24,35 @@ public class GeoConnection2 : INotifyPropertyChanged

public string Owner => Connection.Owner;

private static IPAddress _currentIP;
//TODO: CurrentIP shouldn't be handled in GeoConnection2 class (but in IPHelper or something alike)
public static IPAddress CurrentIP
{
get
{
if (_currentIP is null)
{
{
_currentIP = IPHelper.GetPublicIpAddress();
}
}

return _currentIP;
}
}

private static Location _currentCoordinates;
public static Location CurrentCoordinates
{
get
{
if (_currentCoordinates is null)
{
IPAddress address = IPHelper.GetPublicIpAddress();
if (address == IPAddress.None)
if (CurrentIP == IPAddress.None)
{
throw new Exception(Resources.GeoConnection2_CannotRetrieveConnectionLocationForPublicIp);
}
_currentCoordinates = IPToLocation(address);
_currentCoordinates = IPToLocation(CurrentIP);
}
return _currentCoordinates;
}
Expand Down
11 changes: 3 additions & 8 deletions Console/Helpers/ViewModels/GroupedView.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.Geared;
using LiveCharts.Wpf;

namespace Wokhan.WindowsFirewallNotifier.Console.Helpers.ViewModels
namespace Wokhan.WindowsFirewallNotifier.Console.Helpers.ViewModels
{
public class GroupedView : GroupedViewBase
{
Expand All @@ -22,8 +17,8 @@ public double LastOut
set { _lastout = value; NotifyPropertyChanged(nameof(LastOut)); }
}

public GearedValues<DateTimePoint> SeriesIn { get; } = new GearedValues<DateTimePoint>();
public GearedValues<DateTimePoint> SeriesOut { get; } = new GearedValues<DateTimePoint>();
//public GearedValues<DateTimePoint> SeriesIn { get; } = new GearedValues<DateTimePoint>();
//public GearedValues<DateTimePoint> SeriesOut { get; } = new GearedValues<DateTimePoint>();

}
}
16 changes: 4 additions & 12 deletions Console/UI/Controls/BandwidthGraph.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,9 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
xmlns:local="clr-namespace:Wokhan.WindowsFirewallNotifier.Console.UI.Controls"
xmlns:oxy="http://oxyplot.org/wpf"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" x:Name="me"
d:DesignHeight="450" d:DesignWidth="800">
<lvc:CartesianChart DataContext="{Binding ElementName=me}" x:Name="chart" Pan="X" VirtualizingPanel.IsVirtualizing="True" Series="{Binding SeriesCollection}" LegendLocation="None" MinHeight="150">
<lvc:CartesianChart.AxisX>
<lvc:Axis x:Name="XAxis" MinValue="{Binding Start}" MaxValue="{Binding End}" Title="Time" Separator="{x:Static lvc:DefaultAxes.CleanSeparator}" LabelsRotation="110" LabelFormatter="{Binding XFormatter}" />
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis x:Name="YAxis" Title="Bandwidth" MinValue="0" BarUnit="10" LabelFormatter="{Binding YFormatter}" />
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
d:DesignHeight="450" d:DesignWidth="800" ClipToBounds="True">
<oxy:PlotView x:Name="chart" Model="{Binding Model}" DataContext="{Binding ElementName=me}" />
</UserControl>
85 changes: 55 additions & 30 deletions Console/UI/Controls/BandwidthGraph.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.Geared;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

using Wokhan.Core.Core;
using Wokhan.WindowsFirewallNotifier.Console.Helpers.ViewModels;
Expand All @@ -19,51 +18,77 @@ namespace Wokhan.WindowsFirewallNotifier.Console.UI.Controls
/// <summary>
/// Logique d'interaction pour BandwidthGraph.xaml
/// </summary>
public partial class BandwidthGraph : UserControl, INotifyPropertyChanged
public partial class BandwidthGraph : UserControl
{

public ObservableCollection<Connection> Connections { get => (ObservableCollection<Connection>)GetValue(ConnectionsProperty); set => SetValue(ConnectionsProperty, value); }
public static readonly DependencyProperty ConnectionsProperty = DependencyProperty.Register(nameof(Connections), typeof(ObservableCollection<Connection>), typeof(BandwidthGraph));

public PlotModel Model { get; private set; }

private const int MAX_DURATION_SEC = 10;

private DateTime datetime = DateTime.Now;
private double Start => DateTimeAxis.ToDouble(datetime.AddSeconds(-MAX_DURATION_SEC));
private double End => DateTimeAxis.ToDouble(datetime.AddSeconds(2));

public event PropertyChangedEventHandler PropertyChanged;

public SeriesCollection SeriesCollection { get; } = new SeriesCollection();
public Func<double, string> YFormatter { get; set; } = (y) => UnitFormatter.FormatBytes(y, "ps");
public Func<double, string> XFormatter { get; set; } = (x) => new DateTime((long)x).ToString(DateTimeFormatInfo.CurrentInfo.LongTimePattern);
public long Start => DateTime.Now.AddSeconds(-10).Ticks;
public long End => DateTime.Now.Ticks;
private int Interval = 1;

public BandwidthGraph()
{
Model = new PlotModel()
{
Axes = {
new DateTimeAxis() { Position = AxisPosition.Bottom, StringFormat = "HH:mm:ss", Minimum = Start, Maximum = End },
new LinearAxis() { Position = AxisPosition.Left, Minimum = 0, LabelFormatter = (y) => UnitFormatter.FormatBytes(y, "ps") }
},
IsLegendVisible = false
};

InitializeComponent();
}

public void UpdateGraph()
{
var datetime = DateTime.Now;
datetime = DateTime.Now;

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Start)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(End)));
Model.DefaultXAxis.Minimum = Start;
Model.DefaultXAxis.Maximum = End;

var localConnections = Dispatcher.Invoke(() => Connections.GroupBy(connection => connection.GroupKey).ToList());
//Dispatcher.Invoke(() =>
foreach (var connectionGroup in localConnections)
{
foreach (var connectionGroup in localConnections)
var seriesInTitle = $"{connectionGroup.Key}#In";
var seriesOutTitle = $"{connectionGroup.Key}#Out";
var seriesIn = (ObservableCollection<DataPoint>)((LineSeries)Model.Series.FirstOrDefault(s => s.Title == seriesInTitle))?.ItemsSource;
var seriesOut = (ObservableCollection<DataPoint>)((LineSeries)Model.Series.FirstOrDefault(s => s.Title == seriesOutTitle))?.ItemsSource;

if (seriesIn is null)
{
var seriesInTitle = $"{connectionGroup.Key}#In";
var seriesOutTitle = $"{connectionGroup.Key}#Out";
var seriesIn = Dispatcher.Invoke(() => SeriesCollection.FirstOrDefault(s => s.Title == seriesInTitle));
var seriesOut = Dispatcher.Invoke(() => SeriesCollection.FirstOrDefault(s => s.Title == seriesOutTitle));
var colorbrush = Dispatcher.Invoke(() => (connectionGroup.First().Brush as SolidColorBrush).Color);
var color = OxyColor.FromArgb(colorbrush.A, colorbrush.R, colorbrush.G, colorbrush.B);
Model.Series.Add(new LineSeries() { Title = seriesInTitle, Color = color, ItemsSource = seriesIn = new ObservableCollection<DataPoint>(), InterpolationAlgorithm = InterpolationAlgorithms.CatmullRomSpline });
Model.Series.Add(new LineSeries() { Title = seriesOutTitle, Color = color, ItemsSource = seriesOut = new ObservableCollection<DataPoint>(), InterpolationAlgorithm = InterpolationAlgorithms.CatmullRomSpline });
}

if (seriesIn is null)
{
SeriesCollection.Add(seriesIn = Dispatcher.Invoke(() => new GLineSeries() { Title = seriesInTitle, Values = new GearedValues<DateTimePoint>() }));
SeriesCollection.Add(seriesOut = Dispatcher.Invoke(() => new GLineSeries() { Title = seriesOutTitle, Values = new GearedValues<DateTimePoint>() }));
}
var lastIn = connectionGroup.Sum(connection => connection.InboundBandwidth);
double? prevIn = null;
if (seriesIn.Count == 0 || (prevIn = seriesIn.Last().Y) != lastIn)
{
if (prevIn.HasValue) seriesIn.Add(DateTimeAxis.CreateDataPoint(datetime.AddSeconds(-Interval), prevIn.Value));
seriesIn.Add(DateTimeAxis.CreateDataPoint(datetime, connectionGroup.Sum(connection => connection.InboundBandwidth)));
}

seriesIn.Values.Add(new DateTimePoint(datetime, connectionGroup.Sum(connection => connection.InboundBandwidth)));
seriesOut.Values.Add(new DateTimePoint(datetime, connectionGroup.Sum(connection => connection.OutboundBandwidth)));
double? prevOut = null;
var lastOut = connectionGroup.Sum(connection => connection.InboundBandwidth);
if (seriesOut.Count == 0 || (prevOut = seriesIn.Last().Y) != lastOut)
{
if (prevOut.HasValue) seriesIn.Add(DateTimeAxis.CreateDataPoint(datetime.AddSeconds(-Interval), prevOut.Value));
seriesOut.Add(DateTimeAxis.CreateDataPoint(datetime, connectionGroup.Sum(connection => connection.OutboundBandwidth)));
}
}//);
}

Model.InvalidatePlot(true);
}
}
}
18 changes: 16 additions & 2 deletions Console/UI/Controls/Map.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,33 @@
</ItemsControl.ItemTemplate>
</maps:MapItemsControl>
<maps:MapLayer>
<maps:Pushpin maps:MapLayer.Position="{Binding CurrentCoordinates}" />
<maps:Pushpin maps:MapLayer.Position="{Binding CurrentCoordinates,Mode=OneWay}">
<maps:Pushpin.ToolTip>
<StackPanel>
<TextBlock><Run FontWeight="Bold" Text="IP: " /><Run Text="{Binding CurrentIP,Mode=OneWay}" /></TextBlock>
<TextBlock><Run FontWeight="Bold" Text="Coordinates: " /><Run Text="{Binding CurrentCoordinates,Mode=OneWay}" /></TextBlock>
</StackPanel>
</maps:Pushpin.ToolTip>
</maps:Pushpin>
</maps:MapLayer>
<maps:MapItemsControl ItemsSource="{Binding ConnectionsRoutes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Fill="{Binding Connection.Brush}" maps:MapLayer.Position="{Binding Coordinates}">
<Ellipse.ToolTip>
<StackPanel>
<TextBlock><Run FontWeight="Bold" Text="IP: " /><Run Text="{Binding Connection.RemoteAddress,Mode=OneTime}" /></TextBlock>
<TextBlock><Run FontWeight="Bold" Text="Hostname: " /><Run Text="{Binding Connection.RemoteHostName,Mode=OneWay}" /></TextBlock>
<TextBlock><Run FontWeight="Bold" Text="Coordinates: " /><Run Text="{Binding Coordinates,Mode=OneTime}" /></TextBlock>
</StackPanel>
</Ellipse.ToolTip>
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Width" Value="10" />
<Setter Property="Height" Value="10" />
<Setter Property="maps:MapLayer.PositionOffset" Value="-5,-5" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<DataTrigger Binding="{Binding Connection.IsSelected}" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter Property="maps:MapLayer.PositionOffset" Value="-10,-10" />
<Setter Property="Width" Value="20" />
Expand Down
13 changes: 11 additions & 2 deletions Console/UI/Controls/Map.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.Maps.MapControl.WPF;

using System.Collections.Generic;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
Expand Down Expand Up @@ -90,7 +90,7 @@ public void UpdateMap()
{
Dispatcher.Invoke(() =>
{
foreach (var c in Connections.Where(co => (co.Protocol == "UDP" || co.State == "ESTABLISHED") && co.RemoteAddress != "127.0.0.1" && co.Owner != null))
foreach (var c in Connections.Where(co => (co.Protocol == "UDP" || co.State == "ESTABLISHED") && IsValid(co.RemoteAddress) && co.Owner != null))
{
AddOrUpdateConnection(c);
}
Expand All @@ -100,6 +100,15 @@ public void UpdateMap()
}
}

//TODO: Temporary check for addresses validity (for mapping purpose only). Doesn't look like the right way to do this.
private bool IsValid(string remoteAddress)
{
return (!String.IsNullOrEmpty(remoteAddress)
&& remoteAddress != "127.0.0.1"
&& remoteAddress != "0.0.0.0"
&& remoteAddress != "::0");
}

private void AddOrUpdateConnection(Connection b)
{
GeoConnection2 existingRoute = ConnectionsRoutes.FirstOrDefault(l => l.Connection.RemoteAddress.Equals(b.RemoteAddress));
Expand Down
Loading

0 comments on commit 3842ec1

Please sign in to comment.