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 System.Text.Json;
using LumaTunnel.Shared.Models;
using LumaTunnel.Shared.Protocol;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace LumaTunnel.Client.Views;

public sealed partial class RoutingPage : Page
{
    private List<RoutingRule> _rules = [];
    private bool _loaded;
    public RoutingPage() => InitializeComponent();

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        _rules = AppServices.Profile.Rules.OrderBy(static rule => rule.Priority).ToList();
        ModeBox.SelectedIndex = AppServices.Profile.Mode switch { ProxyMode.Rule => 0, ProxyMode.Global => 1, _ => 2 };
        _loaded = true;
        Refresh();
    }

    private async void OnModeChanged(object sender, SelectionChangedEventArgs e)
    {
        if (!_loaded) return;
        await AppServices.SetModeAsync(ModeBox.SelectedIndex switch { 0 => ProxyMode.Rule, 1 => ProxyMode.Global, _ => ProxyMode.Direct });
    }

    private async void OnAdd(object sender, RoutedEventArgs e)
    {
        try
        {
            var rule = new RoutingRule
            {
                Kind = (RuleKind)KindBox.SelectedIndex,
                Value = ValueBox.Text.Trim(),
                Action = ActionBox.SelectedIndex == 0 ? RouteAction.Tunnel : RouteAction.Direct,
                Priority = _rules.Count
            };
            var candidate = _rules.Append(rule).ToList();
            AppServices.Routing.SetRules(candidate);
            _rules = candidate;
            await SaveAsync();
            ValueBox.Text = string.Empty;
        }
        catch (Exception exception) { Show(exception.Message, InfoBarSeverity.Error); }
    }

    private async void OnDelete(object sender, RoutedEventArgs e)
    {
        if (RuleList.SelectedIndex < 0) return;
        _rules.RemoveAt(RuleList.SelectedIndex);
        await SaveAsync();
    }

    private async void OnMoveUp(object sender, RoutedEventArgs e) => await MoveAsync(-1);
    private async void OnMoveDown(object sender, RoutedEventArgs e) => await MoveAsync(1);

    private async Task MoveAsync(int delta)
    {
        var source = RuleList.SelectedIndex;
        var target = source + delta;
        if (source < 0 || target < 0 || target >= _rules.Count) return;
        (_rules[source], _rules[target]) = (_rules[target], _rules[source]);
        await SaveAsync();
        RuleList.SelectedIndex = target;
    }

    private async void OnExport(object sender, RoutedEventArgs e)
    {
        var box = new TextBox { Text = JsonSerializer.Serialize(_rules, TunnelMessageSerializer.Options), AcceptsReturn = true, TextWrapping = TextWrapping.Wrap, MinWidth = 620, MinHeight = 300, IsReadOnly = true };
        await new ContentDialog { Title = "规则 JSON", Content = box, CloseButtonText = "关闭", XamlRoot = XamlRoot }.ShowAsync();
    }

    private async void OnImport(object sender, RoutedEventArgs e)
    {
        var box = new TextBox { AcceptsReturn = true, TextWrapping = TextWrapping.Wrap, MinWidth = 620, MinHeight = 300, PlaceholderText = "粘贴规则 JSON 数组" };
        var dialog = new ContentDialog { Title = "导入规则", Content = box, PrimaryButtonText = "导入", CloseButtonText = "取消", XamlRoot = XamlRoot };
        if (await dialog.ShowAsync() != ContentDialogResult.Primary) return;
        try
        {
            _rules = JsonSerializer.Deserialize<List<RoutingRule>>(box.Text, TunnelMessageSerializer.Options) ?? [];
            AppServices.Routing.SetRules(_rules);
            await SaveAsync();
        }
        catch (Exception exception) { Show(exception.Message, InfoBarSeverity.Error); }
    }

    private async Task SaveAsync()
    {
        _rules = _rules.Select((rule, index) => rule with { Priority = index }).ToList();
        await AppServices.SetRulesAsync(_rules);
        Refresh();
    }

    private void Refresh() => RuleList.ItemsSource = _rules.Select(rule => $"{rule.Priority + 1}. {rule.Kind}  {rule.Value}  →  {rule.Action}").ToArray();
    private void Show(string message, InfoBarSeverity severity) { MessageBar.Message = message; MessageBar.Severity = severity; MessageBar.IsOpen = true; }
}