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.Shared.Models;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace LumaTunnel.Client.Views;

public sealed partial class NodesPage : Page
{
    private List<NodeProfile> _nodes = [];
    public NodesPage() => InitializeComponent();
    private void OnLoaded(object sender, RoutedEventArgs e) => Refresh();

    private async void OnEnroll(object sender, RoutedEventArgs e)
    {
        await RunAsync(async () =>
        {
            await AppServices.EnrollNodeAsync(UrlBox.Text.Trim(), CodeBox.Text.Trim(), NameBox.Text.Trim());
            UrlBox.Text = CodeBox.Text = NameBox.Text = string.Empty;
            Refresh();
            Show("节点配对成功。", InfoBarSeverity.Success);
        });
    }

    private async void OnTest(object sender, RoutedEventArgs e)
    {
        if (Selected() is not { } node) return;
        await RunAsync(async () => Show($"延迟 {await AppServices.TestNodeAsync(node.Id):0} ms", InfoBarSeverity.Success));
    }

    private async void OnRename(object sender, RoutedEventArgs e)
    {
        if (Selected() is not { } node) return;
        var box = new TextBox { Text = node.Name, Header = "新名称" };
        var dialog = new ContentDialog { Title = "重命名节点", Content = box, PrimaryButtonText = "保存", CloseButtonText = "取消", XamlRoot = XamlRoot };
        if (await dialog.ShowAsync() == ContentDialogResult.Primary && !string.IsNullOrWhiteSpace(box.Text))
        {
            await AppServices.RenameNodeAsync(node.Id, box.Text);
            Refresh();
        }
    }

    private async void OnDelete(object sender, RoutedEventArgs e)
    {
        if (Selected() is not { } node) return;
        await AppServices.RemoveNodeAsync(node.Id);
        Refresh();
    }

    private NodeProfile? Selected() => NodeList.SelectedIndex >= 0 && NodeList.SelectedIndex < _nodes.Count ? _nodes[NodeList.SelectedIndex] : null;

    private void Refresh()
    {
        _nodes = AppServices.Profile.Nodes.ToList();
        NodeList.ItemsSource = _nodes.Select(node => $"{node.Name}    {node.ApiUri.Host}    {(node.LastLatencyMilliseconds is null ? "未测速" : $"{node.LastLatencyMilliseconds:0} ms")}").ToArray();
    }

    private async Task RunAsync(Func<Task> action)
    {
        try { await action(); }
        catch (Exception exception) { Show(exception.Message, InfoBarSeverity.Error); }
    }

    private void Show(string message, InfoBarSeverity severity)
    {
        MessageBar.Message = message;
        MessageBar.Severity = severity;
        MessageBar.IsOpen = true;
    }
}