XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

LumaTunnel

【WinUI】LumaTunnel 是一个面向个人多设备的 Windows 代理系统。客户端在本机提供 HTTP/HTTPS CONNECT 与 SOCKS5 TCP 代理,并通过一个受信任 TLS 证书保护的 WSS 会话,将多个 TCP 流复用到自建 Windows Server 节点。

公开
关注 0 Fork 0 Star 0
UTF-8
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;
    }
}