Compare commits

..

1 commit

Author SHA1 Message Date
JieXu
dbf12af3a0
Merge bc1c42a2a2 into 120e8d0686 2025-08-16 16:15:31 +03:30
21 changed files with 130 additions and 51 deletions

View file

@ -305,6 +305,13 @@ public class Global
"" ""
]; ];
public static readonly List<string> DomainMatchers =
[
"linear",
"mph",
""
];
public static readonly List<string> Fingerprints = public static readonly List<string> Fingerprints =
[ [
"chrome", "chrome",

View file

@ -963,7 +963,7 @@ public class ConfigHandler
{ {
return -1; return -1;
} }
if (profileItem.Security.IsNullOrEmpty()) if (profileItem.Security.IsNotEmpty() && profileItem.Security != Global.None)
{ {
profileItem.Security = Global.None; profileItem.Security = Global.None;
} }

View file

@ -5,18 +5,15 @@ namespace ServiceLib.Handler;
public class PacHandler public class PacHandler
{ {
private static readonly Lazy<PacHandler> _instance = new(() => new PacHandler()); private static string _configPath;
public static PacHandler Instance => _instance.Value; private static int _httpPort;
private static int _pacPort;
private static TcpListener? _tcpListener;
private static byte[] _writeContent;
private static bool _isRunning;
private static bool _needRestart = true;
private string _configPath; public static async Task Start(string configPath, int httpPort, int pacPort)
private int _httpPort;
private int _pacPort;
private TcpListener? _tcpListener;
private byte[] _writeContent;
private bool _isRunning;
private bool _needRestart = true;
public async Task StartAsync(string configPath, int httpPort, int pacPort)
{ {
_needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning; _needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning;
@ -33,7 +30,7 @@ public class PacHandler
} }
} }
private async Task InitText() private static async Task InitText()
{ {
var path = Path.Combine(_configPath, "pac.txt"); var path = Path.Combine(_configPath, "pac.txt");
@ -62,7 +59,7 @@ public class PacHandler
_writeContent = Encoding.UTF8.GetBytes(sb.ToString()); _writeContent = Encoding.UTF8.GetBytes(sb.ToString());
} }
private void RunListener() private static void RunListener()
{ {
_tcpListener = TcpListener.Create(_pacPort); _tcpListener = TcpListener.Create(_pacPort);
_isRunning = true; _isRunning = true;
@ -90,14 +87,14 @@ public class PacHandler
}, TaskCreationOptions.LongRunning); }, TaskCreationOptions.LongRunning);
} }
private void WriteContent(TcpClient client) private static void WriteContent(TcpClient client)
{ {
var stream = client.GetStream(); var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length); stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush(); stream.Flush();
} }
public void Stop() public static void Stop()
{ {
if (_tcpListener == null) if (_tcpListener == null)
{ {

View file

@ -56,7 +56,7 @@ public static class SysProxyHandler
if (type != ESysProxyType.Pac && Utils.IsWindows()) if (type != ESysProxyType.Pac && Utils.IsWindows())
{ {
PacHandler.Instance.Stop(); PacHandler.Stop();
} }
} }
catch (Exception ex) catch (Exception ex)
@ -91,7 +91,7 @@ public static class SysProxyHandler
private static async Task SetWindowsProxyPac(int port) private static async Task SetWindowsProxyPac(int port)
{ {
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac); var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
await PacHandler.Instance.StartAsync(Utils.GetConfigPath(), port, portPac); await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}"; var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4); ProxySettingWindows.SetProxy(strProxy, "", 4);
} }

View file

@ -165,6 +165,7 @@ public class RoutingBasicItem
{ {
public string DomainStrategy { get; set; } public string DomainStrategy { get; set; }
public string DomainStrategy4Singbox { get; set; } public string DomainStrategy4Singbox { get; set; }
public string DomainMatcher { get; set; }
public string RoutingIndexId { get; set; } public string RoutingIndexId { get; set; }
} }

View file

@ -233,6 +233,8 @@ public class Routing4Ray
{ {
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
public string? domainMatcher { get; set; }
public List<RulesItem4Ray> rules { get; set; } public List<RulesItem4Ray> rules { get; set; }
public List<BalancersItem4Ray>? balancers { get; set; } public List<BalancersItem4Ray>? balancers { get; set; }

View file

@ -2463,6 +2463,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Domain Matcher 的本地化字符串。
/// </summary>
public static string TbdomainMatcher {
get {
return ResourceManager.GetString("TbdomainMatcher", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Domain strategy 的本地化字符串。 /// 查找类似 Domain strategy 的本地化字符串。
/// </summary> /// </summary>

View file

@ -825,6 +825,9 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>تنظیم کردن به عنوان قانون فعال</value> <value>تنظیم کردن به عنوان قانون فعال</value>
</data> </data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>تطبیق دامنه</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>استراتژی دامنه</value> <value>استراتژی دامنه</value>
</data> </data>

View file

@ -825,6 +825,9 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Beállítás aktív szabályként (Enter)</value> <value>Beállítás aktív szabályként (Enter)</value>
</data> </data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>Tartomány illesztő</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>Tartomány stratégia</value> <value>Tartomány stratégia</value>
</data> </data>

View file

@ -825,6 +825,9 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule (Enter)</value> <value>Set as active rule (Enter)</value>
</data> </data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>Domain Matcher</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>Domain strategy</value> <value>Domain strategy</value>
</data> </data>

View file

@ -825,6 +825,9 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Установить как активное правило</value> <value>Установить как активное правило</value>
</data> </data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>Сопоставитель доменов</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>Доменная стратегия</value> <value>Доменная стратегия</value>
</data> </data>

View file

@ -825,6 +825,9 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>设为活动规则 (Enter)</value> <value>设为活动规则 (Enter)</value>
</data> </data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>域名匹配算法</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>域名解析策略</value> <value>域名解析策略</value>
</data> </data>

View file

@ -825,6 +825,9 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>設為活動規則 (Enter)</value> <value>設為活動規則 (Enter)</value>
</data> </data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>域名匹配演算法</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>域名解析策略</value> <value>域名解析策略</value>
</data> </data>

View file

@ -523,6 +523,7 @@ public class CoreConfigV2rayService
if (v2rayConfig.routing?.rules != null) if (v2rayConfig.routing?.rules != null)
{ {
v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy; v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy;
v2rayConfig.routing.domainMatcher = _config.RoutingBasicItem.DomainMatcher.IsNullOrEmpty() ? null : _config.RoutingBasicItem.DomainMatcher;
var routing = await ConfigHandler.GetDefaultRouting(_config); var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null) if (routing != null)

View file

@ -75,7 +75,10 @@ public class CheckUpdateViewModel : MyReactiveObject
private async Task CheckUpdate() private async Task CheckUpdate()
{ {
await Task.Run(CheckUpdateTask); await Task.Run(async () =>
{
await CheckUpdateTask();
});
} }
private async Task CheckUpdateTask() private async Task CheckUpdateTask()

View file

@ -20,6 +20,9 @@ public class RoutingSettingViewModel : MyReactiveObject
[Reactive] [Reactive]
public string DomainStrategy { get; set; } public string DomainStrategy { get; set; }
[Reactive]
public string DomainMatcher { get; set; }
[Reactive] [Reactive]
public string DomainStrategy4Singbox { get; set; } public string DomainStrategy4Singbox { get; set; }
@ -72,6 +75,7 @@ public class RoutingSettingViewModel : MyReactiveObject
SelectedSource = new(); SelectedSource = new();
DomainStrategy = _config.RoutingBasicItem.DomainStrategy; DomainStrategy = _config.RoutingBasicItem.DomainStrategy;
DomainMatcher = _config.RoutingBasicItem.DomainMatcher;
DomainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox; DomainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox;
await ConfigHandler.InitBuiltinRouting(_config); await ConfigHandler.InitBuiltinRouting(_config);
@ -105,6 +109,7 @@ public class RoutingSettingViewModel : MyReactiveObject
private async Task SaveRoutingAsync() private async Task SaveRoutingAsync()
{ {
_config.RoutingBasicItem.DomainStrategy = DomainStrategy; _config.RoutingBasicItem.DomainStrategy = DomainStrategy;
_config.RoutingBasicItem.DomainMatcher = DomainMatcher;
_config.RoutingBasicItem.DomainStrategy4Singbox = DomainStrategy4Singbox; _config.RoutingBasicItem.DomainStrategy4Singbox = DomainStrategy4Singbox;
if (await ConfigHandler.SaveConfig(_config) == 0) if (await ConfigHandler.SaveConfig(_config) == 0)

View file

@ -334,7 +334,10 @@ public class StatusBarViewModel : MyReactiveObject
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting); _updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
var msg = await Task.Run(ConnectionHandler.Instance.RunAvailabilityCheck); var msg = await Task.Run(async () =>
{
return await ConnectionHandler.Instance.RunAvailabilityCheck();
});
NoticeHandler.Instance.SendMessageEx(msg); NoticeHandler.Instance.SendMessageEx(msg);
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg); _updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);

View file

@ -50,7 +50,7 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto" ColumnDefinitions="Auto,Auto"
DockPanel.Dock="Top" DockPanel.Dock="Top"
RowDefinitions="Auto,Auto"> RowDefinitions="Auto,Auto,Auto">
<TextBlock <TextBlock
Grid.Row="0" Grid.Row="0"
@ -74,6 +74,19 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
<ComboBox
x:Name="cmbdomainMatcher"
Grid.Row="1"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"> VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click"> <HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click">
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" /> <TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
@ -81,7 +94,7 @@
</TextBlock> </TextBlock>
<ComboBox <ComboBox
x:Name="cmbdomainStrategy4Singbox" x:Name="cmbdomainStrategy4Singbox"
Grid.Row="1" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="300" Width="300"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"

View file

@ -27,6 +27,7 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
ViewModel = new RoutingSettingViewModel(UpdateViewHandler); ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
cmbdomainStrategy.ItemsSource = Global.DomainStrategies; cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox; cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables => this.WhenActivated(disposables =>
@ -35,6 +36,7 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy, v => v.cmbdomainStrategy.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainStrategy, v => v.cmbdomainStrategy.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainMatcher, v => v.cmbdomainMatcher.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.SelectedValue).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables);

View file

@ -78,6 +78,7 @@
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@ -108,6 +109,21 @@
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
<ComboBox
x:Name="cmbdomainMatcher"
Grid.Row="1"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"> Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkdomainStrategy4Singbox_Click"> <Hyperlink Click="linkdomainStrategy4Singbox_Click">
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" /> <TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
@ -116,7 +132,7 @@
</TextBlock> </TextBlock>
<ComboBox <ComboBox
x:Name="cmbdomainStrategy4Singbox" x:Name="cmbdomainStrategy4Singbox"
Grid.Row="1" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="300" Width="300"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"

View file

@ -22,6 +22,7 @@ public partial class RoutingSettingWindow
ViewModel = new RoutingSettingViewModel(UpdateViewHandler); ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
cmbdomainStrategy.ItemsSource = Global.DomainStrategies; cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox; cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables => this.WhenActivated(disposables =>
@ -30,6 +31,7 @@ public partial class RoutingSettingWindow
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy, v => v.cmbdomainStrategy.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainStrategy, v => v.cmbdomainStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainMatcher, v => v.cmbdomainMatcher.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables);