LumaTunnel
【WinUI】LumaTunnel 是一个面向个人多设备的 Windows 代理系统。客户端在本机提供 HTTP/HTTPS CONNECT 与 SOCKS5 TCP 代理,并通过一个受信任 TLS 证书保护的 WSS 会话,将多个 TCP 流复用到自建 Windows Server 节点。
关注
0
Fork
0
Star
0
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace LumaTunnel.Client.ViewModels;
public partial class DashboardViewModel : ObservableObject
{
[ObservableProperty] public partial bool IsEnabled { get; private set; }
[ObservableProperty] public partial bool IsBusy { get; private set; }
[ObservableProperty] public partial string StatusText { get; private set; } = "代理已关闭";
[ObservableProperty] public partial string ActionText { get; private set; } = "启用代理";
[ObservableProperty] public partial string CurrentNodeText { get; private set; } = "未连接";
[ObservableProperty] public partial string TrafficText { get; private set; } = "↑ 0 B/s ↓ 0 B/s";
[ObservableProperty] public partial string? ErrorText { get; private set; }
[RelayCommand]
private async Task ToggleAsync()
{
if (IsBusy) return;
IsBusy = true;
ErrorText = null;
try
{
if (AppServices.IsEnabled)
await AppServices.DisableAsync();
else
await AppServices.EnableAsync();
}
catch (Exception exception)
{
ErrorText = exception.Message;
}
finally
{
IsBusy = false;
Refresh(0, 0);
}
}
public void Refresh(long uploadPerSecond, long downloadPerSecond)
{
IsEnabled = AppServices.IsEnabled;
StatusText = IsEnabled ? "代理运行中" : "代理已关闭";
ActionText = IsEnabled ? "关闭代理" : "启用代理";
CurrentNodeText = AppServices.Nodes.ActiveNode is { } node
? $"{node.Name} · {node.LastLatencyMilliseconds:0} ms"
: AppServices.Profile.Mode == Shared.Models.ProxyMode.Direct ? "直连模式" : "未连接";
TrafficText = $"↑ {FormatRate(uploadPerSecond)} ↓ {FormatRate(downloadPerSecond)}";
}
private static string FormatRate(long bytes) => bytes switch
{
>= 1024 * 1024 => $"{bytes / 1024d / 1024d:0.0} MB/s",
>= 1024 => $"{bytes / 1024d:0.0} KB/s",
_ => $"{bytes} B/s"
};
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace LumaTunnel.Client.ViewModels;
public partial class DashboardViewModel : ObservableObject
{
[ObservableProperty] public partial bool IsEnabled { get; private set; }
[ObservableProperty] public partial bool IsBusy { get; private set; }
[ObservableProperty] public partial string StatusText { get; private set; } = "代理已关闭";
[ObservableProperty] public partial string ActionText { get; private set; } = "启用代理";
[ObservableProperty] public partial string CurrentNodeText { get; private set; } = "未连接";
[ObservableProperty] public partial string TrafficText { get; private set; } = "↑ 0 B/s ↓ 0 B/s";
[ObservableProperty] public partial string? ErrorText { get; private set; }
[RelayCommand]
private async Task ToggleAsync()
{
if (IsBusy) return;
IsBusy = true;
ErrorText = null;
try
{
if (AppServices.IsEnabled)
await AppServices.DisableAsync();
else
await AppServices.EnableAsync();
}
catch (Exception exception)
{
ErrorText = exception.Message;
}
finally
{
IsBusy = false;
Refresh(0, 0);
}
}
public void Refresh(long uploadPerSecond, long downloadPerSecond)
{
IsEnabled = AppServices.IsEnabled;
StatusText = IsEnabled ? "代理运行中" : "代理已关闭";
ActionText = IsEnabled ? "关闭代理" : "启用代理";
CurrentNodeText = AppServices.Nodes.ActiveNode is { } node
? $"{node.Name} · {node.LastLatencyMilliseconds:0} ms"
: AppServices.Profile.Mode == Shared.Models.ProxyMode.Direct ? "直连模式" : "未连接";
TrafficText = $"↑ {FormatRate(uploadPerSecond)} ↓ {FormatRate(downloadPerSecond)}";
}
private static string FormatRate(long bytes) => bytes switch
{
>= 1024 * 1024 => $"{bytes / 1024d / 1024d:0.0} MB/s",
>= 1024 => $"{bytes / 1024d:0.0} KB/s",
_ => $"{bytes} B/s"
};
}