LumaTunnel
【WinUI】LumaTunnel 是一个面向个人多设备的 Windows 代理系统。客户端在本机提供 HTTP/HTTPS CONNECT 与 SOCKS5 TCP 代理,并通过一个受信任 TLS 证书保护的 WSS 会话,将多个 TCP 流复用到自建 Windows Server 节点。
关注
0
Fork
0
Star
0
using LumaTunnel.Client.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Windows.Foundation;
namespace LumaTunnel.Client.Views;
public sealed partial class DashboardPage : Page
{
private readonly Queue<double> _upload = new();
private readonly Queue<double> _download = new();
private DispatcherTimer? _timer;
public DashboardViewModel ViewModel { get; } = new();
public DashboardPage()
{
InitializeComponent();
ViewModel.PropertyChanged += (_, args) =>
{
if (args.PropertyName == nameof(ViewModel.ErrorText))
{
ErrorBar.Message = ViewModel.ErrorText ?? string.Empty;
ErrorBar.IsOpen = ViewModel.ErrorText is not null;
}
};
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
HttpEndpointText.Text = $"127.0.0.1:{AppServices.Profile.HttpPort}";
SocksEndpointText.Text = $"127.0.0.1:{AppServices.Profile.SocksPort}";
_timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
_timer.Tick += OnTick;
_timer.Start();
OnTick(null, null!);
}
private void OnUnloaded(object sender, RoutedEventArgs e) => _timer?.Stop();
private void OnTick(object? sender, object e)
{
var connections = AppServices.ProxyEngine.Connections;
AppServices.TrafficMeter.Sample();
var uploadRate = AppServices.TrafficMeter.Current.UploadBytesPerSecond;
var downloadRate = AppServices.TrafficMeter.Current.DownloadBytesPerSecond;
Push(_upload, uploadRate);
Push(_download, downloadRate);
ViewModel.Refresh(uploadRate, downloadRate);
ConnectionCountText.Text = connections.Count.ToString(System.Globalization.CultureInfo.InvariantCulture);
DrawLines();
}
private static void Push(Queue<double> values, double value)
{
values.Enqueue(value);
while (values.Count > 60) values.Dequeue();
}
private void DrawLines()
{
var max = Math.Max(1, _upload.Concat(_download).DefaultIfEmpty().Max());
var width = Math.Max(100, TrafficCanvas.ActualWidth);
UploadLine.Points = Points(_upload, max, width);
DownloadLine.Points = Points(_download, max, width);
}
private static PointCollection Points(IEnumerable<double> values, double max, double width)
{
var data = values.ToArray();
var points = new PointCollection();
for (var index = 0; index < data.Length; index++)
points.Add(new Point(index * width / 59d, 145 - (data[index] / max * 135)));
return points;
}
}
using LumaTunnel.Client.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Windows.Foundation;
namespace LumaTunnel.Client.Views;
public sealed partial class DashboardPage : Page
{
private readonly Queue<double> _upload = new();
private readonly Queue<double> _download = new();
private DispatcherTimer? _timer;
public DashboardViewModel ViewModel { get; } = new();
public DashboardPage()
{
InitializeComponent();
ViewModel.PropertyChanged += (_, args) =>
{
if (args.PropertyName == nameof(ViewModel.ErrorText))
{
ErrorBar.Message = ViewModel.ErrorText ?? string.Empty;
ErrorBar.IsOpen = ViewModel.ErrorText is not null;
}
};
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
HttpEndpointText.Text = $"127.0.0.1:{AppServices.Profile.HttpPort}";
SocksEndpointText.Text = $"127.0.0.1:{AppServices.Profile.SocksPort}";
_timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
_timer.Tick += OnTick;
_timer.Start();
OnTick(null, null!);
}
private void OnUnloaded(object sender, RoutedEventArgs e) => _timer?.Stop();
private void OnTick(object? sender, object e)
{
var connections = AppServices.ProxyEngine.Connections;
AppServices.TrafficMeter.Sample();
var uploadRate = AppServices.TrafficMeter.Current.UploadBytesPerSecond;
var downloadRate = AppServices.TrafficMeter.Current.DownloadBytesPerSecond;
Push(_upload, uploadRate);
Push(_download, downloadRate);
ViewModel.Refresh(uploadRate, downloadRate);
ConnectionCountText.Text = connections.Count.ToString(System.Globalization.CultureInfo.InvariantCulture);
DrawLines();
}
private static void Push(Queue<double> values, double value)
{
values.Enqueue(value);
while (values.Count > 60) values.Dequeue();
}
private void DrawLines()
{
var max = Math.Max(1, _upload.Concat(_download).DefaultIfEmpty().Max());
var width = Math.Max(100, TrafficCanvas.ActualWidth);
UploadLine.Points = Points(_upload, max, width);
DownloadLine.Points = Points(_download, max, width);
}
private static PointCollection Points(IEnumerable<double> values, double max, double width)
{
var data = values.ToArray();
var points = new PointCollection();
for (var index = 0; index < data.Length; index++)
points.Add(new Point(index * width / 59d, 145 - (data[index] / max * 135)));
return points;
}
}