mirror of
https://github.com/2dust/v2rayN.git
synced 2025-05-03 05:38:51 +00:00
360 lines
No EOL
11 KiB
C#
360 lines
No EOL
11 KiB
C#
using DynamicData.Binding;
|
|
using Microsoft.Win32;
|
|
using ReactiveUI;
|
|
using ReactiveUI.Fody.Helpers;
|
|
using Splat;
|
|
using System.Reactive;
|
|
using System.Windows;
|
|
using v2rayN.Base;
|
|
using v2rayN.Handler;
|
|
using v2rayN.Mode;
|
|
using v2rayN.Resx;
|
|
using v2rayN.Views;
|
|
using Application = System.Windows.Application;
|
|
|
|
namespace v2rayN.ViewModels
|
|
{
|
|
public class RoutingRuleSettingViewModel : ReactiveObject
|
|
{
|
|
private static Config _config;
|
|
private NoticeHandler? _noticeHandler;
|
|
private Window _view;
|
|
private List<RulesItem> _rules;
|
|
|
|
[Reactive]
|
|
public RoutingItem SelectedRouting { get; set; }
|
|
|
|
private IObservableCollection<RulesItemModel> _rulesItems = new ObservableCollectionExtended<RulesItemModel>();
|
|
public IObservableCollection<RulesItemModel> RulesItems => _rulesItems;
|
|
|
|
[Reactive]
|
|
public RulesItemModel SelectedSource { get; set; }
|
|
|
|
public IList<RulesItemModel> SelectedSources { get; set; }
|
|
|
|
public ReactiveCommand<Unit, Unit> RuleAddCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> ImportRulesFromFileCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> ImportRulesFromClipboardCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> ImportRulesFromUrlCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> RuleRemoveCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> RuleExportSelectedCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> MoveUpCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> MoveDownCmd { get; }
|
|
public ReactiveCommand<Unit, Unit> MoveBottomCmd { get; }
|
|
|
|
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
|
|
|
public RoutingRuleSettingViewModel(RoutingItem routingItem, Window view)
|
|
{
|
|
_config = LazyConfig.Instance.GetConfig();
|
|
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
|
|
_view = view;
|
|
SelectedSource = new();
|
|
|
|
if (routingItem.id.IsNullOrEmpty())
|
|
{
|
|
SelectedRouting = routingItem;
|
|
_rules = new();
|
|
}
|
|
else
|
|
{
|
|
SelectedRouting = routingItem;
|
|
_rules = Utils.FromJson<List<RulesItem>>(SelectedRouting.ruleSet);
|
|
}
|
|
|
|
RefreshRulesItems();
|
|
|
|
var canEditRemove = this.WhenAnyValue(
|
|
x => x.SelectedSource,
|
|
selectedSource => selectedSource != null && !selectedSource.outboundTag.IsNullOrEmpty());
|
|
|
|
RuleAddCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
RuleEdit(true);
|
|
});
|
|
ImportRulesFromFileCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
ImportRulesFromFile();
|
|
});
|
|
ImportRulesFromClipboardCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
ImportRulesFromClipboard();
|
|
});
|
|
ImportRulesFromUrlCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
ImportRulesFromUrl();
|
|
});
|
|
|
|
RuleRemoveCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
RuleRemove();
|
|
}, canEditRemove);
|
|
RuleExportSelectedCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
RuleExportSelected();
|
|
}, canEditRemove);
|
|
|
|
MoveTopCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
MoveRule(EMove.Top);
|
|
}, canEditRemove);
|
|
MoveUpCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
MoveRule(EMove.Up);
|
|
}, canEditRemove);
|
|
MoveDownCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
MoveRule(EMove.Down);
|
|
}, canEditRemove);
|
|
MoveBottomCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
MoveRule(EMove.Bottom);
|
|
}, canEditRemove);
|
|
|
|
SaveCmd = ReactiveCommand.Create(() =>
|
|
{
|
|
SaveRouting();
|
|
});
|
|
|
|
Utils.SetDarkBorder(view, _config.uiItem.colorModeDark);
|
|
}
|
|
|
|
public void RefreshRulesItems()
|
|
{
|
|
_rulesItems.Clear();
|
|
|
|
foreach (var item in _rules)
|
|
{
|
|
var it = new RulesItemModel()
|
|
{
|
|
id = item.id,
|
|
outboundTag = item.outboundTag,
|
|
port = item.port,
|
|
protocols = Utils.List2String(item.protocol),
|
|
inboundTags = Utils.List2String(item.inboundTag),
|
|
domains = Utils.List2String(item.domain),
|
|
ips = Utils.List2String(item.ip),
|
|
enabled = item.enabled,
|
|
};
|
|
_rulesItems.Add(it);
|
|
}
|
|
}
|
|
|
|
public void RuleEdit(bool blNew)
|
|
{
|
|
RulesItem item;
|
|
if (blNew)
|
|
{
|
|
item = new();
|
|
}
|
|
else
|
|
{
|
|
item = _rules.FirstOrDefault(t => t.id == SelectedSource?.id);
|
|
if (item is null)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
var ret = (new RoutingRuleDetailsWindow(item)).ShowDialog();
|
|
if (ret == true)
|
|
{
|
|
if (blNew)
|
|
{
|
|
_rules.Add(item);
|
|
}
|
|
RefreshRulesItems();
|
|
}
|
|
}
|
|
|
|
public void RuleRemove()
|
|
{
|
|
if (SelectedSource is null || SelectedSource.outboundTag.IsNullOrEmpty())
|
|
{
|
|
UI.Show(ResUI.PleaseSelectRules);
|
|
return;
|
|
}
|
|
if (UI.ShowYesNo(ResUI.RemoveRules) == MessageBoxResult.No)
|
|
{
|
|
return;
|
|
}
|
|
foreach (var it in SelectedSources)
|
|
{
|
|
var item = _rules.FirstOrDefault(t => t.id == it?.id);
|
|
if (item != null)
|
|
{
|
|
_rules.Remove(item);
|
|
}
|
|
}
|
|
|
|
RefreshRulesItems();
|
|
}
|
|
|
|
public void RuleExportSelected()
|
|
{
|
|
if (SelectedSource is null || SelectedSource.outboundTag.IsNullOrEmpty())
|
|
{
|
|
UI.Show(ResUI.PleaseSelectRules);
|
|
return;
|
|
}
|
|
|
|
var lst = new List<RulesItem>();
|
|
foreach (var it in SelectedSources)
|
|
{
|
|
var item = _rules.FirstOrDefault(t => t.id == it?.id);
|
|
if (item != null)
|
|
{
|
|
lst.Add(item);
|
|
}
|
|
}
|
|
if (lst.Count > 0)
|
|
{
|
|
Utils.SetClipboardData(Utils.ToJson(lst));
|
|
//UI.Show(ResUI.OperationSuccess"));
|
|
}
|
|
}
|
|
|
|
public void MoveRule(EMove eMove)
|
|
{
|
|
if (SelectedSource is null || SelectedSource.outboundTag.IsNullOrEmpty())
|
|
{
|
|
UI.Show(ResUI.PleaseSelectRules);
|
|
return;
|
|
}
|
|
|
|
var item = _rules.FirstOrDefault(t => t.id == SelectedSource?.id);
|
|
if (item == null)
|
|
{
|
|
return;
|
|
}
|
|
var index = _rules.IndexOf(item);
|
|
if (ConfigHandler.MoveRoutingRule(_rules, index, eMove) == 0)
|
|
{
|
|
RefreshRulesItems();
|
|
}
|
|
}
|
|
|
|
private void SaveRouting()
|
|
{
|
|
string remarks = SelectedRouting.remarks;
|
|
if (Utils.IsNullOrEmpty(remarks))
|
|
{
|
|
UI.Show(ResUI.PleaseFillRemarks);
|
|
return;
|
|
}
|
|
var item = SelectedRouting;
|
|
foreach (var it in _rules)
|
|
{
|
|
it.id = Utils.GetGUID(false);
|
|
}
|
|
item.ruleNum = _rules.Count;
|
|
item.ruleSet = Utils.ToJson(_rules, false);
|
|
|
|
if (ConfigHandler.SaveRoutingItem(ref _config, item) == 0)
|
|
{
|
|
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
|
_view.DialogResult = true;
|
|
}
|
|
else
|
|
{
|
|
UI.ShowWarning(ResUI.OperationFailed);
|
|
}
|
|
}
|
|
|
|
#region Import rules
|
|
|
|
private void ImportRulesFromFile()
|
|
{
|
|
OpenFileDialog fileDialog = new OpenFileDialog
|
|
{
|
|
Multiselect = false,
|
|
Filter = "Rules|*.json|All|*.*"
|
|
};
|
|
if (fileDialog.ShowDialog() != true)
|
|
{
|
|
return;
|
|
}
|
|
string fileName = fileDialog.FileName;
|
|
if (Utils.IsNullOrEmpty(fileName))
|
|
{
|
|
return;
|
|
}
|
|
string result = Utils.LoadResource(fileName);
|
|
if (Utils.IsNullOrEmpty(result))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
|
|
{
|
|
RefreshRulesItems();
|
|
UI.Show(ResUI.OperationSuccess);
|
|
}
|
|
}
|
|
|
|
private void ImportRulesFromClipboard()
|
|
{
|
|
string clipboardData = Utils.GetClipboardData();
|
|
if (AddBatchRoutingRules(SelectedRouting, clipboardData) == 0)
|
|
{
|
|
RefreshRulesItems();
|
|
UI.Show(ResUI.OperationSuccess);
|
|
}
|
|
}
|
|
|
|
private async Task ImportRulesFromUrl()
|
|
{
|
|
var url = SelectedRouting.url;
|
|
if (Utils.IsNullOrEmpty(url))
|
|
{
|
|
UI.Show(ResUI.MsgNeedUrl);
|
|
return;
|
|
}
|
|
|
|
DownloadHandle downloadHandle = new DownloadHandle();
|
|
string result = await downloadHandle.TryDownloadString(url, true, "");
|
|
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
|
|
{
|
|
Application.Current.Dispatcher.Invoke((Action)(() =>
|
|
{
|
|
RefreshRulesItems();
|
|
}));
|
|
UI.Show(ResUI.OperationSuccess);
|
|
}
|
|
}
|
|
|
|
private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData)
|
|
{
|
|
bool blReplace = false;
|
|
if (UI.ShowYesNo(ResUI.AddBatchRoutingRulesYesNo) == MessageBoxResult.No)
|
|
{
|
|
blReplace = true;
|
|
}
|
|
if (Utils.IsNullOrEmpty(clipboardData))
|
|
{
|
|
return -1;
|
|
}
|
|
var lstRules = Utils.FromJson<List<RulesItem>>(clipboardData);
|
|
if (lstRules == null)
|
|
{
|
|
return -1;
|
|
}
|
|
foreach (var rule in lstRules)
|
|
{
|
|
rule.id = Utils.GetGUID(false);
|
|
}
|
|
|
|
if (blReplace)
|
|
{
|
|
_rules = lstRules;
|
|
}
|
|
else
|
|
{
|
|
_rules.AddRange(lstRules);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endregion Import rules
|
|
}
|
|
} |