Refactor: ModeHelper, Mode.Type, Netch.Enums.ModeType

This commit is contained in:
ChsBuffer
2021-05-06 23:43:13 +08:00
parent 6f6ff85549
commit ee2d35cb5d
11 changed files with 125 additions and 131 deletions

View File

@@ -55,7 +55,7 @@ namespace Netch.Controllers
public static void Start(Server server, Mode mode)
{
Global.Logger.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
Global.Logger.Info($"启动主控制器: {server.Type} [{(int)mode.Type}]{mode.Remark}");
Server = server;
Mode = mode;

View File

@@ -149,7 +149,7 @@ namespace Netch.Controllers
{
Dial(NameList.TYPE_CLRNAME, "");
var invalidList = new List<string>();
foreach (var s in mode.FullRule)
foreach (var s in mode.GetRules())
{
if (s.StartsWith("!"))
{

View File

@@ -40,7 +40,7 @@ namespace Netch.Controllers
else
argument.Append($" --destination 127.0.0.1:{Global.Settings.Socks5LocalPort}");
argument.Append($" {mode.FullRule.FirstOrDefault() ?? "-P n"}");
argument.Append($" {mode.GetRules().FirstOrDefault() ?? "-P n"}");
StartInstanceAuto(argument.ToString());
}

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Netch.Enums;
using Netch.Interfaces;
using Netch.Interops;
using Netch.Models;
@@ -95,8 +96,8 @@ namespace Netch.Controllers
_tunAdapter = new TunAdapter();
switch (mode.Type)
{
case 1 when Global.Settings.TUNTAP.ProxyDNS:
case 2:
case ModeType.ProxyRuleIPs when Global.Settings.TUNTAP.ProxyDNS:
case ModeType.BypassRuleIPs:
_tunAdapter.NetworkInterface.SetDns(DummyDns);
break;
}
@@ -167,10 +168,10 @@ namespace Netch.Controllers
switch (mode.Type)
{
case 1:
case ModeType.ProxyRuleIPs:
// 代理规则 IP
Global.Logger.Info("代理 → 规则 IP");
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
RouteAction(Action.Create, mode.GetRules(), RouteType.TUNTAP);
if (Global.Settings.TUNTAP.ProxyDNS)
{
@@ -186,17 +187,17 @@ namespace Netch.Controllers
}
break;
case 2:
case ModeType.BypassRuleIPs:
// 绕过规则 IP
Global.Logger.Info("绕行 → 规则 IP");
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
RouteAction(Action.Create, mode.GetRules(), RouteType.Outbound);
break;
}
#endregion
if (mode.Type == 2)
if (mode.Type == ModeType.BypassRuleIPs)
{
Global.Logger.Info("代理 → 全局");
SetInterface(RouteType.TUNTAP, 0);
@@ -225,7 +226,7 @@ namespace Netch.Controllers
RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP);
_directIPs.Clear();
_proxyIPs.Clear();
if (mode.Type == 2)
if (mode.Type == ModeType.BypassRuleIPs)
{
SetInterface(RouteType.Outbound);
}

10
Netch/Enums/Modes.cs Normal file
View File

@@ -0,0 +1,10 @@
namespace Netch.Enums
{
public enum ModeType
{
Process = 0,
ProxyRuleIPs = 1,
BypassRuleIPs = 2,
Pcap2Socks = 6
}
}

View File

@@ -14,6 +14,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Enums;
using Netch.Interfaces;
namespace Netch.Forms
@@ -727,13 +728,13 @@ namespace Netch.Forms
switch (mode.Type)
{
case 0:
case ModeType.Process:
Hide();
new Process(mode).ShowDialog();
Show();
break;
case 1:
case 2:
case ModeType.ProxyRuleIPs:
case ModeType.BypassRuleIPs:
Hide();
new Route(mode).ShowDialog();
Show();
@@ -1422,7 +1423,7 @@ namespace Netch.Forms
// 绘制 模式行数 字符串
TextRenderer.DrawText(e.Graphics,
item.Rule.Count.ToString(),
item.Content.Count.ToString(),
cbx.Font,
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
Color.Black,

View File

@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Netch.Enums;
namespace Netch.Forms.Mode
{
@@ -24,7 +25,7 @@ namespace Netch.Forms.Mode
/// <param name="mode">模式</param>
public Process(Models.Mode? mode = null)
{
if (mode != null && mode.Type is not 0)
if (mode != null && mode.Type is not ModeType.Process)
throw new ArgumentOutOfRangeException();
InitializeComponent();
@@ -62,7 +63,7 @@ namespace Netch.Forms.Mode
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
RemarkTextBox.Text = _mode.Remark;
FilenameTextBox.Text = _mode.RelativePath;
RuleAddRange(_mode.Rule);
RuleAddRange(_mode.Content);
}
i18N.TranslateForm(this);
@@ -116,8 +117,8 @@ namespace Netch.Forms.Mode
if (_mode != null)
{
_mode.Remark = RemarkTextBox.Text;
_mode.Rule.Clear();
_mode.Rule.AddRange(RuleRichTextBox.Lines);
_mode.Content.Clear();
_mode.Content.AddRange(RuleRichTextBox.Lines);
_mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
@@ -134,11 +135,11 @@ namespace Netch.Forms.Mode
var mode = new Models.Mode(fullName)
{
Type = 0,
Type = ModeType.Process,
Remark = RemarkTextBox.Text
};
mode.Rule.AddRange(RuleRichTextBox.Lines);
mode.Content.AddRange(RuleRichTextBox.Lines);
mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode added successfully"));

View File

@@ -4,18 +4,20 @@ using Netch.Utils;
using System;
using System.IO;
using System.Windows.Forms;
using Netch.Enums;
namespace Netch.Forms.Mode
{
public partial class Route : Form
{
private readonly TagItem<int>[] _items = { new(1, "Proxy Rule IPs"), new(2, "Bypass Rule IPs") };
private readonly TagItem<ModeType>[] _items =
{ new(ModeType.ProxyRuleIPs, "Proxy Rule IPs"), new(ModeType.BypassRuleIPs, "Bypass Rule IPs") };
private readonly Models.Mode? _mode;
public Route(Models.Mode? mode = null)
{
if (mode != null && mode.Type is not (1 or 2))
if (mode != null && mode.Type is not (ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs))
throw new ArgumentOutOfRangeException();
_mode = mode;
@@ -37,7 +39,7 @@ namespace Netch.Forms.Mode
RemarkTextBox.Text = _mode.Remark;
comboBox1.SelectedValue = _mode.Type; // ComboBox SelectedValue worked after ctor
FilenameTextBox.Text = _mode.RelativePath;
richTextBox1.Lines = _mode.Rule.ToArray();
richTextBox1.Lines = _mode.Content.ToArray();
}
i18N.TranslateForm(this);
@@ -60,9 +62,9 @@ namespace Netch.Forms.Mode
if (_mode != null)
{
_mode.Remark = RemarkTextBox.Text;
_mode.Rule.Clear();
_mode.Rule.AddRange(richTextBox1.Lines);
_mode.Type = (int)comboBox1.SelectedValue;
_mode.Content.Clear();
_mode.Content.AddRange(richTextBox1.Lines);
_mode.Type = (ModeType)comboBox1.SelectedValue;
_mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
@@ -79,11 +81,11 @@ namespace Netch.Forms.Mode
var mode = new Models.Mode(fullName)
{
Type = (int)comboBox1.SelectedValue,
Type = (ModeType)comboBox1.SelectedValue,
Remark = RemarkTextBox.Text
};
mode.Rule.AddRange(richTextBox1.Lines);
mode.Content.AddRange(richTextBox1.Lines);
mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode added successfully"));

View File

@@ -4,138 +4,126 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Netch.Enums;
namespace Netch.Models
{
public class Mode
{
private readonly Lazy<List<string>> _lazyRule;
public string? FullName { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="fullName">Mode File FullPath</param>
/// <exception cref="FormatException"></exception>
/// <exception cref="NotSupportedException"></exception>
public Mode(string? fullName)
{
_lazyRule = new Lazy<List<string>>(ReadRules);
if (fullName == null)
return;
FullName = fullName;
if (!File.Exists(FullName))
if (FullName == null || !File.Exists(FullName))
return;
var text = File.ReadLines(FullName).First();
// load head
if (text.First() != '#')
throw new Exception($"mode {FullName} head not found at Line 0");
var split = text.Substring(1).SplitTrimEntries(',');
Remark = split[0];
var typeResult = int.TryParse(split.ElementAtOrDefault(1), out var type);
Type = typeResult ? type : 0;
if (!ModeHelper.ModeTypes.Contains(Type))
throw new NotSupportedException($"not support mode \"[{Type}]{Remark}\".");
(Remark, Type) = ReadHead(FullName);
}
public string? FullName { get; }
/// <summary>
/// 规则
/// </summary>
public List<string> Rule => _lazyRule.Value;
public List<string> Content => _content ??= ReadContent();
private List<string>? _content;
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; } = "";
/// <summary>
/// 类型
/// <para />
/// 0. Socks5 + 进程加速
/// <para />
/// 1. Socks5 + TUN/TAP 规则内 IP CIDR 加速
/// <para />
/// 2. Socks5 + TUN/TAP 全局,绕过规则内 IP CIDR
/// <para />
/// 3. Socks5 + HTTP 代理(设置到系统代理)
/// <para />
/// 4. Socks5 代理(不设置到系统代理)
/// <para />
/// 5. Socks5 + HTTP 代理(不设置到系统代理)
/// <para />
/// </summary>
public int Type { get; set; } = 0;
public ModeType Type { get; set; } = ModeType.Process;
/// <summary>
/// 文件相对路径(必须是存在的文件)
/// </summary>
public string? RelativePath => FullName == null ? null : ModeHelper.GetRelativePath(FullName);
public List<string> FullRule
public IEnumerable<string> GetRules()
{
get
var result = new List<string>();
foreach (var s in Content)
{
var result = new List<string>();
foreach (var s in Rule)
if (string.IsNullOrWhiteSpace(s))
continue;
if (s.StartsWith("//"))
continue;
const string include = "#include";
if (s.StartsWith(include))
{
if (string.IsNullOrWhiteSpace(s))
continue;
var relativePath = new StringBuilder(s[include.Length..].Trim());
relativePath.Replace("<", "").Replace(">", "");
relativePath.Replace(".h", ".txt");
if (s.StartsWith("//"))
continue;
var mode = Global.Modes.FirstOrDefault(m => m.RelativePath?.Equals(relativePath.ToString()) ?? false) ??
throw new MessageException($"{relativePath} file included in {Remark} not found");
if (s.StartsWith("#include"))
{
var relativePath = new StringBuilder(s.Substring(8).Trim());
relativePath.Replace("<", "");
relativePath.Replace(">", "");
relativePath.Replace(".h", ".txt");
if (mode == this)
throw new MessageException("Can't self-reference");
var mode = Global.Modes.FirstOrDefault(m => m.FullName != null && m.RelativePath!.Equals(relativePath.ToString()));
if (mode.Type != Type)
throw new MessageException($"{mode.Remark}'s mode is not as same as {Remark}'s mode");
if (mode == null)
throw new MessageException($"{relativePath} file included in {Remark} not found");
if (mode.Content.Any(rule => rule.StartsWith(include)))
throw new Exception("Cannot reference mode that reference other mode");
if (mode == this)
throw new MessageException("Can't self-reference");
if (mode.Type != Type)
throw new MessageException($"{mode.Remark}'s mode is not as same as {Remark}'s mode");
if (mode.Rule.Any(rule => rule.StartsWith("#include")))
throw new Exception("Cannot reference mode that reference other mode");
result.AddRange(mode.FullRule);
}
else
{
result.Add(s);
}
result.AddRange(mode.GetRules());
}
else
{
result.Add(s);
}
return result;
}
return result;
}
private List<string> ReadRules()
private static (string, ModeType) ReadHead(string fileName)
{
var text = File.ReadLines(fileName).First();
if (text.First() != '#')
throw new FormatException($"{fileName} head not found at Line 0");
var split = text[1..].SplitTrimEntries(',');
var typeNumber = int.TryParse(split.ElementAtOrDefault(1), out var type) ? type : 0;
if (!Enum.GetValues(typeof(ModeType)).Cast<int>().Contains(typeNumber))
throw new NotSupportedException($"Not support mode \"{typeNumber}\".");
return (split[0], (ModeType)typeNumber);
}
private List<string> ReadContent()
{
if (FullName == null || !File.Exists(FullName))
return new List<string>();
return File.ReadLines(FullName!).Skip(1).ToList();
return File.ReadLines(FullName).Skip(1).ToList();
}
public void WriteFile(string? fullName = null)
public void ResetContent()
{
if (fullName != null)
throw new NotImplementedException();
_content = null;
}
public void WriteFile()
{
var dir = Path.GetDirectoryName(FullName)!;
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
var content = $"# {Remark}, {(int)Type}{Constants.EOF}{string.Join(Constants.EOF, Content)}";
// 写入到模式文件里
File.WriteAllText(FullName!, ToFileString());
File.WriteAllText(FullName!, content);
}
/// <summary>
@@ -144,16 +132,7 @@ namespace Netch.Models
/// <returns>备注</returns>
public override string ToString()
{
return $"[{Type + 1}] {i18N.Translate(Remark)}";
}
/// <summary>
/// 获取模式文件字符串
/// </summary>
/// <returns>模式文件字符串</returns>
public string ToFileString()
{
return $"# {Remark}, {Type}{Constants.EOF}{string.Join(Constants.EOF, Rule)}";
return $"[{(int)Type + 1}] {i18N.Translate(Remark)}";
}
}
@@ -162,7 +141,7 @@ namespace Netch.Models
/// 是否会转发 UDP
public static bool TestNatRequired(this Mode mode)
{
return mode.Type is 0 or 2;
return mode.Type is ModeType.Process or ModeType.BypassRuleIPs;
}
}
}

View File

@@ -3,6 +3,7 @@ using Netch.Servers.V2ray.Models;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Netch.Enums;
using V2rayConfig = Netch.Servers.V2ray.Models.V2rayConfig;
namespace Netch.Servers.V2ray.Utils
@@ -65,7 +66,7 @@ namespace Netch.Servers.V2ray.Utils
outboundTag = "block"
};
if (mode.Type is 0 or 1 or 2)
if (mode.Type is ModeType.Process or ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs)
blockRuleObject.ip.Add("geoip:private");
static bool CheckRuleItem(ref RulesItem rulesItem)

View File

@@ -2,6 +2,7 @@ using System;
using System.IO;
using System.Linq;
using Netch.Controllers;
using Netch.Enums;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Shadowsocks;
@@ -112,35 +113,33 @@ namespace Netch.Utils
{
switch (mode.Type)
{
case 0:
case ModeType.Process:
return server switch
{
Socks5 => true,
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.Redirector.RedirectorSS => true,
_ => false
};
case 1:
case 2:
case ModeType.ProxyRuleIPs:
case ModeType.BypassRuleIPs:
return server is Socks5;
default:
return false;
}
}
public static readonly int[] ModeTypes = { 0, 1, 2, 6 };
public static IModeController GetModeControllerByType(int type, out ushort? port, out string portName)
public static IModeController GetModeControllerByType(ModeType type, out ushort? port, out string portName)
{
port = null;
portName = string.Empty;
switch (type)
{
case 0:
case ModeType.Process:
return new NFController();
case 1:
case 2:
case ModeType.ProxyRuleIPs:
case ModeType.BypassRuleIPs:
return new TUNController();
case 6:
case ModeType.Pcap2Socks:
return new PcapController();
default:
Global.Logger.Error("未知模式类型");