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