Compare commits
223 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ede3af762 | ||
|
|
97ea1c7a9e | ||
|
|
43bb2c0fb8 | ||
|
|
6e7196bb27 | ||
|
|
87a71d58e8 | ||
|
|
32ffd43fe3 | ||
|
|
6500c8d85e | ||
|
|
9866d436da | ||
|
|
0f4884d9d8 | ||
|
|
5a81441351 | ||
|
|
e8721bfb6b | ||
|
|
1b09d95209 | ||
|
|
35f3b5a50e | ||
|
|
ff5203a561 | ||
|
|
c3c1ced309 | ||
|
|
08b1c8ec83 | ||
|
|
1dd3ee4e0a | ||
|
|
06d0c6517d | ||
|
|
4938ce6364 | ||
|
|
25f3fc354f | ||
|
|
ad1a1f8015 | ||
|
|
5c070e2ca8 | ||
|
|
70ea21fca2 | ||
|
|
bc3593871b | ||
|
|
355a424be2 | ||
|
|
0ffa9a0cc8 | ||
|
|
72fecb2b9a | ||
|
|
4e9dfe5478 | ||
|
|
c79e2e3ad4 | ||
|
|
7c33c1c322 | ||
|
|
ea32f75925 | ||
|
|
7eaed21b9a | ||
|
|
cfe8fcd28d | ||
|
|
9f4718af70 | ||
|
|
39faccfd0b | ||
|
|
7545763dae | ||
|
|
c2928be35d | ||
|
|
449bb40d48 | ||
|
|
4caf1a1e63 | ||
|
|
01b205e6f1 | ||
|
|
160d3843a6 | ||
|
|
5efb784115 | ||
|
|
acde5b8384 | ||
|
|
373ee6586a | ||
|
|
215308c329 | ||
|
|
478cadba5e | ||
|
|
f4af4da791 | ||
|
|
22d4f435de | ||
|
|
ccb8cd5c04 | ||
|
|
e963f9e349 | ||
|
|
e3c2a4b8da | ||
|
|
324f46cdad | ||
|
|
691b19b5fd | ||
|
|
63ed2311dc | ||
|
|
d59e59ca40 | ||
|
|
c9a278b4a2 | ||
|
|
8ee5304148 | ||
|
|
3beaa8145f | ||
|
|
e30c55a0af | ||
|
|
b583590a64 | ||
|
|
a28c63168a | ||
|
|
620422350f | ||
|
|
b77cc3c33b | ||
|
|
71bf9b4887 | ||
|
|
9039d401da | ||
|
|
74a0a93201 | ||
|
|
522571f0b3 | ||
|
|
123c49c22d | ||
|
|
1ff88d29be | ||
|
|
63d5a2a1be | ||
|
|
1e9a6cb06b | ||
|
|
31748aa660 | ||
|
|
d0c6ea6a63 | ||
|
|
7ffe286a56 | ||
|
|
b99b30163b | ||
|
|
83b4f1e660 | ||
|
|
b57ba6a98b | ||
|
|
d748e6eff4 | ||
|
|
315d4b75b2 | ||
|
|
31267cbc33 | ||
|
|
c23379b3b6 | ||
|
|
568144d6a2 | ||
|
|
5857042963 | ||
|
|
28e41dc621 | ||
|
|
baef3b364b | ||
|
|
4b9ddb803f | ||
|
|
c07c7ad82f | ||
|
|
e223b80b95 | ||
|
|
5fe468fa1b | ||
|
|
60068d8d16 | ||
|
|
b6c5b46afe | ||
|
|
124cbfadb4 | ||
|
|
8d21f9b900 | ||
|
|
398dbbd2e5 | ||
|
|
e9b392d1c0 | ||
|
|
9d7c7e3225 | ||
|
|
855fd4f0b7 | ||
|
|
807839929d | ||
|
|
870955fee1 | ||
|
|
e0cea929ea | ||
|
|
315f4c35f0 | ||
|
|
d961ea22a6 | ||
|
|
5c0c07c78f | ||
|
|
bba93a0fb7 | ||
|
|
5683df2fc0 | ||
|
|
b5cb9ce67e | ||
|
|
06a32dc895 | ||
|
|
dff12a8a3a | ||
|
|
dc3f07ee84 | ||
|
|
1aef49ee11 | ||
|
|
ee3159b00e | ||
|
|
86d2c307f1 | ||
|
|
7823a217b4 | ||
|
|
2004df8337 | ||
|
|
13bc2d0340 | ||
|
|
edbc850346 | ||
|
|
901d3c85ca | ||
|
|
abbe83f3c2 | ||
|
|
bb3a04a9c8 | ||
|
|
bac13e8b71 | ||
|
|
3871681de3 | ||
|
|
ae6f2b6df6 | ||
|
|
f59bbc9981 | ||
|
|
eac0c84e11 | ||
|
|
f814cc443d | ||
|
|
262466303b | ||
|
|
3b4cc2c5f2 | ||
|
|
023d3fbf6f | ||
|
|
fe01f290bc | ||
|
|
5805ac9f7f | ||
|
|
4e2f38a343 | ||
|
|
572c924e5c | ||
|
|
e90353e550 | ||
|
|
f8ae1b8c49 | ||
|
|
186d995919 | ||
|
|
70584aff9d | ||
|
|
dcdc63785a | ||
|
|
0e7bfa65de | ||
|
|
9427340ab7 | ||
|
|
63af5bae8a | ||
|
|
9232f1fa40 | ||
|
|
15bdb551f4 | ||
|
|
2cda2b53ed | ||
|
|
028c9ea0b5 | ||
|
|
315b51e7ca | ||
|
|
0185b3b145 | ||
|
|
afaad49879 | ||
|
|
4b2b45979b | ||
|
|
66e40edd0e | ||
|
|
3d5168885f | ||
|
|
6eee2c2342 | ||
|
|
11ec27147a | ||
|
|
a522a02ba2 | ||
|
|
5ff4d35a30 | ||
|
|
4c5546bf52 | ||
|
|
ab37a46e83 | ||
|
|
0b3635b5c5 | ||
|
|
2a338d9a83 | ||
|
|
7031a4c26c | ||
|
|
2c5ca97476 | ||
|
|
fc0c8f6bb1 | ||
|
|
643547704e | ||
|
|
4717b63775 | ||
|
|
4af148f480 | ||
|
|
a9c59693ee | ||
|
|
9b3ac159c1 | ||
|
|
c03c98157f | ||
|
|
74149b761f | ||
|
|
44cfa2d8dc | ||
|
|
b0fb00d597 | ||
|
|
af3c1dc039 | ||
|
|
1c94b5d5f0 | ||
|
|
fbb00c0f85 | ||
|
|
4a72e63d1c | ||
|
|
ce94e0ba4d | ||
|
|
e2c836794b | ||
|
|
05e424f805 | ||
|
|
bf30819a4a | ||
|
|
52e9d30b46 | ||
|
|
1fa2d55e1d | ||
|
|
4d0ee652d8 | ||
|
|
ff215bc9aa | ||
|
|
e1cadc878a | ||
|
|
57d9d8ddb9 | ||
|
|
f76b1a5363 | ||
|
|
9b579be2be | ||
|
|
9d43465eab | ||
|
|
fc52870431 | ||
|
|
c466ea100a | ||
|
|
4054369611 | ||
|
|
11106937a3 | ||
|
|
fdddf901f3 | ||
|
|
2e30c04238 | ||
|
|
bd838094cd | ||
|
|
6f22b74154 | ||
|
|
e71525db0e | ||
|
|
d7c1516ec2 | ||
|
|
ff91a5dad9 | ||
|
|
d76679c2b6 | ||
|
|
d7cb88f0a4 | ||
|
|
8a3eb41314 | ||
|
|
e2f9aac1c9 | ||
|
|
08c7396404 | ||
|
|
69cbdbd20e | ||
|
|
005f26ba7c | ||
|
|
a1dc0c8104 | ||
|
|
75435b8fe0 | ||
|
|
6d7385788e | ||
|
|
726d9d410f | ||
|
|
ee2a61bb61 | ||
|
|
40748d6e42 | ||
|
|
02225ad0b8 | ||
|
|
3c4703ad85 | ||
|
|
6762f35ade | ||
|
|
5135afcf8f | ||
|
|
4aae82e0cc | ||
|
|
ea95c6de79 | ||
|
|
4a67e963ed | ||
|
|
720f177d65 | ||
|
|
2b4a043a92 | ||
|
|
77b20bc562 | ||
|
|
063449448a | ||
|
|
ba246e99e8 |
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@@ -36,13 +36,12 @@ jobs:
|
|||||||
# 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory
|
# 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: v2rayN
|
name: v2rayN
|
||||||
path:
|
path: |
|
||||||
.\v2rayN\v2rayN.zip
|
.\v2rayN\v2rayN.zip
|
||||||
|
|
||||||
|
|
||||||
# - name: Release
|
# - name: Release
|
||||||
# uses: softprops/action-gh-release@v1
|
# uses: softprops/action-gh-release@v1
|
||||||
# env:
|
# env:
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core)
|
|||||||
- Run v2rayN.exe
|
- Run v2rayN.exe
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
- [Microsoft .NET 6.0 Desktop Runtime ](https://download.visualstudio.microsoft.com/download/pr/513d13b7-b456-45af-828b-b7b7981ff462/edf44a743b78f8b54a2cec97ce888346/windowsdesktop-runtime-6.0.15-win-x64.exe)
|
- (6.35 and above)[Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
|
||||||
|
- (6.33 and below)[Microsoft .NET 6.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
|
||||||
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.25.1" />
|
<PackageReference Include="Google.Protobuf" Version="3.27.3" />
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.60.0" />
|
<PackageReference Include="Grpc.Net.Client" Version="2.65.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.60.0">
|
<PackageReference Include="Grpc.Tools" Version="2.65.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<Application
|
<Application
|
||||||
x:Class="v2rayN.App"
|
x:Class="v2rayN.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:conv="clr-namespace:v2rayN.Converters"
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
ShutdownMode="OnExplicitShutdown"
|
ShutdownMode="OnExplicitShutdown"
|
||||||
StartupUri="Views/MainWindow.xaml">
|
StartupUri="Views/MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
@@ -13,13 +13,14 @@
|
|||||||
BaseTheme="Light"
|
BaseTheme="Light"
|
||||||
PrimaryColor="Blue"
|
PrimaryColor="Blue"
|
||||||
SecondaryColor="Lime" />
|
SecondaryColor="Lime" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign2.Defaults.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<system:Double x:Key="MenuItemHeight">26</system:Double>
|
<system:Double x:Key="MenuItemHeight">26</system:Double>
|
||||||
<system:Double x:Key="StdFontSize">12</system:Double>
|
<system:Double x:Key="StdFontSize">12</system:Double>
|
||||||
<system:Double x:Key="StdFontSize1">13</system:Double>
|
<system:Double x:Key="StdFontSize1">13</system:Double>
|
||||||
<system:Double x:Key="StdFontSize2">14</system:Double>
|
<system:Double x:Key="StdFontSize2">14</system:Double>
|
||||||
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
|
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
|
||||||
|
<system:Double x:Key="StdFontSize-1">11</system:Double>
|
||||||
|
|
||||||
<conv:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
<conv:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||||
<Thickness
|
<Thickness
|
||||||
@@ -61,23 +62,26 @@
|
|||||||
</Style>
|
</Style>
|
||||||
<Style TargetType="{x:Type TextElement}">
|
<Style TargetType="{x:Type TextElement}">
|
||||||
<Setter Property="FontWeight" Value="Regular" />
|
<Setter Property="FontWeight" Value="Regular" />
|
||||||
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
|
|
||||||
</Style>
|
</Style>
|
||||||
<Style TargetType="{x:Type TextBlock}">
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="FontWeight" Value="Regular" />
|
<Setter Property="FontWeight" Value="Regular" />
|
||||||
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
|
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}">
|
<Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}">
|
||||||
<Setter Property="Height" Value="20" />
|
<Setter Property="Margin" Value="2" />
|
||||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
<Setter Property="Template">
|
||||||
<Style.Triggers>
|
<Setter.Value>
|
||||||
<Trigger Property="IsSelected" Value="true">
|
<ControlTemplate TargetType="ListViewItem">
|
||||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
|
<materialDesign:Card Name="_Card" SnapsToDevicePixels="true">
|
||||||
</Trigger>
|
<ContentPresenter />
|
||||||
<Trigger Property="IsMouseOver" Value="true">
|
</materialDesign:Card>
|
||||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueMidBrush}" />
|
<ControlTemplate.Triggers>
|
||||||
</Trigger>
|
<Trigger Property="IsSelected" Value="true">
|
||||||
</Style.Triggers>
|
<Setter TargetName="_Card" Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="GridViewColumnHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
|
<Style x:Key="GridViewColumnHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
|
||||||
@@ -156,6 +160,27 @@
|
|||||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||||
<Setter Property="Padding" Value="{StaticResource OutlinedTextBoxDefaultPadding}" />
|
<Setter Property="Padding" Value="{StaticResource OutlinedTextBoxDefaultPadding}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style x:Key="ListItemChip" TargetType="{x:Type materialDesign:Chip}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
|
||||||
|
</Style>
|
||||||
|
<Style
|
||||||
|
x:Key="ListItemTitle"
|
||||||
|
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||||
|
TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
|
||||||
|
</Style>
|
||||||
|
<Style
|
||||||
|
x:Key="ListItemSubTitle"
|
||||||
|
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||||
|
TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||||
|
</Style>
|
||||||
|
<Style
|
||||||
|
x:Key="ListItemSubTitle2"
|
||||||
|
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||||
|
TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize-1}" />
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using System.Windows;
|
using System.Diagnostics;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using v2rayN.Handler;
|
using v2rayN.Handler;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
using v2rayN.Tool;
|
|
||||||
|
|
||||||
namespace v2rayN
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
@@ -28,24 +28,22 @@ namespace v2rayN
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
{
|
{
|
||||||
Global.ExePathKey = Utils.GetMD5(Utils.GetExePath());
|
var exePathKey = Utils.GetMD5(Utils.GetExePath());
|
||||||
|
|
||||||
var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs);
|
var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs);
|
||||||
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Global.ExePathKey, out bool bCreatedNew);
|
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
|
||||||
if (!rebootas && !bCreatedNew)
|
if (!rebootas && !bCreatedNew)
|
||||||
{
|
{
|
||||||
ProgramStarted.Set();
|
ProgramStarted.Set();
|
||||||
Current.Shutdown();
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.ProcessJob = new Job();
|
|
||||||
|
|
||||||
Logging.Setup();
|
Logging.Setup();
|
||||||
Init();
|
Init();
|
||||||
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
||||||
Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
||||||
|
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
Logging.ClearLogs();
|
Logging.ClearLogs();
|
||||||
|
|
||||||
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
||||||
@@ -57,20 +55,21 @@ namespace v2rayN
|
|||||||
{
|
{
|
||||||
if (ConfigHandler.LoadConfig(ref _config) != 0)
|
if (ConfigHandler.LoadConfig(ref _config) != 0)
|
||||||
{
|
{
|
||||||
UI.ShowWarning($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用");
|
UI.Show($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用");
|
||||||
Application.Current.Shutdown();
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64)
|
|
||||||
//{
|
//Under Win10
|
||||||
// _config.guiItem.enableStatistics = false;
|
if (Environment.OSVersion.Version.Major < 10)
|
||||||
//}
|
{
|
||||||
|
Environment.SetEnvironmentVariable("DOTNET_EnableWriteXorExecute", "0", EnvironmentVariableTarget.User);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("App_DispatcherUnhandledException", e.Exception);
|
Logging.SaveLog("App_DispatcherUnhandledException", e.Exception);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,13 +77,20 @@ namespace v2rayN
|
|||||||
{
|
{
|
||||||
if (e.ExceptionObject != null)
|
if (e.ExceptionObject != null)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
|
Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
|
Logging.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnExit(ExitEventArgs e)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("OnExit");
|
||||||
|
base.OnExit(e);
|
||||||
|
Process.GetCurrentProcess().Kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
internal class DownloaderHelper
|
internal class DownloaderHelper
|
||||||
{
|
{
|
||||||
@@ -11,7 +11,7 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
|
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
@@ -120,11 +120,11 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileName));
|
throw new ArgumentNullException(nameof(fileName));
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
public static class FileManager
|
public static class FileManager
|
||||||
{
|
{
|
||||||
@@ -15,12 +15,12 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UncompressFile(string fileName, byte[] content)
|
public static void UncompressedFile(string fileName, byte[] content)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -30,7 +30,7 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,13 +75,13 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -21,26 +22,57 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
|
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
|
||||||
|
|
||||||
|
public async Task<string?> TryGetAsync(string url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(url))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpResponseMessage response = await httpClient.GetAsync(url);
|
||||||
|
return await response.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<string?> GetAsync(string url)
|
public async Task<string?> GetAsync(string url)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url)) return null;
|
if (Utils.IsNullOrEmpty(url)) return null;
|
||||||
return await httpClient.GetStringAsync(url);
|
return await httpClient.GetStringAsync(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
|
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(url)) return null;
|
if (Utils.IsNullOrEmpty(url)) return null;
|
||||||
return await client.GetStringAsync(url, token);
|
return await client.GetStringAsync(url, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PutAsync(string url, Dictionary<string, string> headers)
|
public async Task PutAsync(string url, Dictionary<string, string> headers)
|
||||||
{
|
{
|
||||||
var jsonContent = Utils.ToJson(headers);
|
var jsonContent = JsonUtils.Serialize(headers);
|
||||||
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
|
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
|
||||||
|
|
||||||
var result = await httpClient.PutAsync(url, content);
|
var result = await httpClient.PutAsync(url, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task PatchAsync(string url, Dictionary<string, string> headers)
|
||||||
|
{
|
||||||
|
var myContent = JsonUtils.Serialize(headers);
|
||||||
|
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
|
||||||
|
var byteContent = new ByteArrayContent(buffer);
|
||||||
|
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
|
|
||||||
|
await httpClient.PatchAsync(url, byteContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAsync(string url)
|
||||||
|
{
|
||||||
|
await httpClient.DeleteAsync(url);
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
|
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(url);
|
ArgumentNullException.ThrowIfNull(url);
|
||||||
@@ -76,19 +108,19 @@ namespace v2rayN.Base
|
|||||||
//if (progressPercentage != percent && percent % 10 == 0)
|
//if (progressPercentage != percent && percent % 10 == 0)
|
||||||
{
|
{
|
||||||
progressPercentage = percent;
|
progressPercentage = percent;
|
||||||
progress!.Report(percent);
|
progress?.Report(percent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (canReportProgress)
|
if (canReportProgress)
|
||||||
{
|
{
|
||||||
progress!.Report(101);
|
progress?.Report(101);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
|
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ namespace v2rayN
|
|||||||
|
|
||||||
if (!succ)
|
if (!succ)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error());
|
Logging.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error());
|
||||||
}
|
}
|
||||||
|
|
||||||
return succ;
|
return succ;
|
||||||
134
v2rayN/v2rayN/Common/JsonUtils.cs
Normal file
134
v2rayN/v2rayN/Common/JsonUtils.cs
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace v2rayN
|
||||||
|
{
|
||||||
|
internal class JsonUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DeepCopy
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T DeepCopy<T>(T obj)
|
||||||
|
{
|
||||||
|
return Deserialize<T>(Serialize(obj, false))!;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deserialize to object
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="strJson"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T? Deserialize<T>(string? strJson)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(strJson))
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
return JsonSerializer.Deserialize<T>(strJson);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// parse
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="strJson"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static JsonNode? ParseJson(string strJson)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(strJson))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JsonNode.Parse(strJson);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//SaveLog(ex.Message, ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serialize Object to Json string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <param name="indented"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Serialize(object? obj, bool indented = true)
|
||||||
|
{
|
||||||
|
string result = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = indented ? true : false,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SerializeToNode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save as json file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <param name="filePath"></param>
|
||||||
|
/// <param name="nullValue"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int ToFile(object? obj, string? filePath, bool nullValue = true)
|
||||||
|
{
|
||||||
|
if (filePath is null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using FileStream file = File.Create(filePath);
|
||||||
|
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
|
||||||
|
JsonSerializer.Serialize(file, obj, options);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ using NLog.Config;
|
|||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
public class Logging
|
public class Logging
|
||||||
{
|
{
|
||||||
@@ -51,5 +51,28 @@ namespace v2rayN.Tool
|
|||||||
catch { }
|
catch { }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SaveLog(string strContent)
|
||||||
|
{
|
||||||
|
if (LogManager.IsLoggingEnabled())
|
||||||
|
{
|
||||||
|
var logger = LogManager.GetLogger("Log1");
|
||||||
|
logger.Info(strContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveLog(string strTitle, Exception ex)
|
||||||
|
{
|
||||||
|
if (LogManager.IsLoggingEnabled())
|
||||||
|
{
|
||||||
|
var logger = LogManager.GetLogger("Log2");
|
||||||
|
logger.Debug($"{strTitle},{ex.Message}");
|
||||||
|
logger.Debug(ex.StackTrace);
|
||||||
|
if (ex?.InnerException != null)
|
||||||
|
{
|
||||||
|
logger.Error(ex.InnerException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,38 @@
|
|||||||
using Microsoft.Win32;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices;
|
using static v2rayN.Common.ProxySetting.InternetConnectionOption;
|
||||||
using static v2rayN.Handler.ProxySetting.InternetConnectionOption;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Common
|
||||||
{
|
{
|
||||||
internal class ProxySetting
|
internal class ProxySetting
|
||||||
{
|
{
|
||||||
|
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
|
||||||
|
|
||||||
|
private static bool SetProxyFallback(string? strProxy, string? exceptions, int type)
|
||||||
|
{
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyEnable", 0);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
|
||||||
|
}
|
||||||
|
if (type == 2)
|
||||||
|
{
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyEnable", 1);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
|
||||||
|
}
|
||||||
|
else if (type == 4)
|
||||||
|
{
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyEnable", 0);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
// set to use no proxy
|
// set to use no proxy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -27,18 +54,27 @@ namespace v2rayN.Handler
|
|||||||
/// PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
/// PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
||||||
/// <returns>true: one of connnection is successfully updated proxy settings</returns>
|
/// <returns>true: one of connection is successfully updated proxy settings</returns>
|
||||||
public static bool SetProxy(string? strProxy, string? exceptions, int type)
|
public static bool SetProxy(string? strProxy, string? exceptions, int type)
|
||||||
{
|
{
|
||||||
// set proxy for LAN
|
try
|
||||||
bool result = SetConnectionProxy(null, strProxy, exceptions, type);
|
|
||||||
// set proxy for dial up connections
|
|
||||||
var connections = EnumerateRasEntries();
|
|
||||||
foreach (var connection in connections)
|
|
||||||
{
|
{
|
||||||
result |= SetConnectionProxy(connection, strProxy, exceptions, type);
|
// set proxy for LAN
|
||||||
|
bool result = SetConnectionProxy(null, strProxy, exceptions, type);
|
||||||
|
// set proxy for dial up connections
|
||||||
|
var connections = EnumerateRasEntries();
|
||||||
|
foreach (var connection in connections)
|
||||||
|
{
|
||||||
|
result |= SetConnectionProxy(connection, strProxy, exceptions, type);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SetProxyFallback(strProxy, exceptions, type);
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
|
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
|
||||||
@@ -68,7 +104,7 @@ namespace v2rayN.Handler
|
|||||||
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
|
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//int optionCount = Utils.IsNullOrEmpty(strProxy) ? 1 : (Utils.IsNullOrEmpty(exceptions) ? 2 : 3);
|
//int optionCount = Utile.IsNullOrEmpty(strProxy) ? 1 : (Utile.IsNullOrEmpty(exceptions) ? 2 : 3);
|
||||||
InternetConnectionOption[] options = new InternetConnectionOption[optionCount];
|
InternetConnectionOption[] options = new InternetConnectionOption[optionCount];
|
||||||
// USE a proxy server ...
|
// USE a proxy server ...
|
||||||
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
||||||
@@ -95,25 +131,25 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
list.szConnection = IntPtr.Zero;
|
list.szConnection = nint.Zero;
|
||||||
}
|
}
|
||||||
list.dwOptionCount = options.Length;
|
list.dwOptionCount = options.Length;
|
||||||
list.dwOptionError = 0;
|
list.dwOptionError = 0;
|
||||||
|
|
||||||
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
||||||
// make a pointer out of all that ...
|
// make a pointer out of all that ...
|
||||||
IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
nint optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
||||||
// copy the array over into that spot in memory ...
|
// copy the array over into that spot in memory ...
|
||||||
for (int i = 0; i < options.Length; ++i)
|
for (int i = 0; i < options.Length; ++i)
|
||||||
{
|
{
|
||||||
if (Environment.Is64BitOperatingSystem)
|
if (Environment.Is64BitOperatingSystem)
|
||||||
{
|
{
|
||||||
IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize));
|
nint opt = new(optionsPtr.ToInt64() + i * optSize);
|
||||||
Marshal.StructureToPtr(options[i], opt, false);
|
Marshal.StructureToPtr(options[i], opt, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize));
|
nint opt = new(optionsPtr.ToInt32() + i * optSize);
|
||||||
Marshal.StructureToPtr(options[i], opt, false);
|
Marshal.StructureToPtr(options[i], opt, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,11 +157,11 @@ namespace v2rayN.Handler
|
|||||||
list.options = optionsPtr;
|
list.options = optionsPtr;
|
||||||
|
|
||||||
// and then make a pointer out of the whole list
|
// and then make a pointer out of the whole list
|
||||||
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
|
nint ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
|
||||||
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
||||||
|
|
||||||
// and finally, call the API method!
|
// and finally, call the API method!
|
||||||
bool isSuccess = NativeMethods.InternetSetOption(IntPtr.Zero,
|
bool isSuccess = NativeMethods.InternetSetOption(nint.Zero,
|
||||||
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
||||||
ipcoListPtr, list.dwSize);
|
ipcoListPtr, list.dwSize);
|
||||||
int returnvalue = 0; // ERROR_SUCCESS
|
int returnvalue = 0; // ERROR_SUCCESS
|
||||||
@@ -136,12 +172,12 @@ namespace v2rayN.Handler
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Notify the system that the registry settings have been changed and cause them to be refreshed
|
// Notify the system that the registry settings have been changed and cause them to be refreshed
|
||||||
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
|
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
|
||||||
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
|
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FREE the data ASAP
|
// FREE the data ASAP
|
||||||
if (list.szConnection != IntPtr.Zero) Marshal.FreeHGlobal(list.szConnection); // release mem 3
|
if (list.szConnection != nint.Zero) Marshal.FreeHGlobal(list.szConnection); // release mem 3
|
||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
|
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
|
||||||
@@ -205,12 +241,12 @@ namespace v2rayN.Handler
|
|||||||
public struct InternetPerConnOptionList
|
public struct InternetPerConnOptionList
|
||||||
{
|
{
|
||||||
public int dwSize; // size of the INTERNET_PER_CONN_OPTION_LIST struct
|
public int dwSize; // size of the INTERNET_PER_CONN_OPTION_LIST struct
|
||||||
public IntPtr szConnection; // connection name to set/query options
|
public nint szConnection; // connection name to set/query options
|
||||||
public int dwOptionCount; // number of options to set/query
|
public int dwOptionCount; // number of options to set/query
|
||||||
public int dwOptionError; // on error, which option failed
|
public int dwOptionError; // on error, which option failed
|
||||||
|
|
||||||
//[MarshalAs(UnmanagedType.)]
|
//[MarshalAs(UnmanagedType.)]
|
||||||
public IntPtr options;
|
public nint options;
|
||||||
};
|
};
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||||
@@ -237,7 +273,7 @@ namespace v2rayN.Handler
|
|||||||
public int m_Int;
|
public int m_Int;
|
||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public IntPtr m_StringPtr;
|
public nint m_StringPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||||
@@ -309,7 +345,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption, IntPtr lpBuffer, int dwBufferLength);
|
public static extern bool InternetSetOption(nint hInternet, InternetOption dwOption, nint lpBuffer, int dwBufferLength);
|
||||||
|
|
||||||
[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
|
[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
|
||||||
public static extern uint RasEnumEntries(
|
public static extern uint RasEnumEntries(
|
||||||
@@ -320,27 +356,5 @@ namespace v2rayN.Handler
|
|||||||
ref int lpcEntries // Number of entries written to the buffer
|
ref int lpcEntries // Number of entries written to the buffer
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断是否使用代理
|
|
||||||
public static bool UsedProxy()
|
|
||||||
{
|
|
||||||
using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
|
||||||
if (rk?.GetValue("ProxyEnable")?.ToString() == "1")
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//获得代理的IP和端口
|
|
||||||
public static string? GetProxyProxyServer()
|
|
||||||
{
|
|
||||||
using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
|
||||||
string ProxyServer = rk.GetValue("ProxyServer").ToString();
|
|
||||||
return ProxyServer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
104
v2rayN/v2rayN/Common/QRCodeHelper.cs
Normal file
104
v2rayN/v2rayN/Common/QRCodeHelper.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using QRCoder;
|
||||||
|
using QRCoder.Xaml;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using ZXing;
|
||||||
|
using ZXing.Common;
|
||||||
|
using ZXing.QrCode;
|
||||||
|
using ZXing.Windows.Compatibility;
|
||||||
|
|
||||||
|
namespace v2rayN
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 含有QR码的描述类和包装编码和渲染
|
||||||
|
/// </summary>
|
||||||
|
public class QRCodeHelper
|
||||||
|
{
|
||||||
|
public static DrawingImage? GetQRCode(string? strContent)
|
||||||
|
{
|
||||||
|
if (strContent is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QRCodeGenerator qrGenerator = new();
|
||||||
|
QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H);
|
||||||
|
XamlQRCode qrCode = new(qrCodeData);
|
||||||
|
DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40);
|
||||||
|
return qrCodeAsXaml;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ScanScreen(float dpiX, float dpiY)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var left = (int)(SystemParameters.WorkArea.Left);
|
||||||
|
var top = (int)(SystemParameters.WorkArea.Top);
|
||||||
|
var width = (int)(SystemParameters.WorkArea.Width / dpiX);
|
||||||
|
var height = (int)(SystemParameters.WorkArea.Height / dpiY);
|
||||||
|
|
||||||
|
using Bitmap fullImage = new Bitmap(width, height);
|
||||||
|
using (Graphics g = Graphics.FromImage(fullImage))
|
||||||
|
{
|
||||||
|
g.CopyFromScreen(left, top, 0, 0, fullImage.Size, CopyPixelOperation.SourceCopy);
|
||||||
|
}
|
||||||
|
int maxTry = 10;
|
||||||
|
for (int i = 0; i < maxTry; i++)
|
||||||
|
{
|
||||||
|
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
|
||||||
|
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
|
||||||
|
Rectangle cropRect = new(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
|
||||||
|
Bitmap target = new(width, height);
|
||||||
|
|
||||||
|
double imageScale = (double)width / (double)cropRect.Width;
|
||||||
|
using (Graphics g = Graphics.FromImage(target))
|
||||||
|
{
|
||||||
|
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
|
||||||
|
cropRect,
|
||||||
|
GraphicsUnit.Pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapLuminanceSource source = new(target);
|
||||||
|
QRCodeReader reader = new();
|
||||||
|
|
||||||
|
BinaryBitmap bitmap = new(new HybridBinarizer(source));
|
||||||
|
var result = reader.decode(bitmap);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return result.Text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BinaryBitmap bitmap2 = new(new HybridBinarizer(source.invert()));
|
||||||
|
var result2 = reader.decode(bitmap2);
|
||||||
|
if (result2 != null)
|
||||||
|
{
|
||||||
|
return result2.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tuple<float, float> GetDpiXY(Window window)
|
||||||
|
{
|
||||||
|
IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle();
|
||||||
|
Graphics g = Graphics.FromHwnd(hWnd);
|
||||||
|
|
||||||
|
return new(96 / g.DpiX, 96 / g.DpiY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
public static class QueryableExtension
|
public static class QueryableExtension
|
||||||
{
|
{
|
||||||
@@ -29,22 +29,22 @@ namespace v2rayN.Tool
|
|||||||
|
|
||||||
public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
||||||
{//public
|
{//public
|
||||||
return query.OrderBy(_GetLamba<T, TProp>(memberProperty));
|
return query.OrderBy(_GetLambda<T, TProp>(memberProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
||||||
{//public
|
{//public
|
||||||
return query.OrderByDescending(_GetLamba<T, TProp>(memberProperty));
|
return query.OrderByDescending(_GetLambda<T, TProp>(memberProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Expression<Func<T, TProp>> _GetLamba<T, TProp>(PropertyInfo memberProperty)
|
private static Expression<Func<T, TProp>> _GetLambda<T, TProp>(PropertyInfo memberProperty)
|
||||||
{
|
{
|
||||||
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
|
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
|
||||||
|
|
||||||
var thisArg = Expression.Parameter(typeof(T));
|
var thisArg = Expression.Parameter(typeof(T));
|
||||||
var lamba = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg);
|
var lambda = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg);
|
||||||
|
|
||||||
return lamba;
|
return lambda;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using v2rayN.Base;
|
namespace v2rayN
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
|
||||||
{
|
{
|
||||||
public class SemanticVersion
|
public class SemanticVersion
|
||||||
{
|
{
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
public sealed class SqliteHelper
|
public sealed class SQLiteHelper
|
||||||
{
|
{
|
||||||
private static readonly Lazy<SqliteHelper> _instance = new(() => new());
|
private static readonly Lazy<SQLiteHelper> _instance = new(() => new());
|
||||||
public static SqliteHelper Instance => _instance.Value;
|
public static SQLiteHelper Instance => _instance.Value;
|
||||||
private string _connstr;
|
private string _connstr;
|
||||||
private SQLiteConnection _db;
|
private SQLiteConnection _db;
|
||||||
private SQLiteAsyncConnection _dbAsync;
|
private SQLiteAsyncConnection _dbAsync;
|
||||||
private static readonly object objLock = new();
|
private static readonly object objLock = new();
|
||||||
|
public readonly string _configDB = "guiNDB.db";
|
||||||
|
|
||||||
public SqliteHelper()
|
public SQLiteHelper()
|
||||||
{
|
{
|
||||||
_connstr = Utils.GetConfigPath(Global.ConfigDB);
|
_connstr = Utils.GetConfigPath(_configDB);
|
||||||
_db = new SQLiteConnection(_connstr, false);
|
_db = new SQLiteConnection(_connstr, false);
|
||||||
_dbAsync = new SQLiteAsyncConnection(_connstr, false);
|
_dbAsync = new SQLiteAsyncConnection(_connstr, false);
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,7 @@ namespace v2rayN.Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> Replacesync(object model)
|
public async Task<int> ReplaceAsync(object model)
|
||||||
{
|
{
|
||||||
return await _dbAsync.InsertOrReplaceAsync(model);
|
return await _dbAsync.InsertOrReplaceAsync(model);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
internal static class StringEx
|
internal static class StringEx
|
||||||
{
|
{
|
||||||
@@ -80,5 +80,15 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
return char.ToUpper(value[0]) + value.Substring(1);
|
return char.ToUpper(value[0]) + value.Substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string AppendQuotes(this string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"\"{value}\"";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Windows;
|
using Microsoft.Win32;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
namespace v2rayN
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
@@ -11,14 +12,28 @@ namespace v2rayN
|
|||||||
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
|
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ShowWarning(string msg)
|
|
||||||
{
|
|
||||||
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MessageBoxResult ShowYesNo(string msg)
|
public static MessageBoxResult ShowYesNo(string msg)
|
||||||
{
|
{
|
||||||
return MessageBox.Show(msg, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);
|
return MessageBox.Show(msg, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool? OpenFileDialog(out string fileName, string filter)
|
||||||
|
{
|
||||||
|
fileName = string.Empty;
|
||||||
|
|
||||||
|
var fileDialog = new OpenFileDialog
|
||||||
|
{
|
||||||
|
Multiselect = false,
|
||||||
|
Filter = filter
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fileDialog.ShowDialog() != true)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fileName = fileDialog.FileName;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
58
v2rayN/v2rayN/Common/YamlUtils.cs
Normal file
58
v2rayN/v2rayN/Common/YamlUtils.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using YamlDotNet.Serialization;
|
||||||
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
|
namespace v2rayN.Common
|
||||||
|
{
|
||||||
|
internal class YamlUtils
|
||||||
|
{
|
||||||
|
#region YAML
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 反序列化成对象
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T FromYaml<T>(string str)
|
||||||
|
{
|
||||||
|
var deserializer = new DeserializerBuilder()
|
||||||
|
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||||
|
.Build();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
T obj = deserializer.Deserialize<T>(str);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("FromYaml", ex);
|
||||||
|
return deserializer.Deserialize<T>("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ToYaml(Object obj)
|
||||||
|
{
|
||||||
|
var serializer = new SerializerBuilder()
|
||||||
|
.WithNamingConvention(HyphenatedNamingConvention.Instance)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
string result = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = serializer.Serialize(obj);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion YAML
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ namespace v2rayN.Converters
|
|||||||
|
|
||||||
if (delay <= 0)
|
if (delay <= 0)
|
||||||
return new SolidColorBrush(Colors.Red);
|
return new SolidColorBrush(Colors.Red);
|
||||||
if (delay <= 200)
|
if (delay <= 500)
|
||||||
return new SolidColorBrush(Colors.Green);
|
return new SolidColorBrush(Colors.Green);
|
||||||
else
|
else
|
||||||
return new SolidColorBrush(Colors.IndianRed);
|
return new SolidColorBrush(Colors.IndianRed);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace v2rayN.Converters
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily;
|
var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily;
|
||||||
if (!string.IsNullOrEmpty(fontFamily))
|
if (!Utils.IsNullOrEmpty(fontFamily))
|
||||||
{
|
{
|
||||||
var fontPath = Utils.GetFontsPath();
|
var fontPath = Utils.GetFontsPath();
|
||||||
MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");
|
MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Enums
|
||||||
{
|
{
|
||||||
public enum EConfigType
|
public enum EConfigType
|
||||||
{
|
{
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
VLESS = 5,
|
VLESS = 5,
|
||||||
Trojan = 6,
|
Trojan = 6,
|
||||||
Hysteria2 = 7,
|
Hysteria2 = 7,
|
||||||
Tuic = 8
|
Tuic = 8,
|
||||||
|
Wireguard = 9,
|
||||||
|
Http = 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Enums
|
||||||
{
|
{
|
||||||
public enum ECoreType
|
public enum ECoreType
|
||||||
{
|
{
|
||||||
9
v2rayN/v2rayN/Enums/EGirdOrientation.cs
Normal file
9
v2rayN/v2rayN/Enums/EGirdOrientation.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace v2rayN.Enums
|
||||||
|
{
|
||||||
|
public enum EGirdOrientation
|
||||||
|
{
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
Tab,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Enums
|
||||||
{
|
{
|
||||||
public enum EGlobalHotkey
|
public enum EGlobalHotkey
|
||||||
{
|
{
|
||||||
14
v2rayN/v2rayN/Enums/EInboundProtocol.cs
Normal file
14
v2rayN/v2rayN/Enums/EInboundProtocol.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace v2rayN.Enums
|
||||||
|
{
|
||||||
|
public enum EInboundProtocol
|
||||||
|
{
|
||||||
|
socks = 0,
|
||||||
|
http,
|
||||||
|
socks2,
|
||||||
|
http2,
|
||||||
|
pac,
|
||||||
|
api,
|
||||||
|
api2,
|
||||||
|
speedtest = 21
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Enums
|
||||||
{
|
{
|
||||||
public enum EMove
|
public enum EMove
|
||||||
{
|
{
|
||||||
10
v2rayN/v2rayN/Enums/ERuleMode.cs
Normal file
10
v2rayN/v2rayN/Enums/ERuleMode.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace v2rayN.Enums
|
||||||
|
{
|
||||||
|
public enum ERuleMode
|
||||||
|
{
|
||||||
|
Rule = 0,
|
||||||
|
Global = 1,
|
||||||
|
Direct = 2,
|
||||||
|
Unchanged = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Enums
|
||||||
{
|
{
|
||||||
public enum EServerColName
|
public enum EServerColName
|
||||||
{
|
{
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
remarks,
|
remarks,
|
||||||
address,
|
address,
|
||||||
port,
|
port,
|
||||||
security,
|
|
||||||
network,
|
network,
|
||||||
streamSecurity,
|
streamSecurity,
|
||||||
subRemarks,
|
subRemarks,
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Enums
|
||||||
{
|
{
|
||||||
public enum ESpeedActionType
|
public enum ESpeedActionType
|
||||||
{
|
{
|
||||||
Ping,
|
|
||||||
Tcping,
|
Tcping,
|
||||||
Realping,
|
Realping,
|
||||||
Speedtest,
|
Speedtest,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Enums
|
||||||
{
|
{
|
||||||
public enum ESysProxyType
|
public enum ESysProxyType
|
||||||
{
|
{
|
||||||
15
v2rayN/v2rayN/Enums/ETransport.cs
Normal file
15
v2rayN/v2rayN/Enums/ETransport.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace v2rayN.Enums
|
||||||
|
{
|
||||||
|
public enum ETransport
|
||||||
|
{
|
||||||
|
tcp,
|
||||||
|
kcp,
|
||||||
|
ws,
|
||||||
|
httpupgrade,
|
||||||
|
splithttp,
|
||||||
|
h2,
|
||||||
|
http,
|
||||||
|
quic,
|
||||||
|
grpc
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Enums
|
||||||
{
|
{
|
||||||
public enum EViewAction
|
public enum EViewAction
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using v2rayN.Mode;
|
using v2rayN.Enums;
|
||||||
|
|
||||||
namespace v2rayN
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
@@ -8,9 +8,6 @@ namespace v2rayN
|
|||||||
|
|
||||||
public const string GithubUrl = "https://github.com";
|
public const string GithubUrl = "https://github.com";
|
||||||
public const string GithubApiUrl = "https://api.github.com/repos";
|
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||||
public const string V2rayWebsiteUrl = @"https://www.v2fly.org/";
|
|
||||||
public const string AboutUrl = @"https://github.com/2dust/v2rayN";
|
|
||||||
public const string UpdateUrl = AboutUrl + @"/releases";
|
|
||||||
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
|
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
|
||||||
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
|
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
|
||||||
public const string SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/releases";
|
public const string SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/releases";
|
||||||
@@ -23,21 +20,22 @@ namespace v2rayN
|
|||||||
public const string TuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
|
public const string TuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
|
||||||
public const string SingboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
|
public const string SingboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
|
||||||
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
||||||
public const string SingboxGeoUrl = "https://github.com/soffchen/sing-{0}/releases/latest/download/{0}.db";
|
|
||||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
||||||
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
||||||
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
||||||
|
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
||||||
|
|
||||||
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||||
public const string ConfigFileName = "guiNConfig.json";
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
public const string ConfigDB = "guiNDB.db";
|
|
||||||
public const string CoreConfigFileName = "config.json";
|
public const string CoreConfigFileName = "config.json";
|
||||||
public const string CorePreConfigFileName = "configPre.json";
|
public const string CorePreConfigFileName = "configPre.json";
|
||||||
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
||||||
|
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
||||||
|
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
||||||
public const string V2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
public const string V2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
||||||
public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
|
public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
|
||||||
public const string V2raySampleHttprequestFileName = "v2rayN.Sample.SampleHttprequest";
|
public const string V2raySampleHttpRequestFileName = "v2rayN.Sample.SampleHttpRequest";
|
||||||
public const string V2raySampleHttpresponseFileName = "v2rayN.Sample.SampleHttpresponse";
|
public const string V2raySampleHttpResponseFileName = "v2rayN.Sample.SampleHttpResponse";
|
||||||
public const string V2raySampleInbound = "v2rayN.Sample.SampleInbound";
|
public const string V2raySampleInbound = "v2rayN.Sample.SampleInbound";
|
||||||
public const string V2raySampleOutbound = "v2rayN.Sample.SampleOutbound";
|
public const string V2raySampleOutbound = "v2rayN.Sample.SampleOutbound";
|
||||||
public const string SingboxSampleOutbound = "v2rayN.Sample.SingboxSampleOutbound";
|
public const string SingboxSampleOutbound = "v2rayN.Sample.SingboxSampleOutbound";
|
||||||
@@ -47,6 +45,8 @@ namespace v2rayN
|
|||||||
public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
|
public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
|
||||||
public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal";
|
public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal";
|
||||||
public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal";
|
public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal";
|
||||||
|
public const string ClashMixinYaml = "v2rayN.Sample.clash_mixin_yaml";
|
||||||
|
public const string ClashTunYaml = "v2rayN.Sample.clash_tun_yaml";
|
||||||
|
|
||||||
public const string DefaultSecurity = "auto";
|
public const string DefaultSecurity = "auto";
|
||||||
public const string DefaultNetwork = "tcp";
|
public const string DefaultNetwork = "tcp";
|
||||||
@@ -57,28 +57,24 @@ namespace v2rayN
|
|||||||
public const string BlockTag = "block";
|
public const string BlockTag = "block";
|
||||||
public const string StreamSecurity = "tls";
|
public const string StreamSecurity = "tls";
|
||||||
public const string StreamSecurityReality = "reality";
|
public const string StreamSecurityReality = "reality";
|
||||||
public const string InboundSocks = "socks";
|
|
||||||
public const string InboundHttp = "http";
|
|
||||||
public const string InboundSocks2 = "socks2";
|
|
||||||
public const string InboundHttp2 = "http2";
|
|
||||||
public const string Loopback = "127.0.0.1";
|
public const string Loopback = "127.0.0.1";
|
||||||
public const string InboundAPITagName = "api";
|
public const string InboundAPIProtocol = "dokodemo-door";
|
||||||
public const string InboundAPIProtocal = "dokodemo-door";
|
|
||||||
public const string HttpProtocol = "http://";
|
public const string HttpProtocol = "http://";
|
||||||
public const string HttpsProtocol = "https://";
|
public const string HttpsProtocol = "https://";
|
||||||
|
|
||||||
public const string UserEMail = "t@t.tt";
|
public const string UserEMail = "t@t.tt";
|
||||||
public const string MyRegPath = "Software\\v2rayNGUI";
|
|
||||||
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||||
public const string AutoRunName = "v2rayNAutoRun";
|
public const string AutoRunName = "v2rayNAutoRun";
|
||||||
public const string MyRegKeyLanguage = "CurrentLanguage";
|
|
||||||
public const string CustomIconName = "v2rayN.ico";
|
public const string CustomIconName = "v2rayN.ico";
|
||||||
public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
|
public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
|
||||||
public const string RoutingRuleComma = "<COMMA>";
|
public const string RoutingRuleComma = "<COMMA>";
|
||||||
public const string GrpcgunMode = "gun";
|
public const string GrpcGunMode = "gun";
|
||||||
public const string GrpcmultiMode = "multi";
|
public const string GrpcMultiMode = "multi";
|
||||||
public const int MaxPort = 65536;
|
public const int MaxPort = 65536;
|
||||||
public const string CommandClearMsg = "CommandClearMsg";
|
public const string CommandClearMsg = "CommandClearMsg";
|
||||||
|
public const string CommandSendMsgView = "CommandSendMsgView";
|
||||||
|
public const string CommandStopSpeedTest = "CommandStopSpeedTest";
|
||||||
|
public const string CommandRefreshProfiles = "CommandRefreshProfiles";
|
||||||
public const string DelayUnit = "";
|
public const string DelayUnit = "";
|
||||||
public const string SpeedUnit = "";
|
public const string SpeedUnit = "";
|
||||||
public const int MinFontSize = 10;
|
public const int MinFontSize = 10;
|
||||||
@@ -115,11 +111,17 @@ namespace v2rayN
|
|||||||
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
||||||
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
||||||
@"http://cachefly.cachefly.net/50mb.test",
|
@"http://cachefly.cachefly.net/50mb.test",
|
||||||
@"http://cachefly.cachefly.net/100mb.test",
|
|
||||||
@"http://cachefly.cachefly.net/10mb.test"
|
@"http://cachefly.cachefly.net/10mb.test"
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly Dictionary<string, string> UserAgentTxts = new()
|
public static readonly List<string> SpeedPingTestUrls = new() {
|
||||||
|
@"https://www.google.com/generate_204",
|
||||||
|
@"https://www.gstatic.com/generate_204",
|
||||||
|
@"https://www.apple.com/library/test/success.html",
|
||||||
|
@"http://www.msftconnecttest.com/connecttest.txt",
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
||||||
{
|
{
|
||||||
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
|
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
|
||||||
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
|
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
|
||||||
@@ -138,7 +140,8 @@ namespace v2rayN
|
|||||||
{EConfigType.VLESS,"vless://"},
|
{EConfigType.VLESS,"vless://"},
|
||||||
{EConfigType.Trojan,"trojan://"},
|
{EConfigType.Trojan,"trojan://"},
|
||||||
{EConfigType.Hysteria2,"hysteria2://"},
|
{EConfigType.Hysteria2,"hysteria2://"},
|
||||||
{EConfigType.Tuic,"tuic://"}
|
{EConfigType.Tuic,"tuic://"},
|
||||||
|
{EConfigType.Wireguard,"wireguard://"}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
||||||
@@ -146,49 +149,52 @@ namespace v2rayN
|
|||||||
{EConfigType.VMess,"vmess"},
|
{EConfigType.VMess,"vmess"},
|
||||||
{EConfigType.Shadowsocks,"shadowsocks"},
|
{EConfigType.Shadowsocks,"shadowsocks"},
|
||||||
{EConfigType.Socks,"socks"},
|
{EConfigType.Socks,"socks"},
|
||||||
|
{EConfigType.Http,"http"},
|
||||||
{EConfigType.VLESS,"vless"},
|
{EConfigType.VLESS,"vless"},
|
||||||
{EConfigType.Trojan,"trojan"},
|
{EConfigType.Trojan,"trojan"},
|
||||||
{EConfigType.Hysteria2,"hysteria2"},
|
{EConfigType.Hysteria2,"hysteria2"},
|
||||||
{EConfigType.Tuic,"tuic"}
|
{EConfigType.Tuic,"tuic"},
|
||||||
|
{EConfigType.Wireguard,"wireguard"}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> VmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
||||||
public static readonly List<string> SsSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
|
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
|
||||||
public static readonly List<string> SsSecuritysInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
|
public static readonly List<string> SsSecuritiesInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
|
||||||
public static readonly List<string> SsSecuritysInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
||||||
|
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
|
||||||
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
||||||
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
|
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" };
|
||||||
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
||||||
public static readonly List<string> CoreTypes = new() { "v2fly", "SagerNet", "Xray", "sing_box" };
|
public static readonly List<string> CoreTypes = new() { "v2fly", "SagerNet", "Xray", "sing_box" };
|
||||||
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
|
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
|
||||||
public static readonly List<string> DomainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
public static readonly List<string> DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
||||||
public static readonly List<string> DomainStrategys4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
|
public static readonly List<string> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
|
||||||
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" };
|
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" };
|
||||||
public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
|
public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
|
||||||
public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
|
public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
|
||||||
|
|
||||||
public static readonly List<string> AllowInsecures = new() { "true", "false", "" };
|
public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
|
||||||
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
||||||
|
public static readonly List<string> SingboxDomainStrategy4Out = new() { "ipv4_only", "prefer_ipv4", "prefer_ipv6", "ipv6_only", "" };
|
||||||
|
public static readonly List<string> DomainDNSAddress = ["223.5.5.5", "223.6.6.6", "localhost"];
|
||||||
|
public static readonly List<string> SingboxDomainDNSAddress = ["223.5.5.5", "223.6.6.6", "dhcp://auto"];
|
||||||
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
||||||
public static readonly List<string> Alpns = new() { "h2", "http/1.1", "h2,http/1.1", "h3", "" };
|
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2", "h2,http/1.1", "h3,h2,http/1.1", "" };
|
||||||
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
|
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
|
||||||
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
||||||
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
||||||
public static readonly List<string> TunMtus = new() { "9000", "1500" };
|
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
|
||||||
|
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
|
||||||
|
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
|
||||||
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
||||||
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
|
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
|
||||||
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
|
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
|
||||||
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
|
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
|
||||||
|
|
||||||
|
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" };
|
||||||
|
public static readonly List<string> notAllowTestType = new List<string> { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
|
||||||
|
public static readonly List<string> proxyVehicleType = new List<string> { "file", "http" };
|
||||||
|
|
||||||
#endregion const
|
#endregion const
|
||||||
|
|
||||||
#region global variable
|
|
||||||
|
|
||||||
public static int StatePort { get; set; }
|
|
||||||
public static Job ProcessJob { get; set; }
|
|
||||||
public static bool ShowInTaskbar { get; set; }
|
|
||||||
public static string ExePathKey { get; set; }
|
|
||||||
|
|
||||||
#endregion global variable
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
218
v2rayN/v2rayN/Handler/ClashApiHandler.cs
Normal file
218
v2rayN/v2rayN/Handler/ClashApiHandler.cs
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
using v2rayN.Models;
|
||||||
|
using static v2rayN.Models.ClashProxies;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler
|
||||||
|
{
|
||||||
|
public sealed class ClashApiHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
|
||||||
|
public static ClashApiHandler Instance => instance.Value;
|
||||||
|
|
||||||
|
private Dictionary<String, ProxiesItem> _proxies;
|
||||||
|
public Dictionary<string, object> ProfileContent { get; set; }
|
||||||
|
|
||||||
|
public void SetProxies(Dictionary<String, ProxiesItem> proxies)
|
||||||
|
{
|
||||||
|
_proxies = proxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<String, ProxiesItem> GetProxies()
|
||||||
|
{
|
||||||
|
return _proxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetClashProxies(Config config, Action<ClashProxies, ClashProviders> update)
|
||||||
|
{
|
||||||
|
Task.Run(() => GetClashProxiesAsync(config, update));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetClashProxiesAsync(Config config, Action<ClashProxies, ClashProviders> update)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/proxies";
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
var clashProxies = JsonUtils.Deserialize<ClashProxies>(result);
|
||||||
|
|
||||||
|
var url2 = $"{GetApiUrl()}/providers/proxies";
|
||||||
|
var result2 = await HttpClientHelper.Instance.TryGetAsync(url2);
|
||||||
|
var clashProviders = JsonUtils.Deserialize<ClashProviders>(result2);
|
||||||
|
|
||||||
|
if (clashProxies != null || clashProviders != null)
|
||||||
|
{
|
||||||
|
update(clashProxies, clashProviders);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
}
|
||||||
|
update(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> update)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
if (blAll)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
if (GetProxies() != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
}
|
||||||
|
var proxies = GetProxies();
|
||||||
|
if (proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lstProxy = new List<ClashProxyModel>();
|
||||||
|
foreach (KeyValuePair<string, ProxiesItem> kv in proxies)
|
||||||
|
{
|
||||||
|
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lstProxy.Add(new ClashProxyModel()
|
||||||
|
{
|
||||||
|
name = kv.Value.name,
|
||||||
|
type = kv.Value.type.ToLower(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstProxy == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var urlBase = $"{GetApiUrl()}/proxies";
|
||||||
|
urlBase += @"/{0}/delay?timeout=10000&url=" + LazyConfig.Instance.GetConfig().speedTestItem.speedPingTestUrl;
|
||||||
|
|
||||||
|
List<Task> tasks = new List<Task>();
|
||||||
|
foreach (var it in lstProxy)
|
||||||
|
{
|
||||||
|
if (Global.notAllowTestType.Contains(it.type.ToLower()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var name = it.name;
|
||||||
|
var url = string.Format(urlBase, name);
|
||||||
|
tasks.Add(Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
update(it, result);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Task.WaitAll(tasks.ToArray());
|
||||||
|
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
update(null, "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProxiesItem>? GetClashProxyGroups()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileContent = ProfileContent;
|
||||||
|
if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JsonUtils.Deserialize<List<ProxiesItem>>(JsonUtils.Serialize(fileContent["proxy-groups"]));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GetClashProxyGroups", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashSetActiveProxy(string name, string nameNode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/proxies/{name}";
|
||||||
|
Dictionary<string, string> headers = new Dictionary<string, string>();
|
||||||
|
headers.Add("name", nameNode);
|
||||||
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClashConfigUpdate(Dictionary<string, string> headers)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var proxies = GetProxies();
|
||||||
|
if (proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var urlBase = $"{GetApiUrl()}/configs";
|
||||||
|
|
||||||
|
await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashConfigReload(string filePath)
|
||||||
|
{
|
||||||
|
ClashConnectionClose("");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/configs?force=true";
|
||||||
|
Dictionary<string, string> headers = new Dictionary<string, string>();
|
||||||
|
headers.Add("path", filePath);
|
||||||
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetClashConnections(Config config, Action<ClashConnections> update)
|
||||||
|
{
|
||||||
|
Task.Run(() => GetClashConnectionsAsync(config, update));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetClashConnectionsAsync(Config config, Action<ClashConnections> update)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/connections";
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
var clashConnections = JsonUtils.Deserialize<ClashConnections>(result);
|
||||||
|
|
||||||
|
update(clashConnections);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashConnectionClose(string id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/connections/{id}";
|
||||||
|
await HttpClientHelper.Instance.DeleteAsync(url);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetApiUrl()
|
||||||
|
{
|
||||||
|
return $"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
271
v2rayN/v2rayN/Handler/CoreConfig/CoreConfigClash.cs
Normal file
271
v2rayN/v2rayN/Handler/CoreConfig/CoreConfigClash.cs
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
using System.IO;
|
||||||
|
using v2rayN.Common;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.CoreConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Core configuration file processing class
|
||||||
|
/// </summary>
|
||||||
|
internal class CoreConfigClash
|
||||||
|
{
|
||||||
|
private Config _config;
|
||||||
|
|
||||||
|
public CoreConfigClash(Config config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成配置文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node"></param>
|
||||||
|
/// <param name="fileName"></param>
|
||||||
|
/// <param name="msg"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg)
|
||||||
|
{
|
||||||
|
if (node == null || fileName is null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
File.Delete(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
string addressFileName = node.address;
|
||||||
|
if (string.IsNullOrEmpty(addressFileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!File.Exists(addressFileName))
|
||||||
|
{
|
||||||
|
addressFileName = Path.Combine(Utils.GetConfigPath(), addressFileName);
|
||||||
|
}
|
||||||
|
if (!File.Exists(addressFileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration + "1";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
string tagYamlStr1 = "!<str>";
|
||||||
|
string tagYamlStr2 = "__strn__";
|
||||||
|
string tagYamlStr3 = "!!str";
|
||||||
|
var txtFile = File.ReadAllText(addressFileName);
|
||||||
|
txtFile = txtFile.Replace(tagYamlStr1, tagYamlStr2);
|
||||||
|
|
||||||
|
var fileContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
||||||
|
if (fileContent == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedConversionConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//port
|
||||||
|
fileContent["port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
|
||||||
|
//socks-port
|
||||||
|
fileContent["socks-port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
|
//log-level
|
||||||
|
fileContent["log-level"] = GetLogLevel(_config.coreBasicItem.loglevel);
|
||||||
|
|
||||||
|
//external-controller
|
||||||
|
fileContent["external-controller"] = $"{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
||||||
|
//allow-lan
|
||||||
|
if (_config.inbound[0].allowLANConn)
|
||||||
|
{
|
||||||
|
fileContent["allow-lan"] = "true";
|
||||||
|
fileContent["bind-address"] = "*";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileContent["allow-lan"] = "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
//ipv6
|
||||||
|
fileContent["ipv6"] = _config.clashUIItem.enableIPv6;
|
||||||
|
|
||||||
|
//mode
|
||||||
|
if (!fileContent.ContainsKey("mode"))
|
||||||
|
{
|
||||||
|
fileContent["mode"] = ERuleMode.Rule.ToString().ToLower();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_config.clashUIItem.ruleMode != ERuleMode.Unchanged)
|
||||||
|
{
|
||||||
|
fileContent["mode"] = _config.clashUIItem.ruleMode.ToString().ToLower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//enable tun mode
|
||||||
|
if (_config.tunModeItem.enableTun)
|
||||||
|
{
|
||||||
|
string tun = Utils.GetEmbedText(Global.ClashTunYaml);
|
||||||
|
if (!string.IsNullOrEmpty(tun))
|
||||||
|
{
|
||||||
|
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
||||||
|
if (tunContent != null)
|
||||||
|
fileContent["tun"] = tunContent["tun"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mixin
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MixinContent(fileContent, node);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GenerateClientConfigClash-Mixin", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
|
||||||
|
File.WriteAllText(fileName, txtFileNew);
|
||||||
|
//check again
|
||||||
|
if (!File.Exists(fileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration + "2";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClashApiHandler.Instance.ProfileContent = fileContent;
|
||||||
|
|
||||||
|
msg = string.Format(ResUI.SuccessfulConfiguration, $"{node.GetSummary()}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GenerateClientConfigClash", ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
|
||||||
|
{
|
||||||
|
//if (!_config.clashUIItem.enableMixinContent)
|
||||||
|
//{
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
|
||||||
|
|
||||||
|
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
||||||
|
if (mixinContent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (var item in mixinContent)
|
||||||
|
{
|
||||||
|
if (!_config.tunModeItem.enableTun && item.Key == "tun")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Key.StartsWith("prepend-")
|
||||||
|
|| item.Key.StartsWith("append-")
|
||||||
|
|| item.Key.StartsWith("removed-"))
|
||||||
|
{
|
||||||
|
ModifyContentMerge(fileContent, item.Key, item.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileContent[item.Key] = item.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ModifyContentMerge(Dictionary<string, object> fileContent, string key, object value)
|
||||||
|
{
|
||||||
|
bool blPrepend = false;
|
||||||
|
bool blRemoved = false;
|
||||||
|
if (key.StartsWith("prepend-"))
|
||||||
|
{
|
||||||
|
blPrepend = true;
|
||||||
|
key = key.Replace("prepend-", "");
|
||||||
|
}
|
||||||
|
else if (key.StartsWith("append-"))
|
||||||
|
{
|
||||||
|
blPrepend = false;
|
||||||
|
key = key.Replace("append-", "");
|
||||||
|
}
|
||||||
|
else if (key.StartsWith("removed-"))
|
||||||
|
{
|
||||||
|
blRemoved = true;
|
||||||
|
key = key.Replace("removed-", "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blRemoved && !fileContent.ContainsKey(key))
|
||||||
|
{
|
||||||
|
fileContent.Add(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var lstOri = (List<object>)fileContent[key];
|
||||||
|
var lstValue = (List<object>)value;
|
||||||
|
|
||||||
|
if (blRemoved)
|
||||||
|
{
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.RemoveAll(t => t.ToString().StartsWith(item.ToString()));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blPrepend)
|
||||||
|
{
|
||||||
|
lstValue.Reverse();
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.Insert(0, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetLogLevel(string level)
|
||||||
|
{
|
||||||
|
if (level == "none")
|
||||||
|
{
|
||||||
|
return "silent";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler.CoreConfig
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Core configuration file processing class
|
/// Core configuration file processing class
|
||||||
@@ -24,9 +25,22 @@ namespace v2rayN.Handler
|
|||||||
msg = ResUI.InitialConfiguration;
|
msg = ResUI.InitialConfiguration;
|
||||||
if (node.configType == EConfigType.Custom)
|
if (node.configType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
return GenerateClientCustomConfig(node, fileName, out msg);
|
if (node.coreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
||||||
|
{
|
||||||
|
var configGenClash = new CoreConfigClash(config);
|
||||||
|
return configGenClash.GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
|
if (node.coreType is ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
var configGenSingbox = new CoreConfigSingbox(config);
|
||||||
|
return configGenSingbox.GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (config.tunModeItem.enableTun || LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
else if (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
||||||
{
|
{
|
||||||
var configGenSingbox = new CoreConfigSingbox(config);
|
var configGenSingbox = new CoreConfigSingbox(config);
|
||||||
if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
|
if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||||
@@ -35,11 +49,11 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
content = Utils.ToJson(singboxConfig);
|
content = JsonUtils.Serialize(singboxConfig);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.ToJsonFile(singboxConfig, fileName, false);
|
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -51,17 +65,17 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
content = Utils.ToJson(v2rayConfig);
|
content = JsonUtils.Serialize(v2rayConfig);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.ToJsonFile(v2rayConfig, fileName, false);
|
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("GenerateClientConfig", ex);
|
Logging.SaveLog("GenerateClientConfig", ex);
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -104,46 +118,11 @@ namespace v2rayN.Handler
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//overwrite port
|
|
||||||
if (node.preSocksPort <= 0)
|
|
||||||
{
|
|
||||||
var fileContent = File.ReadAllLines(fileName).ToList();
|
|
||||||
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
|
||||||
switch (coreType)
|
|
||||||
{
|
|
||||||
case ECoreType.v2fly:
|
|
||||||
case ECoreType.SagerNet:
|
|
||||||
case ECoreType.Xray:
|
|
||||||
case ECoreType.v2fly_v5:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ECoreType.clash:
|
|
||||||
case ECoreType.clash_meta:
|
|
||||||
case ECoreType.mihomo:
|
|
||||||
//remove the original
|
|
||||||
var indexPort = fileContent.FindIndex(t => t.Contains("port:"));
|
|
||||||
if (indexPort >= 0)
|
|
||||||
{
|
|
||||||
fileContent.RemoveAt(indexPort);
|
|
||||||
}
|
|
||||||
indexPort = fileContent.FindIndex(t => t.Contains("socks-port:"));
|
|
||||||
if (indexPort >= 0)
|
|
||||||
{
|
|
||||||
fileContent.RemoveAt(indexPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileContent.Add($"port: {LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}");
|
|
||||||
fileContent.Add($"socks-port: {LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
File.WriteAllLines(fileName, fileContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("GenerateClientCustomConfig", ex);
|
Logging.SaveLog("GenerateClientCustomConfig", ex);
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -154,22 +133,44 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
if (coreType == ECoreType.sing_box)
|
if (coreType == ECoreType.sing_box)
|
||||||
{
|
{
|
||||||
if ((new CoreConfigSingbox(config)).GenerateClientSpeedtestConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
if (new CoreConfigSingbox(config).GenerateClientSpeedtestConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Utils.ToJsonFile(singboxConfig, fileName, false);
|
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((new CoreConfigV2ray(config)).GenerateClientSpeedtestConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
if (new CoreConfigV2ray(config).GenerateClientSpeedtestConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
||||||
Utils.ToJsonFile(v2rayConfig, fileName, false);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
if (coreType == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
if (new CoreConfigSingbox(config).GenerateClientMultipleLoadConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||||
|
}
|
||||||
|
else if (coreType == ECoreType.Xray)
|
||||||
|
{
|
||||||
|
if (new CoreConfigV2ray(config).GenerateClientMultipleLoadConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1381
v2rayN/v2rayN/Handler/CoreConfig/CoreConfigSingbox.cs
Normal file
1381
v2rayN/v2rayN/Handler/CoreConfig/CoreConfigSingbox.cs
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,950 +0,0 @@
|
|||||||
using System.Net;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using v2rayN.Base;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Resx;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
|
||||||
{
|
|
||||||
internal class CoreConfigSingbox
|
|
||||||
{
|
|
||||||
private Config _config;
|
|
||||||
|
|
||||||
public CoreConfigSingbox(Config config)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GenerateClientConfigContent(ProfileItem node, out SingboxConfig? singboxConfig, out string msg)
|
|
||||||
{
|
|
||||||
singboxConfig = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (node == null
|
|
||||||
|| node.port <= 0)
|
|
||||||
{
|
|
||||||
msg = ResUI.CheckServerSettings;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = ResUI.InitialConfiguration;
|
|
||||||
|
|
||||||
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
|
|
||||||
if (Utils.IsNullOrEmpty(result))
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGetDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
singboxConfig = Utils.FromJson<SingboxConfig>(result);
|
|
||||||
if (singboxConfig == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenLog(singboxConfig);
|
|
||||||
|
|
||||||
GenInbounds(singboxConfig);
|
|
||||||
|
|
||||||
GenOutbound(node, singboxConfig.outbounds[0]);
|
|
||||||
|
|
||||||
GenMoreOutbounds(node, singboxConfig);
|
|
||||||
|
|
||||||
GenRouting(singboxConfig);
|
|
||||||
|
|
||||||
GenDns(node, singboxConfig);
|
|
||||||
|
|
||||||
GenStatistic(singboxConfig);
|
|
||||||
|
|
||||||
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog("GenerateClientConfig4Singbox", ex);
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region private gen function
|
|
||||||
|
|
||||||
private int GenLog(SingboxConfig singboxConfig)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
switch (_config.coreBasicItem.loglevel)
|
|
||||||
{
|
|
||||||
case "debug":
|
|
||||||
case "info":
|
|
||||||
case "error":
|
|
||||||
singboxConfig.log.level = _config.coreBasicItem.loglevel;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "warning":
|
|
||||||
singboxConfig.log.level = "warn";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (_config.coreBasicItem.loglevel == "none")
|
|
||||||
{
|
|
||||||
singboxConfig.log.disabled = true;
|
|
||||||
}
|
|
||||||
if (_config.coreBasicItem.logEnabled)
|
|
||||||
{
|
|
||||||
var dtNow = DateTime.Now;
|
|
||||||
singboxConfig.log.output = Utils.GetLogPath($"sbox_{dtNow:yyyy-MM-dd}.txt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenInbounds(SingboxConfig singboxConfig)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
singboxConfig.inbounds.Clear();
|
|
||||||
|
|
||||||
if (!_config.tunModeItem.enableTun || (_config.tunModeItem.enableTun && _config.tunModeItem.enableExInbound))
|
|
||||||
{
|
|
||||||
var inbound = new Inbound4Sbox()
|
|
||||||
{
|
|
||||||
type = Global.InboundSocks,
|
|
||||||
tag = Global.InboundSocks,
|
|
||||||
listen = Global.Loopback,
|
|
||||||
};
|
|
||||||
singboxConfig.inbounds.Add(inbound);
|
|
||||||
|
|
||||||
inbound.listen_port = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
|
|
||||||
inbound.sniff = _config.inbound[0].sniffingEnabled;
|
|
||||||
inbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
|
|
||||||
inbound.domain_strategy = Utils.IsNullOrEmpty(_config.routingBasicItem.domainStrategy4Singbox) ? null : _config.routingBasicItem.domainStrategy4Singbox;
|
|
||||||
|
|
||||||
if (_config.routingBasicItem.enableRoutingAdvanced)
|
|
||||||
{
|
|
||||||
var routing = ConfigHandler.GetDefaultRouting(_config);
|
|
||||||
if (!Utils.IsNullOrEmpty(routing.domainStrategy4Singbox))
|
|
||||||
{
|
|
||||||
inbound.domain_strategy = routing.domainStrategy4Singbox;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//http
|
|
||||||
var inbound2 = GetInbound(inbound, Global.InboundHttp, 1, false);
|
|
||||||
singboxConfig.inbounds.Add(inbound2);
|
|
||||||
|
|
||||||
if (_config.inbound[0].allowLANConn)
|
|
||||||
{
|
|
||||||
if (_config.inbound[0].newPort4LAN)
|
|
||||||
{
|
|
||||||
var inbound3 = GetInbound(inbound, Global.InboundSocks2, 2, true);
|
|
||||||
inbound3.listen = "::";
|
|
||||||
singboxConfig.inbounds.Add(inbound3);
|
|
||||||
|
|
||||||
var inbound4 = GetInbound(inbound, Global.InboundHttp2, 3, false);
|
|
||||||
inbound4.listen = "::";
|
|
||||||
singboxConfig.inbounds.Add(inbound4);
|
|
||||||
|
|
||||||
//auth
|
|
||||||
if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
|
|
||||||
{
|
|
||||||
inbound3.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
|
|
||||||
inbound4.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
inbound.listen = "::";
|
|
||||||
inbound2.listen = "::";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config.tunModeItem.enableTun)
|
|
||||||
{
|
|
||||||
if (_config.tunModeItem.mtu <= 0)
|
|
||||||
{
|
|
||||||
_config.tunModeItem.mtu = Convert.ToInt32(Global.TunMtus[0]);
|
|
||||||
}
|
|
||||||
if (Utils.IsNullOrEmpty(_config.tunModeItem.stack))
|
|
||||||
{
|
|
||||||
_config.tunModeItem.stack = Global.TunStacks[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
var tunInbound = Utils.FromJson<Inbound4Sbox>(Utils.GetEmbedText(Global.TunSingboxInboundFileName));
|
|
||||||
tunInbound.mtu = _config.tunModeItem.mtu;
|
|
||||||
tunInbound.strict_route = _config.tunModeItem.strictRoute;
|
|
||||||
tunInbound.stack = _config.tunModeItem.stack;
|
|
||||||
if (_config.tunModeItem.enableIPv6Address == false)
|
|
||||||
{
|
|
||||||
tunInbound.inet6_address = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
singboxConfig.inbounds.Add(tunInbound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Inbound4Sbox? GetInbound(Inbound4Sbox inItem, string tag, int offset, bool bSocks)
|
|
||||||
{
|
|
||||||
var inbound = Utils.DeepCopy(inItem);
|
|
||||||
inbound.tag = tag;
|
|
||||||
inbound.listen_port = inItem.listen_port + offset;
|
|
||||||
inbound.type = bSocks ? Global.InboundSocks : Global.InboundHttp;
|
|
||||||
return inbound;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenOutbound(ProfileItem node, Outbound4Sbox outbound)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
outbound.server = node.address;
|
|
||||||
outbound.server_port = node.port;
|
|
||||||
|
|
||||||
if (node.configType == EConfigType.VMess)
|
|
||||||
{
|
|
||||||
outbound.type = Global.ProtocolTypes[EConfigType.VMess];
|
|
||||||
|
|
||||||
outbound.uuid = node.id;
|
|
||||||
outbound.alter_id = node.alterId;
|
|
||||||
if (Global.VmessSecuritys.Contains(node.security))
|
|
||||||
{
|
|
||||||
outbound.security = node.security;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
outbound.security = Global.DefaultSecurity;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenOutboundMux(node, outbound);
|
|
||||||
}
|
|
||||||
else if (node.configType == EConfigType.Shadowsocks)
|
|
||||||
{
|
|
||||||
outbound.type = Global.ProtocolTypes[EConfigType.Shadowsocks];
|
|
||||||
|
|
||||||
outbound.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none";
|
|
||||||
outbound.password = node.id;
|
|
||||||
|
|
||||||
GenOutboundMux(node, outbound);
|
|
||||||
}
|
|
||||||
else if (node.configType == EConfigType.Socks)
|
|
||||||
{
|
|
||||||
outbound.type = Global.ProtocolTypes[EConfigType.Socks];
|
|
||||||
|
|
||||||
outbound.version = "5";
|
|
||||||
if (!Utils.IsNullOrEmpty(node.security)
|
|
||||||
&& !Utils.IsNullOrEmpty(node.id))
|
|
||||||
{
|
|
||||||
outbound.username = node.security;
|
|
||||||
outbound.password = node.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (node.configType == EConfigType.VLESS)
|
|
||||||
{
|
|
||||||
outbound.type = Global.ProtocolTypes[EConfigType.VLESS];
|
|
||||||
|
|
||||||
outbound.uuid = node.id;
|
|
||||||
|
|
||||||
outbound.packet_encoding = "xudp";
|
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(node.flow))
|
|
||||||
{
|
|
||||||
GenOutboundMux(node, outbound);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
outbound.flow = node.flow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (node.configType == EConfigType.Trojan)
|
|
||||||
{
|
|
||||||
outbound.type = Global.ProtocolTypes[EConfigType.Trojan];
|
|
||||||
|
|
||||||
outbound.password = node.id;
|
|
||||||
|
|
||||||
GenOutboundMux(node, outbound);
|
|
||||||
}
|
|
||||||
else if (node.configType == EConfigType.Hysteria2)
|
|
||||||
{
|
|
||||||
outbound.type = Global.ProtocolTypes[EConfigType.Hysteria2];
|
|
||||||
|
|
||||||
outbound.password = node.id;
|
|
||||||
|
|
||||||
outbound.up_mbps = _config.hysteriaItem.up_mbps > 0 ? _config.hysteriaItem.up_mbps : null;
|
|
||||||
outbound.down_mbps = _config.hysteriaItem.down_mbps > 0 ? _config.hysteriaItem.down_mbps : null;
|
|
||||||
|
|
||||||
GenOutboundMux(node, outbound);
|
|
||||||
}
|
|
||||||
else if (node.configType == EConfigType.Tuic)
|
|
||||||
{
|
|
||||||
outbound.type = Global.ProtocolTypes[EConfigType.Tuic];
|
|
||||||
|
|
||||||
outbound.uuid = node.id;
|
|
||||||
outbound.password = node.security;
|
|
||||||
outbound.congestion_control = node.headerType;
|
|
||||||
|
|
||||||
GenOutboundMux(node, outbound);
|
|
||||||
}
|
|
||||||
|
|
||||||
GenOutboundTls(node, outbound);
|
|
||||||
|
|
||||||
GenOutboundTransport(node, outbound);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenOutboundMux(ProfileItem node, Outbound4Sbox outbound)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//if (_config.coreBasicItem.muxEnabled)
|
|
||||||
//{
|
|
||||||
// var mux = new Multiplex4Sbox()
|
|
||||||
// {
|
|
||||||
// enabled = true,
|
|
||||||
// protocol = _config.mux4Sbox.protocol,
|
|
||||||
// max_connections = _config.mux4Sbox.max_connections,
|
|
||||||
// min_streams = _config.mux4Sbox.min_streams,
|
|
||||||
// max_streams = _config.mux4Sbox.max_streams,
|
|
||||||
// padding = _config.mux4Sbox.padding
|
|
||||||
// };
|
|
||||||
// outbound.multiplex = mux;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenOutboundTls(ProfileItem node, Outbound4Sbox outbound)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (node.streamSecurity == Global.StreamSecurityReality || node.streamSecurity == Global.StreamSecurity)
|
|
||||||
{
|
|
||||||
var server_name = string.Empty;
|
|
||||||
if (!string.IsNullOrWhiteSpace(node.sni))
|
|
||||||
{
|
|
||||||
server_name = node.sni;
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrWhiteSpace(node.requestHost))
|
|
||||||
{
|
|
||||||
server_name = Utils.String2List(node.requestHost)[0];
|
|
||||||
}
|
|
||||||
var tls = new Tls4Sbox()
|
|
||||||
{
|
|
||||||
enabled = true,
|
|
||||||
server_name = server_name,
|
|
||||||
insecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
|
|
||||||
alpn = node.GetAlpn(),
|
|
||||||
};
|
|
||||||
if (!Utils.IsNullOrEmpty(node.fingerprint))
|
|
||||||
{
|
|
||||||
tls.utls = new Utls4Sbox()
|
|
||||||
{
|
|
||||||
enabled = true,
|
|
||||||
fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (node.streamSecurity == Global.StreamSecurityReality)
|
|
||||||
{
|
|
||||||
tls.reality = new Reality4Sbox()
|
|
||||||
{
|
|
||||||
enabled = true,
|
|
||||||
public_key = node.publicKey,
|
|
||||||
short_id = node.shortId
|
|
||||||
};
|
|
||||||
tls.insecure = false;
|
|
||||||
}
|
|
||||||
outbound.tls = tls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenOutboundTransport(ProfileItem node, Outbound4Sbox outbound)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var transport = new Transport4Sbox();
|
|
||||||
|
|
||||||
switch (node.GetNetwork())
|
|
||||||
{
|
|
||||||
case "h2":
|
|
||||||
transport.type = "http";
|
|
||||||
transport.host = Utils.IsNullOrEmpty(node.requestHost) ? null : Utils.String2List(node.requestHost);
|
|
||||||
transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "ws":
|
|
||||||
transport.type = "ws";
|
|
||||||
transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
|
|
||||||
if (!Utils.IsNullOrEmpty(node.requestHost))
|
|
||||||
{
|
|
||||||
transport.headers = new()
|
|
||||||
{
|
|
||||||
Host = node.requestHost
|
|
||||||
};
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "quic":
|
|
||||||
transport.type = "quic";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "grpc":
|
|
||||||
transport.type = "grpc";
|
|
||||||
transport.service_name = node.path;
|
|
||||||
transport.idle_timeout = _config.grpcItem.idle_timeout.ToString("##s");
|
|
||||||
transport.ping_timeout = _config.grpcItem.health_check_timeout.ToString("##s");
|
|
||||||
transport.permit_without_stream = _config.grpcItem.permit_without_stream;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
transport = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
outbound.transport = transport;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenMoreOutbounds(ProfileItem node, SingboxConfig singboxConfig)
|
|
||||||
{
|
|
||||||
if (node.subid.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var subItem = LazyConfig.Instance.GetSubItem(node.subid);
|
|
||||||
if (subItem is null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//current proxy
|
|
||||||
var outbound = singboxConfig.outbounds[0];
|
|
||||||
var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
|
|
||||||
|
|
||||||
//Previous proxy
|
|
||||||
var prevNode = LazyConfig.Instance.GetProfileItemViaRemarks(subItem.prevProfile!);
|
|
||||||
if (prevNode is not null
|
|
||||||
&& prevNode.configType != EConfigType.Custom)
|
|
||||||
{
|
|
||||||
var prevOutbound = Utils.FromJson<Outbound4Sbox>(txtOutbound);
|
|
||||||
GenOutbound(prevNode, prevOutbound);
|
|
||||||
prevOutbound.tag = $"{Global.ProxyTag}2";
|
|
||||||
singboxConfig.outbounds.Add(prevOutbound);
|
|
||||||
|
|
||||||
outbound.detour = prevOutbound.tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Next proxy
|
|
||||||
var nextNode = LazyConfig.Instance.GetProfileItemViaRemarks(subItem.nextProfile!);
|
|
||||||
if (nextNode is not null
|
|
||||||
&& nextNode.configType != EConfigType.Custom)
|
|
||||||
{
|
|
||||||
var nextOutbound = Utils.FromJson<Outbound4Sbox>(txtOutbound);
|
|
||||||
GenOutbound(nextNode, nextOutbound);
|
|
||||||
nextOutbound.tag = Global.ProxyTag;
|
|
||||||
singboxConfig.outbounds.Insert(0, nextOutbound);
|
|
||||||
|
|
||||||
outbound.tag = $"{Global.ProxyTag}1";
|
|
||||||
nextOutbound.detour = outbound.tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenRouting(SingboxConfig singboxConfig)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_config.tunModeItem.enableTun)
|
|
||||||
{
|
|
||||||
singboxConfig.route.auto_detect_interface = true;
|
|
||||||
|
|
||||||
var tunRules = Utils.FromJson<List<Rule4Sbox>>(Utils.GetEmbedText(Global.TunSingboxRulesFileName));
|
|
||||||
singboxConfig.route.rules.AddRange(tunRules);
|
|
||||||
|
|
||||||
GenRoutingDirectExe(out List<string> lstDnsExe, out List<string> lstDirectExe);
|
|
||||||
singboxConfig.route.rules.Add(new()
|
|
||||||
{
|
|
||||||
port = new() { 53 },
|
|
||||||
outbound = "dns_out",
|
|
||||||
process_name = lstDnsExe
|
|
||||||
});
|
|
||||||
|
|
||||||
singboxConfig.route.rules.Add(new()
|
|
||||||
{
|
|
||||||
outbound = "direct",
|
|
||||||
process_name = lstDirectExe
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config.routingBasicItem.enableRoutingAdvanced)
|
|
||||||
{
|
|
||||||
var routing = ConfigHandler.GetDefaultRouting(_config);
|
|
||||||
if (routing != null)
|
|
||||||
{
|
|
||||||
var rules = Utils.FromJson<List<RulesItem>>(routing.ruleSet);
|
|
||||||
foreach (var item in rules!)
|
|
||||||
{
|
|
||||||
if (item.enabled)
|
|
||||||
{
|
|
||||||
GenRoutingUserRule(item, singboxConfig.route.rules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var lockedItem = ConfigHandler.GetLockedRoutingItem(_config);
|
|
||||||
if (lockedItem != null)
|
|
||||||
{
|
|
||||||
var rules = Utils.FromJson<List<RulesItem>>(lockedItem.ruleSet);
|
|
||||||
foreach (var item in rules!)
|
|
||||||
{
|
|
||||||
GenRoutingUserRule(item, singboxConfig.route.rules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenRoutingDirectExe(out List<string> lstDnsExe, out List<string> lstDirectExe)
|
|
||||||
{
|
|
||||||
lstDnsExe = new();
|
|
||||||
lstDirectExe = new();
|
|
||||||
var coreInfos = LazyConfig.Instance.GetCoreInfos();
|
|
||||||
foreach (var it in coreInfos)
|
|
||||||
{
|
|
||||||
if (it.coreType == ECoreType.v2rayN)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
foreach (var it2 in it.coreExes)
|
|
||||||
{
|
|
||||||
if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box)
|
|
||||||
{
|
|
||||||
lstDnsExe.Add($"{it2}.exe");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lstDirectExe.Contains(it2))
|
|
||||||
{
|
|
||||||
lstDirectExe.Add($"{it2}.exe");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rule = new Rule4Sbox()
|
|
||||||
{
|
|
||||||
outbound = item.outboundTag,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!Utils.IsNullOrEmpty(item.port))
|
|
||||||
{
|
|
||||||
if (item.port.Contains("-"))
|
|
||||||
{
|
|
||||||
rule.port_range = new List<string> { item.port.Replace("-", ":") };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rule.port = new List<int> { Utils.ToInt(item.port) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (item.protocol?.Count > 0)
|
|
||||||
{
|
|
||||||
rule.protocol = item.protocol;
|
|
||||||
}
|
|
||||||
if (item.inboundTag?.Count >= 0)
|
|
||||||
{
|
|
||||||
rule.inbound = item.inboundTag;
|
|
||||||
}
|
|
||||||
var rule2 = Utils.DeepCopy(rule);
|
|
||||||
var rule3 = Utils.DeepCopy(rule);
|
|
||||||
|
|
||||||
var hasDomainIp = false;
|
|
||||||
if (item.domain?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var it in item.domain)
|
|
||||||
{
|
|
||||||
ParseV2Domain(it, rule);
|
|
||||||
}
|
|
||||||
rules.Add(rule);
|
|
||||||
hasDomainIp = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.ip?.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var it in item.ip)
|
|
||||||
{
|
|
||||||
ParseV2Address(it, rule2);
|
|
||||||
}
|
|
||||||
rules.Add(rule2);
|
|
||||||
hasDomainIp = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config.tunModeItem.enableTun && item.process?.Count > 0)
|
|
||||||
{
|
|
||||||
rule3.process_name = item.process;
|
|
||||||
rules.Add(rule3);
|
|
||||||
hasDomainIp = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasDomainIp)
|
|
||||||
{
|
|
||||||
rules.Add(rule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ParseV2Domain(string domain, Rule4Sbox rule)
|
|
||||||
{
|
|
||||||
if (domain.StartsWith("ext:") || domain.StartsWith("ext-domain:"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (domain.StartsWith("geosite:"))
|
|
||||||
{
|
|
||||||
if (rule.geosite is null) { rule.geosite = new(); }
|
|
||||||
rule.geosite?.Add(domain.Substring(8));
|
|
||||||
}
|
|
||||||
else if (domain.StartsWith("regexp:"))
|
|
||||||
{
|
|
||||||
if (rule.domain_regex is null) { rule.domain_regex = new(); }
|
|
||||||
rule.domain_regex?.Add(domain.Replace(Global.RoutingRuleComma, ",").Substring(7));
|
|
||||||
}
|
|
||||||
else if (domain.StartsWith("domain:"))
|
|
||||||
{
|
|
||||||
if (rule.domain is null) { rule.domain = new(); }
|
|
||||||
if (rule.domain_suffix is null) { rule.domain_suffix = new(); }
|
|
||||||
rule.domain?.Add(domain.Substring(7));
|
|
||||||
rule.domain_suffix?.Add("." + domain.Substring(7));
|
|
||||||
}
|
|
||||||
else if (domain.StartsWith("full:"))
|
|
||||||
{
|
|
||||||
if (rule.domain is null) { rule.domain = new(); }
|
|
||||||
rule.domain?.Add(domain.Substring(5));
|
|
||||||
}
|
|
||||||
else if (domain.StartsWith("keyword:"))
|
|
||||||
{
|
|
||||||
if (rule.domain_keyword is null) { rule.domain_keyword = new(); }
|
|
||||||
rule.domain_keyword?.Add(domain.Substring(8));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (rule.domain_keyword is null) { rule.domain_keyword = new(); }
|
|
||||||
rule.domain_keyword?.Add(domain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ParseV2Address(string address, Rule4Sbox rule)
|
|
||||||
{
|
|
||||||
if (address.StartsWith("ext:") || address.StartsWith("ext-ip:"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (address.StartsWith("geoip:!"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (address.StartsWith("geoip:"))
|
|
||||||
{
|
|
||||||
if (rule.geoip is null) { rule.geoip = new(); }
|
|
||||||
rule.geoip?.Add(address.Substring(6));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (rule.ip_cidr is null) { rule.ip_cidr = new(); }
|
|
||||||
rule.ip_cidr?.Add(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenDns(ProfileItem node, SingboxConfig singboxConfig)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Dns4Sbox? dns4Sbox;
|
|
||||||
if (_config.tunModeItem.enableTun)
|
|
||||||
{
|
|
||||||
var item = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
|
||||||
var tunDNS = item?.tunDNS;
|
|
||||||
if (string.IsNullOrWhiteSpace(tunDNS))
|
|
||||||
{
|
|
||||||
tunDNS = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
|
|
||||||
}
|
|
||||||
dns4Sbox = Utils.FromJson<Dns4Sbox>(tunDNS);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var item = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
|
||||||
var normalDNS = item?.normalDNS;
|
|
||||||
if (string.IsNullOrWhiteSpace(normalDNS))
|
|
||||||
{
|
|
||||||
normalDNS = "{\"servers\":[{\"address\":\"tcp://8.8.8.8\"}]}";
|
|
||||||
}
|
|
||||||
|
|
||||||
dns4Sbox = Utils.FromJson<Dns4Sbox>(normalDNS);
|
|
||||||
}
|
|
||||||
if (dns4Sbox is null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//Add the dns of the remote server domain
|
|
||||||
if (dns4Sbox.rules is null)
|
|
||||||
{
|
|
||||||
dns4Sbox.rules = new();
|
|
||||||
}
|
|
||||||
dns4Sbox.servers.Add(new()
|
|
||||||
{
|
|
||||||
tag = "local_local",
|
|
||||||
address = "223.5.5.5",
|
|
||||||
detour = "direct"
|
|
||||||
});
|
|
||||||
dns4Sbox.rules.Add(new()
|
|
||||||
{
|
|
||||||
server = "local_local",
|
|
||||||
outbound = "any"
|
|
||||||
});
|
|
||||||
|
|
||||||
singboxConfig.dns = dns4Sbox;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GenStatistic(SingboxConfig singboxConfig)
|
|
||||||
{
|
|
||||||
if (_config.guiItem.enableStatistics)
|
|
||||||
{
|
|
||||||
singboxConfig.experimental = new Experimental4Sbox()
|
|
||||||
{
|
|
||||||
//cache_file = new CacheFile4Sbox()
|
|
||||||
//{
|
|
||||||
// enabled = true
|
|
||||||
//},
|
|
||||||
//v2ray_api = new V2ray_Api4Sbox()
|
|
||||||
//{
|
|
||||||
// listen = $"{Global.Loopback}:{Global.StatePort}",
|
|
||||||
// stats = new Stats4Sbox()
|
|
||||||
// {
|
|
||||||
// enabled = true,
|
|
||||||
// }
|
|
||||||
//},
|
|
||||||
clash_api = new Clash_Api4Sbox()
|
|
||||||
{
|
|
||||||
external_controller = $"{Global.Loopback}:{Global.StatePort}",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion private gen function
|
|
||||||
|
|
||||||
#region Gen speedtest config
|
|
||||||
|
|
||||||
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out SingboxConfig? singboxConfig, out string msg)
|
|
||||||
{
|
|
||||||
singboxConfig = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_config == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.CheckServerSettings;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = ResUI.InitialConfiguration;
|
|
||||||
|
|
||||||
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
|
|
||||||
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
|
|
||||||
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGetDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
singboxConfig = Utils.FromJson<SingboxConfig>(result);
|
|
||||||
if (singboxConfig == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
List<IPEndPoint> lstIpEndPoints = new();
|
|
||||||
List<TcpConnectionInformation> lstTcpConns = new();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
|
||||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
|
||||||
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
GenLog(singboxConfig);
|
|
||||||
GenDns(new(), singboxConfig);
|
|
||||||
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
|
|
||||||
singboxConfig.outbounds.RemoveAt(0);
|
|
||||||
|
|
||||||
int httpPort = LazyConfig.Instance.GetLocalPort("speedtest");
|
|
||||||
|
|
||||||
foreach (var it in selecteds)
|
|
||||||
{
|
|
||||||
if (it.configType == EConfigType.Custom)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.port <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
|
||||||
{
|
|
||||||
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
|
|
||||||
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//find unuse port
|
|
||||||
var port = httpPort;
|
|
||||||
for (int k = httpPort; k < Global.MaxPort; k++)
|
|
||||||
{
|
|
||||||
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//found
|
|
||||||
port = k;
|
|
||||||
httpPort = port + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Port In Used
|
|
||||||
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
it.port = port;
|
|
||||||
it.allowTest = true;
|
|
||||||
|
|
||||||
//inbound
|
|
||||||
Inbound4Sbox inbound = new()
|
|
||||||
{
|
|
||||||
listen = Global.Loopback,
|
|
||||||
listen_port = port,
|
|
||||||
type = Global.InboundHttp
|
|
||||||
};
|
|
||||||
inbound.tag = Global.InboundHttp + inbound.listen_port.ToString();
|
|
||||||
singboxConfig.inbounds.Add(inbound);
|
|
||||||
|
|
||||||
//outbound
|
|
||||||
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
|
||||||
if (item is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.configType == EConfigType.Shadowsocks
|
|
||||||
&& !Global.SsSecuritysInXray.Contains(item.security))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.configType == EConfigType.VLESS
|
|
||||||
&& !Global.Flows.Contains(item.flow))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var outbound = Utils.FromJson<Outbound4Sbox>(txtOutbound);
|
|
||||||
GenOutbound(item, outbound);
|
|
||||||
outbound.tag = Global.ProxyTag + inbound.listen_port.ToString();
|
|
||||||
singboxConfig.outbounds.Add(outbound);
|
|
||||||
|
|
||||||
//rule
|
|
||||||
Rule4Sbox rule = new()
|
|
||||||
{
|
|
||||||
inbound = new List<string> { inbound.tag },
|
|
||||||
outbound = outbound.tag
|
|
||||||
};
|
|
||||||
singboxConfig.route.rules.Add(rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Gen speedtest config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reactive.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Handler.CoreConfig;
|
||||||
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -26,9 +27,8 @@ namespace v2rayN.Handler
|
|||||||
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCore()
|
public void LoadCore(ProfileItem? node)
|
||||||
{
|
{
|
||||||
var node = ConfigHandler.GetDefaultServer(_config);
|
|
||||||
if (node == null)
|
if (node == null)
|
||||||
{
|
{
|
||||||
ShowMsg(false, ResUI.CheckServerSettings);
|
ShowMsg(false, ResUI.CheckServerSettings);
|
||||||
@@ -39,38 +39,45 @@ namespace v2rayN.Handler
|
|||||||
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
|
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
|
||||||
{
|
{
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
ShowMsg(true, $"{node.GetSummary()}");
|
ShowMsg(true, $"{node.GetSummary()}");
|
||||||
CoreStop();
|
CoreStop();
|
||||||
|
if (_config.tunModeItem.enableTun)
|
||||||
|
{
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
Utils.RemoveTunDevice();
|
||||||
|
}
|
||||||
|
|
||||||
CoreStart(node);
|
CoreStart(node);
|
||||||
|
|
||||||
//In tun mode, do a delay check and restart the core
|
//In tun mode, do a delay check and restart the core
|
||||||
if (_config.tunModeItem.enableTun)
|
//if (_config.tunModeItem.enableTun)
|
||||||
{
|
//{
|
||||||
Observable.Range(1, 1)
|
// Observable.Range(1, 1)
|
||||||
.Delay(TimeSpan.FromSeconds(15))
|
// .Delay(TimeSpan.FromSeconds(15))
|
||||||
.Subscribe(x =>
|
// .Subscribe(x =>
|
||||||
{
|
// {
|
||||||
{
|
// {
|
||||||
if (_process == null || _process.HasExited)
|
// if (_process == null || _process.HasExited)
|
||||||
{
|
// {
|
||||||
CoreStart(node);
|
// CoreStart(node);
|
||||||
ShowMsg(false, "Tun mode restart the core once");
|
// ShowMsg(false, "Tun mode restart the core once");
|
||||||
Utils.SaveLog("Tun mode restart the core once");
|
// Logging.SaveLog("Tun mode restart the core once");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
public int LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
int pid = -1;
|
int pid = -1;
|
||||||
var coreType = selecteds.Exists(t => t.configType == EConfigType.Hysteria2 || t.configType == EConfigType.Tuic) ? ECoreType.sing_box : ECoreType.Xray;
|
var coreType = selecteds.Exists(t => t.configType == EConfigType.Hysteria2 || t.configType == EConfigType.Tuic || t.configType == EConfigType.Wireguard) ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
string configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
string configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
||||||
if (CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType, out string msg) != 0)
|
if (CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType, out string msg) != 0)
|
||||||
{
|
{
|
||||||
@@ -107,8 +114,8 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
if (!hasProc)
|
if (!hasProc)
|
||||||
{
|
{
|
||||||
var coreInfos = LazyConfig.Instance.GetCoreInfos();
|
var coreInfo = LazyConfig.Instance.GetCoreInfo();
|
||||||
foreach (var it in coreInfos)
|
foreach (var it in coreInfo)
|
||||||
{
|
{
|
||||||
if (it.coreType == ECoreType.v2rayN)
|
if (it.coreType == ECoreType.v2rayN)
|
||||||
{
|
{
|
||||||
@@ -120,7 +127,7 @@ namespace v2rayN.Handler
|
|||||||
foreach (Process p in existing)
|
foreach (Process p in existing)
|
||||||
{
|
{
|
||||||
string? path = p.MainModule?.FileName;
|
string? path = p.MainModule?.FileName;
|
||||||
if (path == $"{Utils.GetBinPath(vName, it.coreType)}.exe")
|
if (path == $"{Utils.GetBinPath(vName, it.coreType.ToString())}.exe")
|
||||||
{
|
{
|
||||||
KillProcess(p);
|
KillProcess(p);
|
||||||
}
|
}
|
||||||
@@ -131,7 +138,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,17 +151,19 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CoreFindexe(CoreInfo coreInfo)
|
#region Private
|
||||||
|
|
||||||
|
private string CoreFindExe(CoreInfo coreInfo)
|
||||||
{
|
{
|
||||||
string fileName = string.Empty;
|
string fileName = string.Empty;
|
||||||
foreach (string name in coreInfo.coreExes)
|
foreach (string name in coreInfo.coreExes)
|
||||||
{
|
{
|
||||||
string vName = $"{name}.exe";
|
string vName = $"{name}.exe";
|
||||||
vName = Utils.GetBinPath(vName, coreInfo.coreType);
|
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
|
||||||
if (File.Exists(vName))
|
if (File.Exists(vName))
|
||||||
{
|
{
|
||||||
fileName = vName;
|
fileName = vName;
|
||||||
@@ -163,8 +172,8 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
|
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType.ToString()), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
|
||||||
Utils.SaveLog(msg);
|
Logging.SaveLog(msg);
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
}
|
}
|
||||||
return fileName;
|
return fileName;
|
||||||
@@ -172,44 +181,65 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
private void CoreStart(ProfileItem node)
|
private void CoreStart(ProfileItem node)
|
||||||
{
|
{
|
||||||
|
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
|
|
||||||
ECoreType coreType;
|
//ECoreType coreType;
|
||||||
if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
|
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
|
||||||
{
|
//{
|
||||||
coreType = ECoreType.sing_box;
|
// coreType = ECoreType.sing_box;
|
||||||
}
|
//}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||||
}
|
//}
|
||||||
|
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||||
|
_config.runningCoreType = coreType;
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
||||||
|
|
||||||
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
|
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
|
||||||
var proc = RunProcess(node, coreInfo, "", displayLog, ShowMsg);
|
var proc = RunProcess(node, coreInfo, "", displayLog);
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_process = proc;
|
_process = proc;
|
||||||
|
|
||||||
//start a socks service
|
//start a pre service
|
||||||
if (_process != null && !_process.HasExited)
|
if (_process != null && !_process.HasExited)
|
||||||
{
|
{
|
||||||
if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
|
ProfileItem? itemSocks = null;
|
||||||
|
var preCoreType = ECoreType.sing_box;
|
||||||
|
if (node.configType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.tunModeItem.enableTun)
|
||||||
{
|
{
|
||||||
var itemSocks = new ProfileItem()
|
itemSocks = new ProfileItem()
|
||||||
{
|
{
|
||||||
coreType = ECoreType.sing_box,
|
coreType = preCoreType,
|
||||||
|
configType = EConfigType.Socks,
|
||||||
|
address = Global.Loopback,
|
||||||
|
sni = node.address, //Tun2SocksAddress
|
||||||
|
port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
|
||||||
|
{
|
||||||
|
preCoreType = _config.tunModeItem.enableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
|
itemSocks = new ProfileItem()
|
||||||
|
{
|
||||||
|
coreType = preCoreType,
|
||||||
configType = EConfigType.Socks,
|
configType = EConfigType.Socks,
|
||||||
address = Global.Loopback,
|
address = Global.Loopback,
|
||||||
port = node.preSocksPort
|
port = node.preSocksPort
|
||||||
};
|
};
|
||||||
|
_config.runningCoreType = preCoreType;
|
||||||
|
}
|
||||||
|
if (itemSocks != null)
|
||||||
|
{
|
||||||
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
||||||
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
|
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
|
||||||
{
|
{
|
||||||
var coreInfo2 = LazyConfig.Instance.GetCoreInfo(ECoreType.sing_box);
|
var coreInfo2 = LazyConfig.Instance.GetCoreInfo(preCoreType);
|
||||||
var proc2 = RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true, ShowMsg);
|
var proc2 = RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
|
||||||
if (proc2 is not null)
|
if (proc2 is not null)
|
||||||
{
|
{
|
||||||
_processPre = proc2;
|
_processPre = proc2;
|
||||||
@@ -227,7 +257,7 @@ namespace v2rayN.Handler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
||||||
var proc = RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true, ShowMsg);
|
var proc = RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
@@ -237,25 +267,27 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
string msg = ex.Message;
|
string msg = ex.Message;
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowMsg(bool updateToTrayTooltip, string msg)
|
private void ShowMsg(bool notify, string msg)
|
||||||
{
|
{
|
||||||
_updateFunc(updateToTrayTooltip, msg);
|
_updateFunc(notify, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Private
|
||||||
|
|
||||||
#region Process
|
#region Process
|
||||||
|
|
||||||
private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog, Action<bool, string> update)
|
private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string fileName = CoreFindexe(coreInfo);
|
string fileName = CoreFindExe(coreInfo);
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@@ -275,22 +307,29 @@ namespace v2rayN.Handler
|
|||||||
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var startUpErrorMessage = new StringBuilder();
|
||||||
|
var startUpSuccessful = false;
|
||||||
if (displayLog)
|
if (displayLog)
|
||||||
{
|
{
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
proc.OutputDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
if (!Utils.IsNullOrEmpty(e.Data))
|
||||||
{
|
{
|
||||||
string msg = e.Data + Environment.NewLine;
|
string msg = e.Data + Environment.NewLine;
|
||||||
update(false, msg);
|
ShowMsg(false, msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
proc.ErrorDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
if (!Utils.IsNullOrEmpty(e.Data))
|
||||||
{
|
{
|
||||||
string msg = e.Data + Environment.NewLine;
|
string msg = e.Data + Environment.NewLine;
|
||||||
update(false, msg);
|
ShowMsg(false, msg);
|
||||||
|
|
||||||
|
if (!startUpSuccessful)
|
||||||
|
{
|
||||||
|
startUpErrorMessage.Append(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -303,17 +342,22 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
if (proc.WaitForExit(1000))
|
if (proc.WaitForExit(1000))
|
||||||
{
|
{
|
||||||
throw new Exception(displayLog ? proc.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)");
|
proc.CancelErrorRead();
|
||||||
|
throw new Exception(displayLog ? startUpErrorMessage.ToString() : "启动进程失败并退出 (Failed to start the process and exited)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startUpSuccessful = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.ProcessJob.AddProcess(proc.Handle);
|
LazyConfig.Instance.AddProcess(proc.Handle);
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
string msg = ex.Message;
|
string msg = ex.Message;
|
||||||
update(true, msg);
|
ShowMsg(true, msg);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,7 +370,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
proc.CloseMainWindow();
|
proc.Kill();
|
||||||
proc.WaitForExit(100);
|
proc.WaitForExit(100);
|
||||||
if (!proc.HasExited)
|
if (!proc.HasExited)
|
||||||
{
|
{
|
||||||
@@ -336,7 +380,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.Net;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using v2rayN.Base;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -84,7 +84,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
@@ -111,7 +111,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.SaveLog("StatusCode error: " + url);
|
Logging.SaveLog("StatusCode error: " + url);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -146,7 +146,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -166,7 +166,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -212,7 +212,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -243,7 +243,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -270,13 +270,13 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,8 +286,6 @@ namespace v2rayN.Handler
|
|||||||
int responseTime = -1;
|
int responseTime = -1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Stopwatch timer = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
|
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
|
||||||
using var client = new HttpClient(new SocketsHttpHandler()
|
using var client = new HttpClient(new SocketsHttpHandler()
|
||||||
@@ -295,13 +293,21 @@ namespace v2rayN.Handler
|
|||||||
Proxy = webProxy,
|
Proxy = webProxy,
|
||||||
UseProxy = webProxy != null
|
UseProxy = webProxy != null
|
||||||
});
|
});
|
||||||
await client.GetAsync(url, cts.Token);
|
|
||||||
|
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
List<int> oneTime = [];
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
var timer = Stopwatch.StartNew();
|
||||||
|
await client.GetAsync(url, cts.Token);
|
||||||
|
timer.Stop();
|
||||||
|
oneTime.Add((int)timer.Elapsed.TotalMilliseconds);
|
||||||
|
await Task.Delay(100);
|
||||||
|
}
|
||||||
|
responseTime = oneTime.Where(x => x > 0).OrderBy(x => x).FirstOrDefault();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch //(Exception ex)
|
||||||
{
|
{
|
||||||
//Utils.SaveLog(ex.Message, ex);
|
//Utile.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
return responseTime;
|
return responseTime;
|
||||||
}
|
}
|
||||||
@@ -312,7 +318,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var httpPort = LazyConfig.Instance.GetLocalPort(Global.InboundHttp);
|
var httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
|
||||||
if (!SocketCheck(Global.Loopback, httpPort))
|
if (!SocketCheck(Global.Loopback, httpPort))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
208
v2rayN/v2rayN/Handler/Fmt/BaseFmt.cs
Normal file
208
v2rayN/v2rayN/Handler/Fmt/BaseFmt.cs
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.IO;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class BaseFmt
|
||||||
|
{
|
||||||
|
protected static string GetIpv6(string address)
|
||||||
|
{
|
||||||
|
if (Utils.IsIpv6(address))
|
||||||
|
{
|
||||||
|
// 检查地址是否已经被方括号包围,如果没有,则添加方括号
|
||||||
|
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
|
||||||
|
}
|
||||||
|
return address; // 如果不是IPv6地址,直接返回原地址
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||||
|
{
|
||||||
|
if (!Utils.IsNullOrEmpty(item.flow))
|
||||||
|
{
|
||||||
|
dicQuery.Add("flow", item.flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
||||||
|
{
|
||||||
|
dicQuery.Add("security", item.streamSecurity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (securityDef != null)
|
||||||
|
{
|
||||||
|
dicQuery.Add("security", securityDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.sni))
|
||||||
|
{
|
||||||
|
dicQuery.Add("sni", item.sni);
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||||
|
{
|
||||||
|
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.fingerprint))
|
||||||
|
{
|
||||||
|
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.publicKey))
|
||||||
|
{
|
||||||
|
dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.shortId))
|
||||||
|
{
|
||||||
|
dicQuery.Add("sid", Utils.UrlEncode(item.shortId));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.spiderX))
|
||||||
|
{
|
||||||
|
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
||||||
|
}
|
||||||
|
if (item.allowInsecure.Equals("true"))
|
||||||
|
{
|
||||||
|
dicQuery.Add("allowInsecure", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
||||||
|
|
||||||
|
switch (item.network)
|
||||||
|
{
|
||||||
|
case nameof(ETransport.tcp):
|
||||||
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
|
{
|
||||||
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.kcp):
|
||||||
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("seed", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.ws):
|
||||||
|
case nameof(ETransport.httpupgrade):
|
||||||
|
case nameof(ETransport.splithttp):
|
||||||
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
|
{
|
||||||
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.http):
|
||||||
|
case nameof(ETransport.h2):
|
||||||
|
dicQuery["type"] = nameof(ETransport.http);
|
||||||
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
|
{
|
||||||
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.quic):
|
||||||
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
|
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
|
||||||
|
dicQuery.Add("key", Utils.UrlEncode(item.path));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.grpc):
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("authority", Utils.UrlEncode(item.requestHost));
|
||||||
|
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
||||||
|
if (item.headerType is Global.GrpcGunMode or Global.GrpcMultiMode)
|
||||||
|
{
|
||||||
|
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
||||||
|
{
|
||||||
|
item.flow = query["flow"] ?? "";
|
||||||
|
item.streamSecurity = query["security"] ?? "";
|
||||||
|
item.sni = query["sni"] ?? "";
|
||||||
|
item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
|
||||||
|
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
|
||||||
|
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
||||||
|
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
||||||
|
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
||||||
|
item.allowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
|
||||||
|
|
||||||
|
item.network = query["type"] ?? nameof(ETransport.tcp);
|
||||||
|
switch (item.network)
|
||||||
|
{
|
||||||
|
case nameof(ETransport.tcp):
|
||||||
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.kcp):
|
||||||
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
|
item.path = Utils.UrlDecode(query["seed"] ?? "");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.ws):
|
||||||
|
case nameof(ETransport.httpupgrade):
|
||||||
|
case nameof(ETransport.splithttp):
|
||||||
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
|
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.http):
|
||||||
|
case nameof(ETransport.h2):
|
||||||
|
item.network = nameof(ETransport.h2);
|
||||||
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
|
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.quic):
|
||||||
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
|
item.requestHost = query["quicSecurity"] ?? Global.None;
|
||||||
|
item.path = Utils.UrlDecode(query["key"] ?? "");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.grpc):
|
||||||
|
item.requestHost = Utils.UrlDecode(query["authority"] ?? "");
|
||||||
|
item.path = Utils.UrlDecode(query["serviceName"] ?? "");
|
||||||
|
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static bool Contains(string str, params string[] s)
|
||||||
|
{
|
||||||
|
foreach (var item in s)
|
||||||
|
{
|
||||||
|
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string WriteAllText(string strData, string ext = "json")
|
||||||
|
{
|
||||||
|
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.{ext}");
|
||||||
|
File.WriteAllText(fileName, strData);
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
v2rayN/v2rayN/Handler/Fmt/ClashFmt.cs
Normal file
26
v2rayN/v2rayN/Handler/Fmt/ClashFmt.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class ClashFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "port", "socks-port", "proxies"))
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData, "yaml");
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.mihomo,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "clash_custom"
|
||||||
|
};
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
94
v2rayN/v2rayN/Handler/Fmt/FmtHandler.cs
Normal file
94
v2rayN/v2rayN/Handler/Fmt/FmtHandler.cs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class FmtHandler
|
||||||
|
{
|
||||||
|
public static string? GetShareUri(ProfileItem item)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = item.configType switch
|
||||||
|
{
|
||||||
|
EConfigType.VMess => VmessFmt.ToUri(item),
|
||||||
|
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
|
||||||
|
EConfigType.Socks => SocksFmt.ToUri(item),
|
||||||
|
EConfigType.Trojan => TrojanFmt.ToUri(item),
|
||||||
|
EConfigType.VLESS => VLESSFmt.ToUri(item),
|
||||||
|
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
||||||
|
EConfigType.Tuic => TuicFmt.ToUri(item),
|
||||||
|
EConfigType.Wireguard => WireguardFmt.ToUri(item),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveConfig(string config, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string str = config.TrimEx();
|
||||||
|
if (Utils.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
|
||||||
|
{
|
||||||
|
return VmessFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks]))
|
||||||
|
{
|
||||||
|
return ShadowsocksFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Socks]))
|
||||||
|
{
|
||||||
|
return SocksFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Trojan]))
|
||||||
|
{
|
||||||
|
return TrojanFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.VLESS]))
|
||||||
|
{
|
||||||
|
return VLESSFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || str.StartsWith(Global.Hysteria2ProtocolShare))
|
||||||
|
{
|
||||||
|
return Hysteria2Fmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Tuic]))
|
||||||
|
{
|
||||||
|
return TuicFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Wireguard]))
|
||||||
|
{
|
||||||
|
return WireguardFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg = ResUI.NonvmessOrssProtocol;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
msg = ResUI.Incorrectconfiguration;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
104
v2rayN/v2rayN/Handler/Fmt/Hysteria2Fmt.cs
Normal file
104
v2rayN/v2rayN/Handler/Fmt/Hysteria2Fmt.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class Hysteria2Fmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Hysteria2
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
item.path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
||||||
|
item.allowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
if (!Utils.IsNullOrEmpty(item.sni))
|
||||||
|
{
|
||||||
|
dicQuery.Add("sni", item.sni);
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||||
|
{
|
||||||
|
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("obfs", "salamander");
|
||||||
|
dicQuery.Add("obfs-password", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0");
|
||||||
|
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
item.id,
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}/{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "server", "up", "down", "listen", "<html>", "<body>"))
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.hysteria,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "hysteria_custom"
|
||||||
|
};
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull2(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "server", "auth", "up", "down", "listen"))
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.hysteria2,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "hysteria2_custom"
|
||||||
|
};
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
v2rayN/v2rayN/Handler/Fmt/NaiveproxyFmt.cs
Normal file
26
v2rayN/v2rayN/Handler/Fmt/NaiveproxyFmt.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class NaiveproxyFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "listen", "proxy", "<html>", "<body>"))
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.naiveproxy,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "naiveproxy_custom"
|
||||||
|
};
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
183
v2rayN/v2rayN/Handler/Fmt/ShadowsocksFmt.cs
Normal file
183
v2rayN/v2rayN/Handler/Fmt/ShadowsocksFmt.cs
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class ShadowsocksFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem? item;
|
||||||
|
|
||||||
|
item = ResolveSSLegacy(str) ?? ResolveSip002(str);
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (item.address.Length == 0 || item.port == 0 || item.security.Length == 0 || item.id.Length == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.configType = EConfigType.Shadowsocks;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||||
|
// item.security,
|
||||||
|
// item.id,
|
||||||
|
// item.address,
|
||||||
|
// item.port);
|
||||||
|
//url = Utile.Base64Encode(url);
|
||||||
|
//new Sip002
|
||||||
|
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
||||||
|
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Shadowsocks]}{url}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveSSLegacy(string result)
|
||||||
|
{
|
||||||
|
var match = UrlFinder.Match(result);
|
||||||
|
if (!match.Success)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ProfileItem item = new();
|
||||||
|
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
||||||
|
var tag = match.Groups["tag"].Value;
|
||||||
|
if (!Utils.IsNullOrEmpty(tag))
|
||||||
|
{
|
||||||
|
item.remarks = Utils.UrlDecode(tag);
|
||||||
|
}
|
||||||
|
Match details;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
details = DetailsParser.Match(Utils.Base64Decode(base64));
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!details.Success)
|
||||||
|
return null;
|
||||||
|
item.security = details.Groups["method"].Value;
|
||||||
|
item.id = details.Groups["password"].Value;
|
||||||
|
item.address = details.Groups["hostname"].Value;
|
||||||
|
item.port = Utils.ToInt(details.Groups["port"].Value);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveSip002(string result)
|
||||||
|
{
|
||||||
|
Uri parsedUrl;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parsedUrl = new Uri(result);
|
||||||
|
}
|
||||||
|
catch (UriFormatException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
|
address = parsedUrl.IdnHost,
|
||||||
|
port = parsedUrl.Port,
|
||||||
|
};
|
||||||
|
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
|
||||||
|
//2022-blake3
|
||||||
|
if (rawUserInfo.Contains(':'))
|
||||||
|
{
|
||||||
|
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
||||||
|
if (userInfoParts.Length != 2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
item.security = userInfoParts[0];
|
||||||
|
item.id = Utils.UrlDecode(userInfoParts[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// parse base64 UserInfo
|
||||||
|
string userInfo = Utils.Base64Decode(rawUserInfo);
|
||||||
|
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||||
|
if (userInfoParts.Length != 2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
item.security = userInfoParts[0];
|
||||||
|
item.id = userInfoParts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
||||||
|
if (queryParameters["plugin"] != null)
|
||||||
|
{
|
||||||
|
//obfs-host exists
|
||||||
|
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
||||||
|
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
|
||||||
|
{
|
||||||
|
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||||
|
item.network = Global.DefaultNetwork;
|
||||||
|
item.headerType = Global.TcpHeaderHttp;
|
||||||
|
item.requestHost = obfsHost ?? "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ProfileItem>? ResolveSip008(string result)
|
||||||
|
{
|
||||||
|
//SsSIP008
|
||||||
|
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(result);
|
||||||
|
if (lstSsServer?.Count <= 0)
|
||||||
|
{
|
||||||
|
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(result);
|
||||||
|
if (ssSIP008?.servers?.Count > 0)
|
||||||
|
{
|
||||||
|
lstSsServer = ssSIP008.servers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstSsServer?.Count > 0)
|
||||||
|
{
|
||||||
|
List<ProfileItem> lst = [];
|
||||||
|
foreach (var it in lstSsServer)
|
||||||
|
{
|
||||||
|
var ssItem = new ProfileItem()
|
||||||
|
{
|
||||||
|
remarks = it.remarks,
|
||||||
|
security = it.method,
|
||||||
|
id = it.password,
|
||||||
|
address = it.server,
|
||||||
|
port = Utils.ToInt(it.server_port)
|
||||||
|
};
|
||||||
|
lst.Add(ssItem);
|
||||||
|
}
|
||||||
|
return lst;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
v2rayN/v2rayN/Handler/Fmt/SingboxFmt.cs
Normal file
58
v2rayN/v2rayN/Handler/Fmt/SingboxFmt.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class SingboxFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
|
||||||
|
if (configObjects != null && configObjects.Length > 0)
|
||||||
|
{
|
||||||
|
List<ProfileItem> lstResult = [];
|
||||||
|
foreach (var configObject in configObjects)
|
||||||
|
{
|
||||||
|
var objectString = JsonUtils.Serialize(configObject);
|
||||||
|
var singboxCon = JsonUtils.Deserialize<SingboxConfig>(objectString);
|
||||||
|
if (singboxCon?.inbounds?.Count > 0
|
||||||
|
&& singboxCon.outbounds?.Count > 0
|
||||||
|
&& singboxCon.route != null)
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(objectString);
|
||||||
|
|
||||||
|
var profileIt = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.sing_box,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "singbox_custom",
|
||||||
|
};
|
||||||
|
lstResult.Add(profileIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lstResult;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
var singboxConfig = JsonUtils.Deserialize<SingboxConfig>(strData);
|
||||||
|
if (singboxConfig?.inbounds?.Count > 0
|
||||||
|
&& singboxConfig.outbounds?.Count > 0
|
||||||
|
&& singboxConfig.route != null)
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.sing_box,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "singbox_custom"
|
||||||
|
};
|
||||||
|
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
131
v2rayN/v2rayN/Handler/Fmt/SocksFmt.cs
Normal file
131
v2rayN/v2rayN/Handler/Fmt/SocksFmt.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class SocksFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem? item;
|
||||||
|
|
||||||
|
item = ResolveSocksNew(str) ?? ResolveSocks(str);
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (item.address.Length == 0 || item.port == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.configType = EConfigType.Socks;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||||
|
// item.security,
|
||||||
|
// item.id,
|
||||||
|
// item.address,
|
||||||
|
// item.port);
|
||||||
|
//url = Utile.Base64Encode(url);
|
||||||
|
//new
|
||||||
|
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
||||||
|
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Socks]}{url}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveSocks(string result)
|
||||||
|
{
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Socks
|
||||||
|
};
|
||||||
|
result = result[Global.ProtocolShares[EConfigType.Socks].Length..];
|
||||||
|
//remark
|
||||||
|
int indexRemark = result.IndexOf("#");
|
||||||
|
if (indexRemark > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
item.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
result = result[..indexRemark];
|
||||||
|
}
|
||||||
|
//part decode
|
||||||
|
int indexS = result.IndexOf("@");
|
||||||
|
if (indexS > 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = Utils.Base64Decode(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] arr1 = result.Split('@');
|
||||||
|
if (arr1.Length != 2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
string[] arr21 = arr1[0].Split(':');
|
||||||
|
//string[] arr22 = arr1[1].Split(':');
|
||||||
|
int indexPort = arr1[1].LastIndexOf(":");
|
||||||
|
if (arr21.Length != 2 || indexPort < 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
item.address = arr1[1][..indexPort];
|
||||||
|
item.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
||||||
|
item.security = arr21[0];
|
||||||
|
item.id = arr21[1];
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveSocksNew(string result)
|
||||||
|
{
|
||||||
|
Uri parsedUrl;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parsedUrl = new Uri(result);
|
||||||
|
}
|
||||||
|
catch (UriFormatException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
|
address = parsedUrl.IdnHost,
|
||||||
|
port = parsedUrl.Port,
|
||||||
|
};
|
||||||
|
|
||||||
|
// parse base64 UserInfo
|
||||||
|
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
|
||||||
|
string userInfo = Utils.Base64Decode(rawUserInfo);
|
||||||
|
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||||
|
if (userInfoParts.Length == 2)
|
||||||
|
{
|
||||||
|
item.security = userInfoParts[0];
|
||||||
|
item.id = userInfoParts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
v2rayN/v2rayN/Handler/Fmt/TrojanFmt.cs
Normal file
53
v2rayN/v2rayN/Handler/Fmt/TrojanFmt.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class TrojanFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Trojan
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
GetStdTransport(item, null, ref dicQuery);
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
item.id,
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Trojan]}{url}{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
v2rayN/v2rayN/Handler/Fmt/TuicFmt.cs
Normal file
68
v2rayN/v2rayN/Handler/Fmt/TuicFmt.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class TuicFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Tuic
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
var userInfoParts = url.UserInfo.Split(new[] { ':' }, 2);
|
||||||
|
if (userInfoParts.Length == 2)
|
||||||
|
{
|
||||||
|
item.id = userInfoParts[0];
|
||||||
|
item.security = userInfoParts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
item.headerType = query["congestion_control"] ?? "";
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
if (!Utils.IsNullOrEmpty(item.sni))
|
||||||
|
{
|
||||||
|
dicQuery.Add("sni", item.sni);
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||||
|
{
|
||||||
|
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||||
|
}
|
||||||
|
dicQuery.Add("congestion_control", item.headerType);
|
||||||
|
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
$"{item.id}:{item.security}",
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Tuic]}{url}{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
v2rayN/v2rayN/Handler/Fmt/V2rayFmt.cs
Normal file
59
v2rayN/v2rayN/Handler/Fmt/V2rayFmt.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class V2rayFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
|
||||||
|
if (configObjects != null && configObjects.Length > 0)
|
||||||
|
{
|
||||||
|
List<ProfileItem> lstResult = [];
|
||||||
|
foreach (var configObject in configObjects)
|
||||||
|
{
|
||||||
|
var objectString = JsonUtils.Serialize(configObject);
|
||||||
|
var v2rayCon = JsonUtils.Deserialize<V2rayConfig>(objectString);
|
||||||
|
if (v2rayCon?.inbounds?.Count > 0
|
||||||
|
&& v2rayCon.outbounds?.Count > 0
|
||||||
|
&& v2rayCon.routing != null)
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(objectString);
|
||||||
|
|
||||||
|
var profileIt = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.Xray,
|
||||||
|
address = fileName,
|
||||||
|
remarks = v2rayCon.remarks ?? subRemarks ?? "v2ray_custom",
|
||||||
|
};
|
||||||
|
lstResult.Add(profileIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lstResult;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(strData);
|
||||||
|
if (v2rayConfig?.inbounds?.Count > 0
|
||||||
|
&& v2rayConfig.outbounds?.Count > 0
|
||||||
|
&& v2rayConfig.routing != null)
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.Xray,
|
||||||
|
address = fileName,
|
||||||
|
remarks = v2rayConfig.remarks ?? subRemarks ?? "v2ray_custom"
|
||||||
|
};
|
||||||
|
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
v2rayN/v2rayN/Handler/Fmt/VLESSFmt.cs
Normal file
64
v2rayN/v2rayN/Handler/Fmt/VLESSFmt.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class VLESSFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.VLESS,
|
||||||
|
security = Global.None
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
item.security = query["encryption"] ?? Global.None;
|
||||||
|
item.streamSecurity = query["security"] ?? "";
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
if (!Utils.IsNullOrEmpty(item.security))
|
||||||
|
{
|
||||||
|
dicQuery.Add("encryption", item.security);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dicQuery.Add("encryption", Global.None);
|
||||||
|
}
|
||||||
|
GetStdTransport(item, Global.None, ref dicQuery);
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
item.id,
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.VLESS]}{url}{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
126
v2rayN/v2rayN/Handler/Fmt/VmessFmt.cs
Normal file
126
v2rayN/v2rayN/Handler/Fmt/VmessFmt.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class VmessFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem? item;
|
||||||
|
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
|
||||||
|
{
|
||||||
|
item = ResolveStdVmess(str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item = ResolveVmess(str, out msg);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
VmessQRCode vmessQRCode = new()
|
||||||
|
{
|
||||||
|
v = item.configVersion,
|
||||||
|
ps = item.remarks.TrimEx(),
|
||||||
|
add = item.address,
|
||||||
|
port = item.port,
|
||||||
|
id = item.id,
|
||||||
|
aid = item.alterId,
|
||||||
|
scy = item.security,
|
||||||
|
net = item.network,
|
||||||
|
type = item.headerType,
|
||||||
|
host = item.requestHost,
|
||||||
|
path = item.path,
|
||||||
|
tls = item.streamSecurity,
|
||||||
|
sni = item.sni,
|
||||||
|
alpn = item.alpn,
|
||||||
|
fp = item.fingerprint
|
||||||
|
};
|
||||||
|
|
||||||
|
url = JsonUtils.Serialize(vmessQRCode);
|
||||||
|
url = Utils.Base64Encode(url);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveVmess(string result, out string msg)
|
||||||
|
{
|
||||||
|
msg = string.Empty;
|
||||||
|
var item = new ProfileItem
|
||||||
|
{
|
||||||
|
configType = EConfigType.VMess
|
||||||
|
};
|
||||||
|
|
||||||
|
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
||||||
|
result = Utils.Base64Decode(result);
|
||||||
|
|
||||||
|
//转成Json
|
||||||
|
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
||||||
|
if (vmessQRCode == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedConversionConfiguration;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.network = Global.DefaultNetwork;
|
||||||
|
item.headerType = Global.None;
|
||||||
|
|
||||||
|
item.configVersion = Utils.ToInt(vmessQRCode.v);
|
||||||
|
item.remarks = Utils.ToString(vmessQRCode.ps);
|
||||||
|
item.address = Utils.ToString(vmessQRCode.add);
|
||||||
|
item.port = Utils.ToInt(vmessQRCode.port);
|
||||||
|
item.id = Utils.ToString(vmessQRCode.id);
|
||||||
|
item.alterId = Utils.ToInt(vmessQRCode.aid);
|
||||||
|
item.security = Utils.ToString(vmessQRCode.scy);
|
||||||
|
|
||||||
|
item.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
||||||
|
if (!Utils.IsNullOrEmpty(vmessQRCode.net))
|
||||||
|
{
|
||||||
|
item.network = vmessQRCode.net;
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(vmessQRCode.type))
|
||||||
|
{
|
||||||
|
item.headerType = vmessQRCode.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.requestHost = Utils.ToString(vmessQRCode.host);
|
||||||
|
item.path = Utils.ToString(vmessQRCode.path);
|
||||||
|
item.streamSecurity = Utils.ToString(vmessQRCode.tls);
|
||||||
|
item.sni = Utils.ToString(vmessQRCode.sni);
|
||||||
|
item.alpn = Utils.ToString(vmessQRCode.alpn);
|
||||||
|
item.fingerprint = Utils.ToString(vmessQRCode.fp);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveStdVmess(string str)
|
||||||
|
{
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.VMess,
|
||||||
|
security = "auto"
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
v2rayN/v2rayN/Handler/Fmt/WireguardFmt.cs
Normal file
73
v2rayN/v2rayN/Handler/Fmt/WireguardFmt.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.Fmt
|
||||||
|
{
|
||||||
|
internal class WireguardFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Wireguard
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
|
||||||
|
item.publicKey = Utils.UrlDecode(query["publickey"] ?? "");
|
||||||
|
item.path = Utils.UrlDecode(query["reserved"] ?? "");
|
||||||
|
item.requestHost = Utils.UrlDecode(query["address"] ?? "");
|
||||||
|
item.shortId = Utils.UrlDecode(query["mtu"] ?? "");
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
if (!Utils.IsNullOrEmpty(item.publicKey))
|
||||||
|
{
|
||||||
|
dicQuery.Add("publickey", Utils.UrlEncode(item.publicKey));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("reserved", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
|
{
|
||||||
|
dicQuery.Add("address", Utils.UrlEncode(item.requestHost));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.shortId))
|
||||||
|
{
|
||||||
|
dicQuery.Add("mtu", Utils.UrlEncode(item.shortId));
|
||||||
|
}
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
Utils.UrlEncode(item.id),
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Wireguard]}{url}/{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,8 @@ using System.Text;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Runtime.Intrinsics.X86;
|
using System.Runtime.Intrinsics.X86;
|
||||||
using v2rayN.Base;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
@@ -8,18 +8,41 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
private static readonly Lazy<LazyConfig> _instance = new(() => new());
|
private static readonly Lazy<LazyConfig> _instance = new(() => new());
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private List<CoreInfo> coreInfos;
|
private List<CoreInfo> coreInfo;
|
||||||
|
|
||||||
public static LazyConfig Instance => _instance.Value;
|
public static LazyConfig Instance => _instance.Value;
|
||||||
|
|
||||||
|
private int? _statePort;
|
||||||
|
private int? _statePort2;
|
||||||
|
|
||||||
|
public int StatePort
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
|
||||||
|
return _statePort.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int StatePort2
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
|
||||||
|
return _statePort2.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Job _processJob = new();
|
||||||
|
|
||||||
public LazyConfig()
|
public LazyConfig()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.CreateTable<SubItem>();
|
SQLiteHelper.Instance.CreateTable<SubItem>();
|
||||||
SqliteHelper.Instance.CreateTable<ProfileItem>();
|
SQLiteHelper.Instance.CreateTable<ProfileItem>();
|
||||||
SqliteHelper.Instance.CreateTable<ServerStatItem>();
|
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
|
||||||
SqliteHelper.Instance.CreateTable<RoutingItem>();
|
SQLiteHelper.Instance.CreateTable<RoutingItem>();
|
||||||
SqliteHelper.Instance.CreateTable<ProfileExItem>();
|
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
|
||||||
SqliteHelper.Instance.CreateTable<DNSItem>();
|
SQLiteHelper.Instance.CreateTable<DNSItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Config
|
#region Config
|
||||||
@@ -34,67 +57,52 @@ namespace v2rayN.Handler
|
|||||||
return _config;
|
return _config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetLocalPort(string protocol)
|
public int GetLocalPort(EInboundProtocol protocol)
|
||||||
{
|
{
|
||||||
int localPort = _config.inbound.FirstOrDefault(t => t.protocol == Global.InboundSocks).localPort;
|
var localPort = _config.inbound.FirstOrDefault(t => t.protocol == nameof(EInboundProtocol.socks))?.localPort ?? 10808;
|
||||||
if (protocol == Global.InboundSocks)
|
return localPort + (int)protocol;
|
||||||
{
|
|
||||||
return localPort;
|
|
||||||
}
|
|
||||||
else if (protocol == Global.InboundHttp)
|
|
||||||
{
|
|
||||||
return localPort + 1;
|
|
||||||
}
|
|
||||||
else if (protocol == Global.InboundSocks2)
|
|
||||||
{
|
|
||||||
return localPort + 2;
|
|
||||||
}
|
|
||||||
else if (protocol == Global.InboundHttp2)
|
|
||||||
{
|
|
||||||
return localPort + 3;
|
|
||||||
}
|
|
||||||
else if (protocol == ESysProxyType.Pac.ToString())
|
|
||||||
{
|
|
||||||
return localPort + 4;
|
|
||||||
}
|
|
||||||
else if (protocol == "speedtest")
|
|
||||||
{
|
|
||||||
return localPort + 103;
|
|
||||||
}
|
|
||||||
return localPort;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddProcess(IntPtr processHandle)
|
||||||
|
{
|
||||||
|
_processJob.AddProcess(processHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Config
|
||||||
|
|
||||||
|
#region SqliteHelper
|
||||||
|
|
||||||
public List<SubItem> SubItems()
|
public List<SubItem> SubItems()
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<SubItem>().ToList();
|
return SQLiteHelper.Instance.Table<SubItem>().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubItem GetSubItem(string subid)
|
public SubItem GetSubItem(string subid)
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
|
return SQLiteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ProfileItem> ProfileItems(string subid)
|
public List<ProfileItem> ProfileItems(string subid)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
if (Utils.IsNullOrEmpty(subid))
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().ToList();
|
return SQLiteHelper.Instance.Table<ProfileItem>().ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
|
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> ProfileItemIndexs(string subid)
|
public List<string> ProfileItemIndexes(string subid)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
if (Utils.IsNullOrEmpty(subid))
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
|
return SQLiteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
|
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +126,7 @@ namespace v2rayN.Handler
|
|||||||
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
|
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
|
return SQLiteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileItem? GetProfileItem(string indexId)
|
public ProfileItem? GetProfileItem(string indexId)
|
||||||
@@ -127,7 +135,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
|
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileItem? GetProfileItemViaRemarks(string remarks)
|
public ProfileItem? GetProfileItemViaRemarks(string remarks)
|
||||||
@@ -136,45 +144,48 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.remarks == remarks);
|
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.remarks == remarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RoutingItem> RoutingItems()
|
public List<RoutingItem> RoutingItems()
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
|
return SQLiteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoutingItem GetRoutingItem(string id)
|
public RoutingItem GetRoutingItem(string id)
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
|
return SQLiteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DNSItem> DNSItems()
|
public List<DNSItem> DNSItems()
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<DNSItem>().ToList();
|
return SQLiteHelper.Instance.Table<DNSItem>().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DNSItem GetDNSItem(ECoreType eCoreType)
|
public DNSItem GetDNSItem(ECoreType eCoreType)
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<DNSItem>().FirstOrDefault(it => it.coreType == eCoreType);
|
return SQLiteHelper.Instance.Table<DNSItem>().FirstOrDefault(it => it.coreType == eCoreType);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Config
|
#endregion SqliteHelper
|
||||||
|
|
||||||
#region Core Type
|
#region Core Type
|
||||||
|
|
||||||
public List<string> GetShadowsocksSecuritys(ProfileItem profileItem)
|
public List<string> GetShadowsocksSecurities(ProfileItem profileItem)
|
||||||
{
|
{
|
||||||
if (GetCoreType(profileItem, EConfigType.Shadowsocks) == ECoreType.v2fly)
|
var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks);
|
||||||
|
switch (coreType)
|
||||||
{
|
{
|
||||||
return Global.SsSecuritys;
|
case ECoreType.v2fly:
|
||||||
}
|
return Global.SsSecurities;
|
||||||
if (GetCoreType(profileItem, EConfigType.Shadowsocks) == ECoreType.Xray)
|
|
||||||
{
|
|
||||||
return Global.SsSecuritysInXray;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Global.SsSecuritysInSagerNet;
|
case ECoreType.Xray:
|
||||||
|
return Global.SsSecuritiesInXray;
|
||||||
|
|
||||||
|
case ECoreType.sing_box:
|
||||||
|
return Global.SsSecuritiesInSingbox;
|
||||||
|
}
|
||||||
|
return Global.SsSecuritiesInSagerNet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
|
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
|
||||||
@@ -198,27 +209,27 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
public CoreInfo? GetCoreInfo(ECoreType coreType)
|
public CoreInfo? GetCoreInfo(ECoreType coreType)
|
||||||
{
|
{
|
||||||
if (coreInfos == null)
|
if (coreInfo == null)
|
||||||
{
|
{
|
||||||
InitCoreInfo();
|
InitCoreInfo();
|
||||||
}
|
}
|
||||||
return coreInfos!.FirstOrDefault(t => t.coreType == coreType);
|
return coreInfo?.FirstOrDefault(t => t.coreType == coreType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CoreInfo> GetCoreInfos()
|
public List<CoreInfo> GetCoreInfo()
|
||||||
{
|
{
|
||||||
if (coreInfos == null)
|
if (coreInfo == null)
|
||||||
{
|
{
|
||||||
InitCoreInfo();
|
InitCoreInfo();
|
||||||
}
|
}
|
||||||
return coreInfos!;
|
return coreInfo!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitCoreInfo()
|
private void InitCoreInfo()
|
||||||
{
|
{
|
||||||
coreInfos = new(16);
|
coreInfo = new(16);
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2rayN,
|
coreType = ECoreType.v2rayN,
|
||||||
coreUrl = Global.NUrl,
|
coreUrl = Global.NUrl,
|
||||||
@@ -228,7 +239,7 @@ namespace v2rayN.Handler
|
|||||||
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip"
|
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip"
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2fly,
|
coreType = ECoreType.v2fly,
|
||||||
coreExes = new List<string> { "wv2ray", "v2ray" },
|
coreExes = new List<string> { "wv2ray", "v2ray" },
|
||||||
@@ -243,7 +254,7 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.SagerNet,
|
coreType = ECoreType.SagerNet,
|
||||||
coreExes = new List<string> { "SagerNet", "v2ray" },
|
coreExes = new List<string> { "SagerNet", "v2ray" },
|
||||||
@@ -258,7 +269,7 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2fly_v5,
|
coreType = ECoreType.v2fly_v5,
|
||||||
coreExes = new List<string> { "v2ray" },
|
coreExes = new List<string> { "v2ray" },
|
||||||
@@ -273,7 +284,7 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.Xray,
|
coreType = ECoreType.Xray,
|
||||||
coreExes = new List<string> { "xray", "wxray" },
|
coreExes = new List<string> { "xray", "wxray" },
|
||||||
@@ -288,7 +299,7 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.clash,
|
coreType = ECoreType.clash,
|
||||||
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
|
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
|
||||||
@@ -303,7 +314,7 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.clash_meta,
|
coreType = ECoreType.clash_meta,
|
||||||
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
|
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
|
||||||
@@ -318,18 +329,22 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.mihomo,
|
coreType = ECoreType.mihomo,
|
||||||
coreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
|
coreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
|
||||||
arguments = "-f config.yaml",
|
arguments = "-f config.json",
|
||||||
coreUrl = Global.MihomoCoreUrl,
|
coreUrl = Global.MihomoCoreUrl,
|
||||||
coreReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
coreReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
coreDownloadUrl32 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-386-{0}.zip",
|
||||||
|
coreDownloadUrl64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
|
||||||
|
coreDownloadUrlArm64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
||||||
match = "Mihomo",
|
match = "Mihomo",
|
||||||
|
versionArg = "-v",
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.hysteria,
|
coreType = ECoreType.hysteria,
|
||||||
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
||||||
@@ -342,7 +357,7 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.naiveproxy,
|
coreType = ECoreType.naiveproxy,
|
||||||
coreExes = new List<string> { "naiveproxy", "naive" },
|
coreExes = new List<string> { "naiveproxy", "naive" },
|
||||||
@@ -351,7 +366,7 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = false,
|
redirectInfo = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.tuic,
|
coreType = ECoreType.tuic,
|
||||||
coreExes = new List<string> { "tuic-client", "tuic" },
|
coreExes = new List<string> { "tuic-client", "tuic" },
|
||||||
@@ -360,7 +375,7 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.sing_box,
|
coreType = ECoreType.sing_box,
|
||||||
coreExes = new List<string> { "sing-box-client", "sing-box" },
|
coreExes = new List<string> { "sing-box-client", "sing-box" },
|
||||||
@@ -375,7 +390,7 @@ namespace v2rayN.Handler
|
|||||||
versionArg = "version",
|
versionArg = "version",
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.juicity,
|
coreType = ECoreType.juicity,
|
||||||
coreExes = new List<string> { "juicity-client", "juicity" },
|
coreExes = new List<string> { "juicity-client", "juicity" },
|
||||||
@@ -383,7 +398,7 @@ namespace v2rayN.Handler
|
|||||||
coreUrl = Global.JuicityCoreUrl
|
coreUrl = Global.JuicityCoreUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.hysteria2,
|
coreType = ECoreType.hysteria2,
|
||||||
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
using Splat;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interop;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Handler.CoreConfig;
|
||||||
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -16,7 +22,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int index = (int)config.sysProxyType;
|
int index = (int)config.systemProxyItem.sysProxyType;
|
||||||
|
|
||||||
//Load from routing setting
|
//Load from routing setting
|
||||||
var createdIcon = GetNotifyIcon4Routing(config);
|
var createdIcon = GetNotifyIcon4Routing(config);
|
||||||
@@ -42,7 +48,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return Properties.Resources.NotifyIcon1;
|
return Properties.Resources.NotifyIcon1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,18 +56,18 @@ namespace v2rayN.Handler
|
|||||||
public System.Windows.Media.ImageSource GetAppIcon(Config config)
|
public System.Windows.Media.ImageSource GetAppIcon(Config config)
|
||||||
{
|
{
|
||||||
int index = 1;
|
int index = 1;
|
||||||
switch ((int)config.sysProxyType)
|
switch (config.systemProxyItem.sysProxyType)
|
||||||
{
|
{
|
||||||
case 0:
|
case ESysProxyType.ForcedClear:
|
||||||
index = 1;
|
index = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case ESysProxyType.ForcedChange:
|
||||||
case 3:
|
case ESysProxyType.Pac:
|
||||||
index = 2;
|
index = 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case ESysProxyType.Unchanged:
|
||||||
index = 3;
|
index = 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -84,7 +90,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
Color color = ColorTranslator.FromHtml("#3399CC");
|
Color color = ColorTranslator.FromHtml("#3399CC");
|
||||||
int index = (int)config.sysProxyType;
|
int index = (int)config.systemProxyItem.sysProxyType;
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
{
|
{
|
||||||
color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1];
|
color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1];
|
||||||
@@ -112,7 +118,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,11 +129,6 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (item.configType == EConfigType.Custom)
|
|
||||||
{
|
|
||||||
UI.Show(ResUI.NonVmessService);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveFileDialog fileDialog = new()
|
SaveFileDialog fileDialog = new()
|
||||||
{
|
{
|
||||||
@@ -146,11 +147,12 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (CoreConfigHandler.GenerateClientConfig(item, fileName, out string msg, out string content) != 0)
|
if (CoreConfigHandler.GenerateClientConfig(item, fileName, out string msg, out string content) != 0)
|
||||||
{
|
{
|
||||||
UI.Show(msg);
|
Locator.Current.GetService<NoticeHandler>()?.Enqueue(msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UI.ShowWarning(string.Format(ResUI.SaveClientConfigurationIn, fileName));
|
msg = string.Format(ResUI.SaveClientConfigurationIn, fileName);
|
||||||
|
Locator.Current.GetService<NoticeHandler>()?.SendMessageAndEnqueue(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +165,7 @@ namespace v2rayN.Handler
|
|||||||
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
|
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
|
||||||
{
|
{
|
||||||
await Task.Delay(60000);
|
await Task.Delay(60000);
|
||||||
Utils.SaveLog("UpdateTaskRunSubscription");
|
Logging.SaveLog("UpdateTaskRunSubscription");
|
||||||
|
|
||||||
var updateHandle = new UpdateHandle();
|
var updateHandle = new UpdateHandle();
|
||||||
while (true)
|
while (true)
|
||||||
@@ -180,7 +182,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
update(success, msg);
|
update(success, msg);
|
||||||
if (success)
|
if (success)
|
||||||
Utils.SaveLog("subscription" + msg);
|
Logging.SaveLog("subscription" + msg);
|
||||||
});
|
});
|
||||||
item.updateTime = updateTime;
|
item.updateTime = updateTime;
|
||||||
ConfigHandler.AddSubItem(config, item);
|
ConfigHandler.AddSubItem(config, item);
|
||||||
@@ -196,7 +198,7 @@ namespace v2rayN.Handler
|
|||||||
var autoUpdateGeoTime = DateTime.Now;
|
var autoUpdateGeoTime = DateTime.Now;
|
||||||
|
|
||||||
await Task.Delay(1000 * 120);
|
await Task.Delay(1000 * 120);
|
||||||
Utils.SaveLog("UpdateTaskRunGeo");
|
Logging.SaveLog("UpdateTaskRunGeo");
|
||||||
|
|
||||||
var updateHandle = new UpdateHandle();
|
var updateHandle = new UpdateHandle();
|
||||||
while (true)
|
while (true)
|
||||||
@@ -224,5 +226,27 @@ namespace v2rayN.Handler
|
|||||||
HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
|
HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
|
||||||
HotkeyHandler.Instance.Load();
|
HotkeyHandler.Instance.Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RegisterSystemColorSet(Config config, Window window, Action<bool> update)
|
||||||
|
{
|
||||||
|
var helper = new WindowInteropHelper(window);
|
||||||
|
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
|
||||||
|
hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
|
||||||
|
{
|
||||||
|
if (config.uiItem.followSystemTheme)
|
||||||
|
{
|
||||||
|
const int WM_SETTINGCHANGE = 0x001A;
|
||||||
|
if (msg == WM_SETTINGCHANGE)
|
||||||
|
{
|
||||||
|
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet")
|
||||||
|
{
|
||||||
|
update(!Utils.IsLightTheme());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return IntPtr.Zero;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,24 +10,40 @@ namespace v2rayN.Handler
|
|||||||
public NoticeHandler(ISnackbarMessageQueue snackbarMessageQueue)
|
public NoticeHandler(ISnackbarMessageQueue snackbarMessageQueue)
|
||||||
{
|
{
|
||||||
_snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue));
|
_snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue));
|
||||||
|
|
||||||
//_snackbarMessageQueue = snackbarMessageQueue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Enqueue(object content)
|
public void Enqueue(string? content)
|
||||||
{
|
{
|
||||||
|
if (content.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
_snackbarMessageQueue?.Enqueue(content);
|
_snackbarMessageQueue?.Enqueue(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string msg)
|
public void SendMessage(string? content)
|
||||||
{
|
{
|
||||||
MessageBus.Current.SendMessage(msg, "MsgView");
|
if (content.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageBus.Current.SendMessage(content, Global.CommandSendMsgView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string msg, bool time)
|
public void SendMessage(string? content, bool time)
|
||||||
{
|
{
|
||||||
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {msg}";
|
if (content.IsNullOrEmpty())
|
||||||
MessageBus.Current.SendMessage(msg, "MsgView");
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
content = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {content}";
|
||||||
|
SendMessage(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendMessageAndEnqueue(string? msg)
|
||||||
|
{
|
||||||
|
Enqueue(msg);
|
||||||
|
SendMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using v2rayN.Base;
|
using v2rayN.Models;
|
||||||
using v2rayN.Mode;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
internal class ProfileExHandler
|
internal class ProfileExHandler
|
||||||
{
|
{
|
||||||
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
||||||
private ConcurrentBag<ProfileExItem> _lstProfileEx;
|
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
||||||
private Queue<string> _queIndexIds = new();
|
private Queue<string> _queIndexIds = new();
|
||||||
public ConcurrentBag<ProfileExItem> ProfileExs => _lstProfileEx;
|
public ConcurrentBag<ProfileExItem> ProfileExs => _lstProfileEx;
|
||||||
public static ProfileExHandler Instance => _instance.Value;
|
public static ProfileExHandler Instance => _instance.Value;
|
||||||
@@ -16,33 +15,24 @@ namespace v2rayN.Handler
|
|||||||
public ProfileExHandler()
|
public ProfileExHandler()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
|
||||||
|
|
||||||
private void Init()
|
|
||||||
{
|
|
||||||
SqliteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
|
||||||
|
|
||||||
_lstProfileEx = new(SqliteHelper.Instance.Table<ProfileExItem>());
|
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var cnt = _queIndexIds.Count;
|
SaveQueueIndexIds();
|
||||||
for (int i = 0; i < cnt; i++)
|
await Task.Delay(1000 * 600);
|
||||||
{
|
|
||||||
var id = _queIndexIds.Dequeue();
|
|
||||||
var item = _lstProfileEx.FirstOrDefault(t => t.indexId == id);
|
|
||||||
if (item is not null)
|
|
||||||
{
|
|
||||||
SqliteHelper.Instance.Replace(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Task.Delay(1000 * 60);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
SQLiteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
||||||
|
|
||||||
|
_lstProfileEx = new(SQLiteHelper.Instance.Table<ProfileExItem>());
|
||||||
|
}
|
||||||
|
|
||||||
private void IndexIdEnqueue(string indexId)
|
private void IndexIdEnqueue(string indexId)
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
|
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
|
||||||
@@ -51,6 +41,49 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SaveQueueIndexIds()
|
||||||
|
{
|
||||||
|
var cnt = _queIndexIds.Count;
|
||||||
|
if (cnt > 0)
|
||||||
|
{
|
||||||
|
var lstExists = SQLiteHelper.Instance.Table<ProfileExItem>();
|
||||||
|
List<ProfileExItem> lstInserts = [];
|
||||||
|
List<ProfileExItem> lstUpdates = [];
|
||||||
|
|
||||||
|
for (int i = 0; i < cnt; i++)
|
||||||
|
{
|
||||||
|
var id = _queIndexIds.Dequeue();
|
||||||
|
var item = lstExists.FirstOrDefault(t => t.indexId == id);
|
||||||
|
var itemNew = _lstProfileEx?.FirstOrDefault(t => t.indexId == id);
|
||||||
|
if (itemNew is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is not null)
|
||||||
|
{
|
||||||
|
lstUpdates.Add(itemNew);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lstInserts.Add(itemNew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (lstInserts.Count() > 0)
|
||||||
|
SQLiteHelper.Instance.InsertAll(lstInserts);
|
||||||
|
|
||||||
|
if (lstUpdates.Count() > 0)
|
||||||
|
SQLiteHelper.Instance.UpdateAll(lstUpdates);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("ProfileExHandler", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void AddProfileEx(string indexId, ref ProfileExItem? profileEx)
|
private void AddProfileEx(string indexId, ref ProfileExItem? profileEx)
|
||||||
{
|
{
|
||||||
profileEx = new()
|
profileEx = new()
|
||||||
@@ -66,7 +99,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
public void ClearAll()
|
public void ClearAll()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.Execute($"delete from ProfileExItem ");
|
SQLiteHelper.Instance.Execute($"delete from ProfileExItem ");
|
||||||
_lstProfileEx = new();
|
_lstProfileEx = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,15 +107,11 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//foreach (var item in _lstProfileEx)
|
SaveQueueIndexIds();
|
||||||
//{
|
|
||||||
// SqliteHelper.Instance.Replace(item);
|
|
||||||
//}
|
|
||||||
SqliteHelper.Instance.UpdateAll(_lstProfileEx);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
using QRCoder;
|
|
||||||
using QRCoder.Xaml;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 含有QR码的描述类和包装编码和渲染
|
|
||||||
/// </summary>
|
|
||||||
public class QRCodeHelper
|
|
||||||
{
|
|
||||||
public static DrawingImage? GetQRCode(string strContent)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
QRCodeGenerator qrGenerator = new();
|
|
||||||
QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H);
|
|
||||||
XamlQRCode qrCode = new(qrCodeData);
|
|
||||||
DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40);
|
|
||||||
return qrCodeAsXaml;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,934 +0,0 @@
|
|||||||
using System.Collections.Specialized;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Web;
|
|
||||||
using v2rayN.Base;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Resx;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
|
||||||
{
|
|
||||||
internal class ShareHandler
|
|
||||||
{
|
|
||||||
#region GetShareUrl
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// GetShareUrl
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string? GetShareUrl(ProfileItem item)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string? url = string.Empty;
|
|
||||||
|
|
||||||
url = item.configType switch
|
|
||||||
{
|
|
||||||
EConfigType.VMess => ShareVmess(item),
|
|
||||||
EConfigType.Shadowsocks => ShareShadowsocks(item),
|
|
||||||
EConfigType.Socks => ShareSocks(item),
|
|
||||||
EConfigType.Trojan => ShareTrojan(item),
|
|
||||||
EConfigType.VLESS => ShareVLESS(item),
|
|
||||||
EConfigType.Hysteria2 => ShareHysteria2(item),
|
|
||||||
EConfigType.Tuic => ShareTuic(item),
|
|
||||||
_ => null,
|
|
||||||
};
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ShareVmess(ProfileItem item)
|
|
||||||
{
|
|
||||||
string url = string.Empty;
|
|
||||||
|
|
||||||
VmessQRCode vmessQRCode = new()
|
|
||||||
{
|
|
||||||
v = item.configVersion.ToString(),
|
|
||||||
ps = item.remarks.TrimEx(),
|
|
||||||
add = item.address,
|
|
||||||
port = item.port.ToString(),
|
|
||||||
id = item.id,
|
|
||||||
aid = item.alterId.ToString(),
|
|
||||||
scy = item.security,
|
|
||||||
net = item.network,
|
|
||||||
type = item.headerType,
|
|
||||||
host = item.requestHost,
|
|
||||||
path = item.path,
|
|
||||||
tls = item.streamSecurity,
|
|
||||||
sni = item.sni,
|
|
||||||
alpn = item.alpn,
|
|
||||||
fp = item.fingerprint
|
|
||||||
};
|
|
||||||
|
|
||||||
url = Utils.ToJson(vmessQRCode);
|
|
||||||
url = Utils.Base64Encode(url);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ShareShadowsocks(ProfileItem item)
|
|
||||||
{
|
|
||||||
string url = string.Empty;
|
|
||||||
|
|
||||||
string remark = string.Empty;
|
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
|
||||||
{
|
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
|
||||||
}
|
|
||||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
|
||||||
// item.security,
|
|
||||||
// item.id,
|
|
||||||
// item.address,
|
|
||||||
// item.port);
|
|
||||||
//url = Utils.Base64Encode(url);
|
|
||||||
//new Sip002
|
|
||||||
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
|
||||||
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Shadowsocks]}{url}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ShareSocks(ProfileItem item)
|
|
||||||
{
|
|
||||||
string url = string.Empty;
|
|
||||||
string remark = string.Empty;
|
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
|
||||||
{
|
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
|
||||||
}
|
|
||||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
|
||||||
// item.security,
|
|
||||||
// item.id,
|
|
||||||
// item.address,
|
|
||||||
// item.port);
|
|
||||||
//url = Utils.Base64Encode(url);
|
|
||||||
//new
|
|
||||||
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
|
||||||
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Socks]}{url}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ShareTrojan(ProfileItem item)
|
|
||||||
{
|
|
||||||
string url = string.Empty;
|
|
||||||
string remark = string.Empty;
|
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
|
||||||
{
|
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
|
||||||
}
|
|
||||||
var dicQuery = new Dictionary<string, string>();
|
|
||||||
GetStdTransport(item, null, ref dicQuery);
|
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
|
||||||
item.id,
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Trojan]}{url}{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ShareVLESS(ProfileItem item)
|
|
||||||
{
|
|
||||||
string url = string.Empty;
|
|
||||||
string remark = string.Empty;
|
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
|
||||||
{
|
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
|
||||||
}
|
|
||||||
var dicQuery = new Dictionary<string, string>();
|
|
||||||
if (!Utils.IsNullOrEmpty(item.security))
|
|
||||||
{
|
|
||||||
dicQuery.Add("encryption", item.security);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dicQuery.Add("encryption", "none");
|
|
||||||
}
|
|
||||||
GetStdTransport(item, "none", ref dicQuery);
|
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
|
||||||
item.id,
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.VLESS]}{url}{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ShareHysteria2(ProfileItem item)
|
|
||||||
{
|
|
||||||
string url = string.Empty;
|
|
||||||
string remark = string.Empty;
|
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
|
||||||
{
|
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
|
||||||
}
|
|
||||||
var dicQuery = new Dictionary<string, string>();
|
|
||||||
if (!Utils.IsNullOrEmpty(item.sni))
|
|
||||||
{
|
|
||||||
dicQuery.Add("sni", item.sni);
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
|
||||||
{
|
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
|
||||||
}
|
|
||||||
dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0");
|
|
||||||
|
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
|
||||||
item.id,
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ShareTuic(ProfileItem item)
|
|
||||||
{
|
|
||||||
string url = string.Empty;
|
|
||||||
string remark = string.Empty;
|
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
|
||||||
{
|
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
|
||||||
}
|
|
||||||
var dicQuery = new Dictionary<string, string>();
|
|
||||||
if (!Utils.IsNullOrEmpty(item.sni))
|
|
||||||
{
|
|
||||||
dicQuery.Add("sni", item.sni);
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
|
||||||
{
|
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
|
||||||
}
|
|
||||||
dicQuery.Add("congestion_control", item.headerType);
|
|
||||||
|
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
|
||||||
$"{item.id}:{item.security}",
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Tuic]}{url}{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetIpv6(string address)
|
|
||||||
{
|
|
||||||
return Utils.IsIpv6(address) ? $"[{address}]" : address;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
|
||||||
{
|
|
||||||
if (!Utils.IsNullOrEmpty(item.flow))
|
|
||||||
{
|
|
||||||
dicQuery.Add("flow", item.flow);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
|
||||||
{
|
|
||||||
dicQuery.Add("security", item.streamSecurity);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (securityDef != null)
|
|
||||||
{
|
|
||||||
dicQuery.Add("security", securityDef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.sni))
|
|
||||||
{
|
|
||||||
dicQuery.Add("sni", item.sni);
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
|
||||||
{
|
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.fingerprint))
|
|
||||||
{
|
|
||||||
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.publicKey))
|
|
||||||
{
|
|
||||||
dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey));
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.shortId))
|
|
||||||
{
|
|
||||||
dicQuery.Add("sid", Utils.UrlEncode(item.shortId));
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.spiderX))
|
|
||||||
{
|
|
||||||
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
|
||||||
}
|
|
||||||
|
|
||||||
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : "tcp");
|
|
||||||
|
|
||||||
switch (item.network)
|
|
||||||
{
|
|
||||||
case "tcp":
|
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none");
|
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
|
||||||
{
|
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "kcp":
|
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none");
|
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
|
||||||
{
|
|
||||||
dicQuery.Add("seed", Utils.UrlEncode(item.path));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "ws":
|
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
|
||||||
{
|
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
|
||||||
{
|
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "http":
|
|
||||||
case "h2":
|
|
||||||
dicQuery["type"] = "http";
|
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
|
||||||
{
|
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
|
||||||
{
|
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "quic":
|
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none");
|
|
||||||
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
|
|
||||||
dicQuery.Add("key", Utils.UrlEncode(item.path));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "grpc":
|
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
|
||||||
{
|
|
||||||
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
|
||||||
if (item.headerType is Global.GrpcgunMode or Global.GrpcmultiMode)
|
|
||||||
{
|
|
||||||
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion GetShareUrl
|
|
||||||
|
|
||||||
#region ImportShareUrl
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从剪贴板导入URL
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
|
|
||||||
{
|
|
||||||
msg = string.Empty;
|
|
||||||
|
|
||||||
ProfileItem profileItem = new();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//载入配置文件
|
|
||||||
string result = clipboardData.TrimEx();// Utils.GetClipboardData();
|
|
||||||
if (Utils.IsNullOrEmpty(result))
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedReadConfiguration;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
|
|
||||||
{
|
|
||||||
int indexSplit = result.IndexOf("?");
|
|
||||||
if (indexSplit > 0)
|
|
||||||
{
|
|
||||||
profileItem = ResolveStdVmess(result) ?? ResolveVmess4Kitsunebi(result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
profileItem = ResolveVmess(result, out msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks]))
|
|
||||||
{
|
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
|
||||||
|
|
||||||
profileItem = ResolveSSLegacy(result) ?? ResolveSip002(result);
|
|
||||||
if (profileItem == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (profileItem.address.Length == 0 || profileItem.port == 0 || profileItem.security.Length == 0 || profileItem.id.Length == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
profileItem.configType = EConfigType.Shadowsocks;
|
|
||||||
}
|
|
||||||
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Socks]))
|
|
||||||
{
|
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
|
||||||
|
|
||||||
profileItem = ResolveSocksNew(result) ?? ResolveSocks(result);
|
|
||||||
if (profileItem == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (profileItem.address.Length == 0 || profileItem.port == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
profileItem.configType = EConfigType.Socks;
|
|
||||||
}
|
|
||||||
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Trojan]))
|
|
||||||
{
|
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
|
||||||
|
|
||||||
profileItem = ResolveTrojan(result);
|
|
||||||
}
|
|
||||||
else if (result.StartsWith(Global.ProtocolShares[EConfigType.VLESS]))
|
|
||||||
{
|
|
||||||
profileItem = ResolveStdVLESS(result);
|
|
||||||
}
|
|
||||||
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || result.StartsWith(Global.Hysteria2ProtocolShare))
|
|
||||||
{
|
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
|
||||||
|
|
||||||
profileItem = ResolveHysteria2(result);
|
|
||||||
}
|
|
||||||
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Tuic]))
|
|
||||||
{
|
|
||||||
profileItem = ResolveTuic(result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg = ResUI.NonvmessOrssProtocol;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
msg = ResUI.Incorrectconfiguration;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return profileItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveVmess(string result, out string msg)
|
|
||||||
{
|
|
||||||
msg = string.Empty;
|
|
||||||
var profileItem = new ProfileItem
|
|
||||||
{
|
|
||||||
configType = EConfigType.VMess
|
|
||||||
};
|
|
||||||
|
|
||||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
|
||||||
result = Utils.Base64Decode(result);
|
|
||||||
|
|
||||||
//转成Json
|
|
||||||
VmessQRCode? vmessQRCode = Utils.FromJson<VmessQRCode>(result);
|
|
||||||
if (vmessQRCode == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedConversionConfiguration;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
profileItem.network = Global.DefaultNetwork;
|
|
||||||
profileItem.headerType = Global.None;
|
|
||||||
|
|
||||||
profileItem.configVersion = Utils.ToInt(vmessQRCode.v);
|
|
||||||
profileItem.remarks = Utils.ToString(vmessQRCode.ps);
|
|
||||||
profileItem.address = Utils.ToString(vmessQRCode.add);
|
|
||||||
profileItem.port = Utils.ToInt(vmessQRCode.port);
|
|
||||||
profileItem.id = Utils.ToString(vmessQRCode.id);
|
|
||||||
profileItem.alterId = Utils.ToInt(vmessQRCode.aid);
|
|
||||||
profileItem.security = Utils.ToString(vmessQRCode.scy);
|
|
||||||
|
|
||||||
profileItem.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
|
||||||
if (!Utils.IsNullOrEmpty(vmessQRCode.net))
|
|
||||||
{
|
|
||||||
profileItem.network = vmessQRCode.net;
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(vmessQRCode.type))
|
|
||||||
{
|
|
||||||
profileItem.headerType = vmessQRCode.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
profileItem.requestHost = Utils.ToString(vmessQRCode.host);
|
|
||||||
profileItem.path = Utils.ToString(vmessQRCode.path);
|
|
||||||
profileItem.streamSecurity = Utils.ToString(vmessQRCode.tls);
|
|
||||||
profileItem.sni = Utils.ToString(vmessQRCode.sni);
|
|
||||||
profileItem.alpn = Utils.ToString(vmessQRCode.alpn);
|
|
||||||
profileItem.fingerprint = Utils.ToString(vmessQRCode.fp);
|
|
||||||
|
|
||||||
return profileItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveVmess4Kitsunebi(string result)
|
|
||||||
{
|
|
||||||
ProfileItem profileItem = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.VMess
|
|
||||||
};
|
|
||||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
|
||||||
int indexSplit = result.IndexOf("?");
|
|
||||||
if (indexSplit > 0)
|
|
||||||
{
|
|
||||||
result = result[..indexSplit];
|
|
||||||
}
|
|
||||||
result = Utils.Base64Decode(result);
|
|
||||||
|
|
||||||
string[] arr1 = result.Split('@');
|
|
||||||
if (arr1.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
string[] arr21 = arr1[0].Split(':');
|
|
||||||
string[] arr22 = arr1[1].Split(':');
|
|
||||||
if (arr21.Length != 2 || arr22.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
profileItem.address = arr22[0];
|
|
||||||
profileItem.port = Utils.ToInt(arr22[1]);
|
|
||||||
profileItem.security = arr21[0];
|
|
||||||
profileItem.id = arr21[1];
|
|
||||||
|
|
||||||
profileItem.network = Global.DefaultNetwork;
|
|
||||||
profileItem.headerType = Global.None;
|
|
||||||
profileItem.remarks = "Alien";
|
|
||||||
|
|
||||||
return profileItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveStdVmess(string result)
|
|
||||||
{
|
|
||||||
ProfileItem i = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.VMess,
|
|
||||||
security = "auto"
|
|
||||||
};
|
|
||||||
|
|
||||||
Uri u = new(result);
|
|
||||||
|
|
||||||
i.address = u.IdnHost;
|
|
||||||
i.port = u.Port;
|
|
||||||
i.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
|
||||||
var q = HttpUtility.ParseQueryString(u.Query);
|
|
||||||
|
|
||||||
var m = StdVmessUserInfo.Match(u.UserInfo);
|
|
||||||
if (!m.Success) return null;
|
|
||||||
|
|
||||||
i.id = m.Groups["id"].Value;
|
|
||||||
|
|
||||||
if (m.Groups["streamSecurity"].Success)
|
|
||||||
{
|
|
||||||
i.streamSecurity = m.Groups["streamSecurity"].Value;
|
|
||||||
}
|
|
||||||
switch (i.streamSecurity)
|
|
||||||
{
|
|
||||||
case "tls":
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (!string.IsNullOrWhiteSpace(i.streamSecurity))
|
|
||||||
return null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.network = m.Groups["network"].Value;
|
|
||||||
switch (i.network)
|
|
||||||
{
|
|
||||||
case "tcp":
|
|
||||||
string t1 = q["type"] ?? "none";
|
|
||||||
i.headerType = t1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "kcp":
|
|
||||||
i.headerType = q["type"] ?? "none";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "ws":
|
|
||||||
string p1 = q["path"] ?? "/";
|
|
||||||
string h1 = q["host"] ?? "";
|
|
||||||
i.requestHost = Utils.UrlDecode(h1);
|
|
||||||
i.path = p1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "http":
|
|
||||||
case "h2":
|
|
||||||
i.network = "h2";
|
|
||||||
string p2 = q["path"] ?? "/";
|
|
||||||
string h2 = q["host"] ?? "";
|
|
||||||
i.requestHost = Utils.UrlDecode(h2);
|
|
||||||
i.path = p2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "quic":
|
|
||||||
string s = q["security"] ?? "none";
|
|
||||||
string k = q["key"] ?? "";
|
|
||||||
string t3 = q["type"] ?? "none";
|
|
||||||
i.headerType = t3;
|
|
||||||
i.requestHost = Utils.UrlDecode(s);
|
|
||||||
i.path = k;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveSip002(string result)
|
|
||||||
{
|
|
||||||
Uri parsedUrl;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
parsedUrl = new Uri(result);
|
|
||||||
}
|
|
||||||
catch (UriFormatException)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ProfileItem server = new()
|
|
||||||
{
|
|
||||||
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
|
||||||
address = parsedUrl.IdnHost,
|
|
||||||
port = parsedUrl.Port,
|
|
||||||
};
|
|
||||||
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
|
|
||||||
//2022-blake3
|
|
||||||
if (rawUserInfo.Contains(':'))
|
|
||||||
{
|
|
||||||
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
|
||||||
if (userInfoParts.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
server.security = userInfoParts[0];
|
|
||||||
server.id = Utils.UrlDecode(userInfoParts[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// parse base64 UserInfo
|
|
||||||
string userInfo = Utils.Base64Decode(rawUserInfo);
|
|
||||||
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
|
||||||
if (userInfoParts.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
server.security = userInfoParts[0];
|
|
||||||
server.id = userInfoParts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query);
|
|
||||||
if (queryParameters["plugin"] != null)
|
|
||||||
{
|
|
||||||
//obfs-host exists
|
|
||||||
var obfsHost = queryParameters["plugin"].Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
|
||||||
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
|
|
||||||
{
|
|
||||||
obfsHost = obfsHost.Replace("obfs-host=", "");
|
|
||||||
server.network = Global.DefaultNetwork;
|
|
||||||
server.headerType = Global.TcpHeaderHttp;
|
|
||||||
server.requestHost = obfsHost;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
||||||
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveSSLegacy(string result)
|
|
||||||
{
|
|
||||||
var match = UrlFinder.Match(result);
|
|
||||||
if (!match.Success)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
ProfileItem server = new();
|
|
||||||
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
|
||||||
var tag = match.Groups["tag"].Value;
|
|
||||||
if (!Utils.IsNullOrEmpty(tag))
|
|
||||||
{
|
|
||||||
server.remarks = Utils.UrlDecode(tag);
|
|
||||||
}
|
|
||||||
Match details;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
details = DetailsParser.Match(Utils.Base64Decode(base64));
|
|
||||||
}
|
|
||||||
catch (FormatException)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!details.Success)
|
|
||||||
return null;
|
|
||||||
server.security = details.Groups["method"].Value;
|
|
||||||
server.id = details.Groups["password"].Value;
|
|
||||||
server.address = details.Groups["hostname"].Value;
|
|
||||||
server.port = Utils.ToInt(details.Groups["port"].Value);
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly Regex StdVmessUserInfo = new(
|
|
||||||
@"^(?<network>[a-z]+)(\+(?<streamSecurity>[a-z]+))?:(?<id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveSocks(string result)
|
|
||||||
{
|
|
||||||
ProfileItem profileItem = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.Socks
|
|
||||||
};
|
|
||||||
result = result[Global.ProtocolShares[EConfigType.Socks].Length..];
|
|
||||||
//remark
|
|
||||||
int indexRemark = result.IndexOf("#");
|
|
||||||
if (indexRemark > 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
result = result[..indexRemark];
|
|
||||||
}
|
|
||||||
//part decode
|
|
||||||
int indexS = result.IndexOf("@");
|
|
||||||
if (indexS > 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = Utils.Base64Decode(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] arr1 = result.Split('@');
|
|
||||||
if (arr1.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
string[] arr21 = arr1[0].Split(':');
|
|
||||||
//string[] arr22 = arr1[1].Split(':');
|
|
||||||
int indexPort = arr1[1].LastIndexOf(":");
|
|
||||||
if (arr21.Length != 2 || indexPort < 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
profileItem.address = arr1[1][..indexPort];
|
|
||||||
profileItem.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
|
||||||
profileItem.security = arr21[0];
|
|
||||||
profileItem.id = arr21[1];
|
|
||||||
|
|
||||||
return profileItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveSocksNew(string result)
|
|
||||||
{
|
|
||||||
Uri parsedUrl;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
parsedUrl = new Uri(result);
|
|
||||||
}
|
|
||||||
catch (UriFormatException)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ProfileItem server = new()
|
|
||||||
{
|
|
||||||
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
|
||||||
address = parsedUrl.IdnHost,
|
|
||||||
port = parsedUrl.Port,
|
|
||||||
};
|
|
||||||
|
|
||||||
// parse base64 UserInfo
|
|
||||||
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
|
|
||||||
string userInfo = Utils.Base64Decode(rawUserInfo);
|
|
||||||
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
|
||||||
if (userInfoParts.Length == 2)
|
|
||||||
{
|
|
||||||
server.security = userInfoParts[0];
|
|
||||||
server.id = userInfoParts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem ResolveTrojan(string result)
|
|
||||||
{
|
|
||||||
ProfileItem item = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.Trojan
|
|
||||||
};
|
|
||||||
|
|
||||||
Uri url = new(result);
|
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
|
||||||
item.port = url.Port;
|
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
|
||||||
item.id = url.UserInfo;
|
|
||||||
|
|
||||||
var query = HttpUtility.ParseQueryString(url.Query);
|
|
||||||
ResolveStdTransport(query, ref item);
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem ResolveStdVLESS(string result)
|
|
||||||
{
|
|
||||||
ProfileItem item = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.VLESS,
|
|
||||||
security = "none"
|
|
||||||
};
|
|
||||||
|
|
||||||
Uri url = new(result);
|
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
|
||||||
item.port = url.Port;
|
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
|
||||||
item.id = url.UserInfo;
|
|
||||||
|
|
||||||
var query = HttpUtility.ParseQueryString(url.Query);
|
|
||||||
item.security = query["encryption"] ?? "none";
|
|
||||||
item.streamSecurity = query["security"] ?? "";
|
|
||||||
ResolveStdTransport(query, ref item);
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem ResolveHysteria2(string result)
|
|
||||||
{
|
|
||||||
ProfileItem item = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.Hysteria2
|
|
||||||
};
|
|
||||||
|
|
||||||
Uri url = new(result);
|
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
|
||||||
item.port = url.Port;
|
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
|
||||||
item.id = url.UserInfo;
|
|
||||||
|
|
||||||
var query = HttpUtility.ParseQueryString(url.Query);
|
|
||||||
ResolveStdTransport(query, ref item);
|
|
||||||
item.allowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem ResolveTuic(string result)
|
|
||||||
{
|
|
||||||
ProfileItem item = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.Tuic
|
|
||||||
};
|
|
||||||
|
|
||||||
Uri url = new(result);
|
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
|
||||||
item.port = url.Port;
|
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
|
||||||
var userInfoParts = url.UserInfo.Split(new[] { ':' }, 2);
|
|
||||||
if (userInfoParts.Length == 2)
|
|
||||||
{
|
|
||||||
item.id = userInfoParts[0];
|
|
||||||
item.security = userInfoParts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
var query = HttpUtility.ParseQueryString(url.Query);
|
|
||||||
ResolveStdTransport(query, ref item);
|
|
||||||
item.headerType = query["congestion_control"] ?? "";
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
|
||||||
{
|
|
||||||
item.flow = query["flow"] ?? "";
|
|
||||||
item.streamSecurity = query["security"] ?? "";
|
|
||||||
item.sni = query["sni"] ?? "";
|
|
||||||
item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
|
|
||||||
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
|
|
||||||
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
|
||||||
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
|
||||||
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
|
||||||
|
|
||||||
item.network = query["type"] ?? "tcp";
|
|
||||||
switch (item.network)
|
|
||||||
{
|
|
||||||
case "tcp":
|
|
||||||
item.headerType = query["headerType"] ?? "none";
|
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "kcp":
|
|
||||||
item.headerType = query["headerType"] ?? "none";
|
|
||||||
item.path = Utils.UrlDecode(query["seed"] ?? "");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "ws":
|
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
|
||||||
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "http":
|
|
||||||
case "h2":
|
|
||||||
item.network = "h2";
|
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
|
||||||
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "quic":
|
|
||||||
item.headerType = query["headerType"] ?? "none";
|
|
||||||
item.requestHost = query["quicSecurity"] ?? "none";
|
|
||||||
item.path = Utils.UrlDecode(query["key"] ?? "");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "grpc":
|
|
||||||
item.path = Utils.UrlDecode(query["serviceName"] ?? "");
|
|
||||||
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcgunMode);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion ImportShareUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
using System.Diagnostics;
|
using ReactiveUI;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
internal class SpeedtestHandler
|
internal class SpeedtestHandler
|
||||||
{
|
{
|
||||||
private Config _config;
|
private Config? _config;
|
||||||
private CoreHandler _coreHandler;
|
private CoreHandler _coreHandler;
|
||||||
private List<ServerTestItem> _selecteds;
|
private List<ServerTestItem> _selecteds;
|
||||||
private ESpeedActionType _actionType;
|
private ESpeedActionType _actionType;
|
||||||
@@ -51,7 +52,6 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
switch (actionType)
|
switch (actionType)
|
||||||
{
|
{
|
||||||
case ESpeedActionType.Ping:
|
|
||||||
case ESpeedActionType.Tcping:
|
case ESpeedActionType.Tcping:
|
||||||
case ESpeedActionType.Realping:
|
case ESpeedActionType.Realping:
|
||||||
UpdateFunc(it.indexId, ResUI.Speedtesting, "");
|
UpdateFunc(it.indexId, ResUI.Speedtesting, "");
|
||||||
@@ -73,10 +73,6 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
switch (actionType)
|
switch (actionType)
|
||||||
{
|
{
|
||||||
case ESpeedActionType.Ping:
|
|
||||||
Task.Run(RunPing);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ESpeedActionType.Tcping:
|
case ESpeedActionType.Tcping:
|
||||||
Task.Run(RunTcping);
|
Task.Run(RunTcping);
|
||||||
break;
|
break;
|
||||||
@@ -95,52 +91,45 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunPingSubAsync(Action<ServerTestItem> updateFun)
|
private Task RunTcping()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (var it in _selecteds.Where(it => it.configType != EConfigType.Custom))
|
List<Task> tasks = [];
|
||||||
|
foreach (var it in _selecteds)
|
||||||
{
|
{
|
||||||
try
|
if (it.configType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
Task.Run(() => updateFun(it));
|
continue;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
tasks.Add(Task.Run(() =>
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
try
|
||||||
}
|
{
|
||||||
}
|
int time = GetTcpingTime(it.address, it.port);
|
||||||
|
var output = FormatOut(time, Global.DelayUnit);
|
||||||
|
|
||||||
await Task.Delay(10);
|
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
||||||
|
UpdateFunc(it.indexId, output);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Task.WaitAll([.. tasks]);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
finally
|
||||||
|
|
||||||
private async void RunPing()
|
|
||||||
{
|
|
||||||
await RunPingSubAsync((ServerTestItem it) =>
|
|
||||||
{
|
|
||||||
long time = Ping(it.address);
|
|
||||||
var output = FormatOut(time, Global.DelayUnit);
|
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
|
||||||
UpdateFunc(it.indexId, output);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void RunTcping()
|
|
||||||
{
|
|
||||||
await RunPingSubAsync((ServerTestItem it) =>
|
|
||||||
{
|
{
|
||||||
int time = GetTcpingTime(it.address, it.port);
|
ProfileExHandler.Instance.SaveTo();
|
||||||
var output = FormatOut(time, Global.DelayUnit);
|
}
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
return Task.CompletedTask;
|
||||||
UpdateFunc(it.indexId, output);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task RunRealPing()
|
private Task RunRealPing()
|
||||||
@@ -184,7 +173,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -192,7 +181,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -226,8 +215,24 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandle downloadHandle = new();
|
||||||
|
|
||||||
|
var exitLoop = false;
|
||||||
|
MessageBus.Current.Listen<string>(Global.CommandStopSpeedTest)
|
||||||
|
.Subscribe(x =>
|
||||||
|
{
|
||||||
|
if (!exitLoop)
|
||||||
|
{
|
||||||
|
UpdateFunc("", ResUI.SpeedtestingStop);
|
||||||
|
}
|
||||||
|
exitLoop = true;
|
||||||
|
});
|
||||||
|
|
||||||
foreach (var it in _selecteds)
|
foreach (var it in _selecteds)
|
||||||
{
|
{
|
||||||
|
if (exitLoop)
|
||||||
|
{
|
||||||
|
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!it.allowTest)
|
if (!it.allowTest)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -283,8 +288,25 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandle downloadHandle = new();
|
||||||
|
|
||||||
|
var exitLoop = false;
|
||||||
|
MessageBus.Current.Listen<string>(Global.CommandStopSpeedTest)
|
||||||
|
.Subscribe(x =>
|
||||||
|
{
|
||||||
|
if (!exitLoop)
|
||||||
|
{
|
||||||
|
UpdateFunc("", ResUI.SpeedtestingStop);
|
||||||
|
}
|
||||||
|
exitLoop = true;
|
||||||
|
});
|
||||||
|
|
||||||
foreach (var it in _selecteds)
|
foreach (var it in _selecteds)
|
||||||
{
|
{
|
||||||
|
if (exitLoop)
|
||||||
|
{
|
||||||
|
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!it.allowTest)
|
if (!it.allowTest)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -336,10 +358,10 @@ namespace v2rayN.Handler
|
|||||||
await RunSpeedTestMulti();
|
await RunSpeedTestMulti();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy)
|
private async Task<string> GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy)
|
||||||
{
|
{
|
||||||
int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10);
|
int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10);
|
||||||
//string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
|
//string output = Utile.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
|
||||||
return FormatOut(responseTime, Global.DelayUnit);
|
return FormatOut(responseTime, Global.DelayUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,70 +371,32 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!IPAddress.TryParse(url, out IPAddress ipAddress))
|
if (!IPAddress.TryParse(url, out IPAddress? ipAddress))
|
||||||
{
|
{
|
||||||
IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(url);
|
IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(url);
|
||||||
ipAddress = ipHostInfo.AddressList[0];
|
ipAddress = ipHostInfo.AddressList[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Stopwatch timer = new();
|
var timer = Stopwatch.StartNew();
|
||||||
timer.Start();
|
|
||||||
|
|
||||||
IPEndPoint endPoint = new(ipAddress, port);
|
IPEndPoint endPoint = new(ipAddress, port);
|
||||||
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
|
||||||
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
|
var result = clientSocket.BeginConnect(endPoint, null, null);
|
||||||
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
||||||
throw new TimeoutException("connect timeout (5s): " + url);
|
throw new TimeoutException("connect timeout (5s): " + url);
|
||||||
clientSocket.EndConnect(result);
|
clientSocket.EndConnect(result);
|
||||||
|
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
responseTime = (int)timer.Elapsed.TotalMilliseconds;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
return responseTime;
|
return responseTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ping
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="host"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public long Ping(string host)
|
|
||||||
{
|
|
||||||
long roundtripTime = -1;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int timeout = 30;
|
|
||||||
int echoNum = 2;
|
|
||||||
using Ping pingSender = new();
|
|
||||||
for (int i = 0; i < echoNum; i++)
|
|
||||||
{
|
|
||||||
PingReply reply = pingSender.Send(host, timeout);
|
|
||||||
if (reply.Status == IPStatus.Success)
|
|
||||||
{
|
|
||||||
if (reply.RoundtripTime < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (roundtripTime < 0 || reply.RoundtripTime < roundtripTime)
|
|
||||||
{
|
|
||||||
roundtripTime = reply.RoundtripTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return roundtripTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string FormatOut(object time, string unit)
|
private string FormatOut(object time, string unit)
|
||||||
{
|
{
|
||||||
//if (time.ToString().Equals("-1"))
|
//if (time.ToString().Equals("-1"))
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
using System.Net;
|
using v2rayN.Models;
|
||||||
using System.Net.Sockets;
|
|
||||||
using v2rayN.Base;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsHandler
|
internal class StatisticsHandler
|
||||||
{
|
{
|
||||||
|
private static readonly Lazy<StatisticsHandler> instance = new(() => new());
|
||||||
|
public static StatisticsHandler Instance => instance.Value;
|
||||||
|
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private ServerStatItem? _serverStatItem;
|
private ServerStatItem? _serverStatItem;
|
||||||
private List<ServerStatItem> _lstServerStat;
|
private List<ServerStatItem> _lstServerStat;
|
||||||
@@ -15,21 +15,17 @@ namespace v2rayN.Handler
|
|||||||
private StatisticsSingbox? _statisticsSingbox;
|
private StatisticsSingbox? _statisticsSingbox;
|
||||||
|
|
||||||
public List<ServerStatItem> ServerStat => _lstServerStat;
|
public List<ServerStatItem> ServerStat => _lstServerStat;
|
||||||
public bool Enable { get; set; }
|
|
||||||
|
|
||||||
public StatisticsHandler(Config config, Action<ServerSpeedItem> update)
|
public void Init(Config config, Action<ServerSpeedItem> update)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
Enable = config.guiItem.enableStatistics;
|
_updateFunc = update;
|
||||||
if (!Enable)
|
if (!config.guiItem.enableStatistics)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateFunc = update;
|
InitData();
|
||||||
|
|
||||||
Init();
|
|
||||||
Global.StatePort = GetFreePort();
|
|
||||||
|
|
||||||
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
|
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
|
||||||
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
|
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
|
||||||
@@ -44,13 +40,13 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearAllServerStatistics()
|
public void ClearAllServerStatistics()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.Execute($"delete from ServerStatItem ");
|
SQLiteHelper.Instance.Execute($"delete from ServerStatItem ");
|
||||||
_serverStatItem = null;
|
_serverStatItem = null;
|
||||||
_lstServerStat = new();
|
_lstServerStat = new();
|
||||||
}
|
}
|
||||||
@@ -59,28 +55,35 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.UpdateAll(_lstServerStat);
|
if (_lstServerStat != null)
|
||||||
|
{
|
||||||
|
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init()
|
private void InitData()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
|
SQLiteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
|
||||||
|
|
||||||
long ticks = DateTime.Now.Date.Ticks;
|
long ticks = DateTime.Now.Date.Ticks;
|
||||||
SqliteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
|
SQLiteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
|
||||||
|
|
||||||
_lstServerStat = SqliteHelper.Instance.Table<ServerStatItem>().ToList();
|
_lstServerStat = SQLiteHelper.Instance.Table<ServerStatItem>().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateServerStat(ServerSpeedItem server)
|
private void UpdateServerStat(ServerSpeedItem server)
|
||||||
{
|
{
|
||||||
GetServerStatItem(_config.indexId);
|
GetServerStatItem(_config.indexId);
|
||||||
|
|
||||||
|
if (_serverStatItem is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (server.proxyUp != 0 || server.proxyDown != 0)
|
if (server.proxyUp != 0 || server.proxyDown != 0)
|
||||||
{
|
{
|
||||||
_serverStatItem.todayUp += server.proxyUp;
|
_serverStatItem.todayUp += server.proxyUp;
|
||||||
@@ -88,15 +91,13 @@ namespace v2rayN.Handler
|
|||||||
_serverStatItem.totalUp += server.proxyUp;
|
_serverStatItem.totalUp += server.proxyUp;
|
||||||
_serverStatItem.totalDown += server.proxyDown;
|
_serverStatItem.totalDown += server.proxyDown;
|
||||||
}
|
}
|
||||||
if (Global.ShowInTaskbar)
|
|
||||||
{
|
server.indexId = _config.indexId;
|
||||||
server.indexId = _config.indexId;
|
server.todayUp = _serverStatItem.todayUp;
|
||||||
server.todayUp = _serverStatItem.todayUp;
|
server.todayDown = _serverStatItem.todayDown;
|
||||||
server.todayDown = _serverStatItem.todayDown;
|
server.totalUp = _serverStatItem.totalUp;
|
||||||
server.totalUp = _serverStatItem.totalUp;
|
server.totalDown = _serverStatItem.totalDown;
|
||||||
server.totalDown = _serverStatItem.totalDown;
|
_updateFunc(server);
|
||||||
_updateFunc(server);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetServerStatItem(string indexId)
|
private void GetServerStatItem(string indexId)
|
||||||
@@ -121,7 +122,7 @@ namespace v2rayN.Handler
|
|||||||
todayDown = 0,
|
todayDown = 0,
|
||||||
dateNow = ticks
|
dateNow = ticks
|
||||||
};
|
};
|
||||||
SqliteHelper.Instance.Replace(_serverStatItem);
|
SQLiteHelper.Instance.Replace(_serverStatItem);
|
||||||
_lstServerStat.Add(_serverStatItem);
|
_lstServerStat.Add(_serverStatItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,27 +134,5 @@ namespace v2rayN.Handler
|
|||||||
_serverStatItem.dateNow = ticks;
|
_serverStatItem.dateNow = ticks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetFreePort()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int defaultPort = 9090;
|
|
||||||
if (!Utils.PortInUse(defaultPort))
|
|
||||||
{
|
|
||||||
return defaultPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
TcpListener l = new(IPAddress.Loopback, 0);
|
|
||||||
l.Start();
|
|
||||||
int port = ((IPEndPoint)l.LocalEndpoint).Port;
|
|
||||||
l.Stop();
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return 69090;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsSingbox
|
internal class StatisticsSingbox
|
||||||
{
|
{
|
||||||
@@ -27,7 +28,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
url = $"ws://{Global.Loopback}:{Global.StatePort}/traffic";
|
url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort2}/traffic";
|
||||||
|
|
||||||
if (webSocket == null)
|
if (webSocket == null)
|
||||||
{
|
{
|
||||||
@@ -51,7 +52,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,8 +62,13 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
while (!_exitFlag)
|
while (!_exitFlag)
|
||||||
{
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!(_config.IsRunningCore(ECoreType.clash)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (webSocket != null)
|
if (webSocket != null)
|
||||||
{
|
{
|
||||||
if (webSocket.State == WebSocketState.Aborted
|
if (webSocket.State == WebSocketState.Aborted
|
||||||
@@ -84,7 +90,7 @@ namespace v2rayN.Handler
|
|||||||
while (!res.CloseStatus.HasValue)
|
while (!res.CloseStatus.HasValue)
|
||||||
{
|
{
|
||||||
var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
|
var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
|
||||||
if (!string.IsNullOrEmpty(result))
|
if (!Utils.IsNullOrEmpty(result))
|
||||||
{
|
{
|
||||||
ParseOutput(result, out ulong up, out ulong down);
|
ParseOutput(result, out ulong up, out ulong down);
|
||||||
|
|
||||||
@@ -101,10 +107,6 @@ namespace v2rayN.Handler
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
await Task.Delay(1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +115,7 @@ namespace v2rayN.Handler
|
|||||||
up = 0; down = 0;
|
up = 0; down = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var trafficItem = Utils.FromJson<TrafficItem>(source);
|
var trafficItem = JsonUtils.Deserialize<TrafficItem>(source);
|
||||||
if (trafficItem != null)
|
if (trafficItem != null)
|
||||||
{
|
{
|
||||||
up = trafficItem.up;
|
up = trafficItem.up;
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
using Grpc.Net.Client;
|
using Grpc.Net.Client;
|
||||||
using ProtosLib.Statistics;
|
using ProtosLib.Statistics;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsV2ray
|
internal class StatisticsV2ray
|
||||||
{
|
{
|
||||||
private Mode.Config _config;
|
private Models.Config _config;
|
||||||
private GrpcChannel? _channel;
|
private GrpcChannel? _channel;
|
||||||
private StatsService.StatsServiceClient? _client;
|
private StatsService.StatsServiceClient? _client;
|
||||||
private bool _exitFlag;
|
private bool _exitFlag;
|
||||||
private Action<ServerSpeedItem> _updateFunc;
|
private Action<ServerSpeedItem> _updateFunc;
|
||||||
|
|
||||||
public StatisticsV2ray(Mode.Config config, Action<ServerSpeedItem> update)
|
public StatisticsV2ray(Models.Config config, Action<ServerSpeedItem> update)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_updateFunc = update;
|
_updateFunc = update;
|
||||||
@@ -30,12 +31,12 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{Global.StatePort}");
|
_channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort}");
|
||||||
_client = new StatsService.StatsServiceClient(_channel);
|
_client = new StatsService.StatsServiceClient(_channel);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,14 +50,20 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
while (!_exitFlag)
|
while (!_exitFlag)
|
||||||
{
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!(_config.IsRunningCore(ECoreType.Xray)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (_channel?.State == ConnectivityState.Ready)
|
if (_channel?.State == ConnectivityState.Ready)
|
||||||
{
|
{
|
||||||
QueryStatsResponse? res = null;
|
QueryStatsResponse? res = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
|
if (_client != null)
|
||||||
|
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -68,8 +75,8 @@ namespace v2rayN.Handler
|
|||||||
_updateFunc(server);
|
_updateFunc(server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Task.Delay(1000);
|
if (_channel != null)
|
||||||
await _channel.ConnectAsync();
|
await _channel.ConnectAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -80,6 +87,8 @@ namespace v2rayN.Handler
|
|||||||
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
|
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
|
||||||
{
|
{
|
||||||
server = new();
|
server = new();
|
||||||
|
long aggregateProxyUp = 0;
|
||||||
|
long aggregateProxyDown = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (Stat stat in source)
|
foreach (Stat stat in source)
|
||||||
@@ -94,15 +103,15 @@ namespace v2rayN.Handler
|
|||||||
name = nStr[1];
|
name = nStr[1];
|
||||||
type = nStr[3];
|
type = nStr[3];
|
||||||
|
|
||||||
if (name == Global.ProxyTag)
|
if (name.StartsWith(Global.ProxyTag))
|
||||||
{
|
{
|
||||||
if (type == "uplink")
|
if (type == "uplink")
|
||||||
{
|
{
|
||||||
server.proxyUp = value;
|
aggregateProxyUp += value;
|
||||||
}
|
}
|
||||||
else if (type == "downlink")
|
else if (type == "downlink")
|
||||||
{
|
{
|
||||||
server.proxyDown = value;
|
aggregateProxyDown += value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (name == Global.DirectTag)
|
else if (name == Global.DirectTag)
|
||||||
@@ -117,6 +126,8 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
server.proxyUp = aggregateProxyUp;
|
||||||
|
server.proxyDown = aggregateProxyDown;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -1,38 +1,17 @@
|
|||||||
using PacLib;
|
using PacLib;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Common;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
public static class SysProxyHandle
|
public static class SysProxyHandle
|
||||||
{
|
{
|
||||||
//private const string _userWininetConfigFile = "user-wininet.json";
|
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
|
||||||
|
|
||||||
//private static string _queryStr;
|
|
||||||
|
|
||||||
// In general, this won't change
|
|
||||||
// format:
|
|
||||||
// <flags><CR-LF>
|
|
||||||
// <proxy-server><CR-LF>
|
|
||||||
// <bypass-list><CR-LF>
|
|
||||||
// <pac-url>
|
|
||||||
|
|
||||||
private enum RET_ERRORS : int
|
|
||||||
{
|
|
||||||
RET_NO_ERROR = 0,
|
|
||||||
INVALID_FORMAT = 1,
|
|
||||||
NO_PERMISSION = 2,
|
|
||||||
SYSCALL_FAILED = 3,
|
|
||||||
NO_MEMORY = 4,
|
|
||||||
INVAILD_OPTION_COUNT = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
static SysProxyHandle()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool UpdateSysProxy(Config config, bool forceDisable)
|
public static bool UpdateSysProxy(Config config, bool forceDisable)
|
||||||
{
|
{
|
||||||
var type = config.sysProxyType;
|
var type = config.systemProxyItem.sysProxyType;
|
||||||
|
|
||||||
if (forceDisable && type != ESysProxyType.Unchanged)
|
if (forceDisable && type != ESysProxyType.Unchanged)
|
||||||
{
|
{
|
||||||
@@ -41,34 +20,38 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int port = LazyConfig.Instance.GetLocalPort(Global.InboundHttp);
|
int port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
|
||||||
int portSocks = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
|
int portSocks = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
int portPac = LazyConfig.Instance.GetLocalPort(ESysProxyType.Pac.ToString());
|
int portPac = LazyConfig.Instance.GetLocalPort(EInboundProtocol.pac);
|
||||||
if (port <= 0)
|
if (port <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (type == ESysProxyType.ForcedChange)
|
if (type == ESysProxyType.ForcedChange)
|
||||||
{
|
{
|
||||||
var strExceptions = $"{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}";
|
var strExceptions = "";
|
||||||
|
if (config.systemProxyItem.notProxyLocalAddress)
|
||||||
|
{
|
||||||
|
strExceptions = $"<local>;{config.constItem.defIEProxyExceptions};{config.systemProxyItem.systemProxyExceptions}";
|
||||||
|
}
|
||||||
|
|
||||||
var strProxy = string.Empty;
|
var strProxy = string.Empty;
|
||||||
if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol))
|
if (Utils.IsNullOrEmpty(config.systemProxyItem.systemProxyAdvancedProtocol))
|
||||||
{
|
{
|
||||||
strProxy = $"{Global.Loopback}:{port}";
|
strProxy = $"{Global.Loopback}:{port}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strProxy = config.systemProxyAdvancedProtocol
|
strProxy = config.systemProxyItem.systemProxyAdvancedProtocol
|
||||||
.Replace("{ip}", Global.Loopback)
|
.Replace("{ip}", Global.Loopback)
|
||||||
.Replace("{http_port}", port.ToString())
|
.Replace("{http_port}", port.ToString())
|
||||||
.Replace("{socks_port}", portSocks.ToString());
|
.Replace("{socks_port}", portSocks.ToString());
|
||||||
}
|
}
|
||||||
ProxySetting.SetProxy(strProxy, strExceptions, 2); // set a named proxy
|
ProxySetting.SetProxy(strProxy, strExceptions, 2);
|
||||||
}
|
}
|
||||||
else if (type == ESysProxyType.ForcedClear)
|
else if (type == ESysProxyType.ForcedClear)
|
||||||
{
|
{
|
||||||
ProxySetting.UnsetProxy(); // set to no proxy
|
ProxySetting.UnsetProxy();
|
||||||
}
|
}
|
||||||
else if (type == ESysProxyType.Unchanged)
|
else if (type == ESysProxyType.Unchanged)
|
||||||
{
|
{
|
||||||
@@ -77,7 +60,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
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}";
|
||||||
ProxySetting.SetProxy(strProxy, "", 4); // use pac script url for auto-config proxy
|
ProxySetting.SetProxy(strProxy, "", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != ESysProxyType.Pac)
|
if (type != ESysProxyType.Pac)
|
||||||
@@ -87,21 +70,14 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ResetIEProxy4WindowsShutDown()
|
public static void ResetIEProxy4WindowsShutDown()
|
||||||
{
|
{
|
||||||
try
|
ProxySetting.UnsetProxy();
|
||||||
{
|
|
||||||
//TODO To be verified
|
|
||||||
Utils.RegWriteValue(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", "ProxyEnable", 0);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,9 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using v2rayN.Base;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
using v2rayN.Tool;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
@@ -56,7 +55,7 @@ namespace v2rayN.Handler
|
|||||||
StartInfo = new ProcessStartInfo
|
StartInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = "v2rayUpgrade.exe",
|
FileName = "v2rayUpgrade.exe",
|
||||||
Arguments = $"\"{fileName}\"",
|
Arguments = fileName.AppendQuotes(),
|
||||||
WorkingDirectory = Utils.StartupPath()
|
WorkingDirectory = Utils.StartupPath()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -88,7 +87,10 @@ namespace v2rayN.Handler
|
|||||||
_updateFunc(false, args.Msg);
|
_updateFunc(false, args.Msg);
|
||||||
|
|
||||||
url = args.Url;
|
url = args.Url;
|
||||||
_ = askToDownload(downloadHandle, url, true);
|
AskToDownload(downloadHandle, url, true).ContinueWith(task =>
|
||||||
|
{
|
||||||
|
_updateFunc(false, url);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -141,7 +143,10 @@ namespace v2rayN.Handler
|
|||||||
_updateFunc(false, args.Msg);
|
_updateFunc(false, args.Msg);
|
||||||
|
|
||||||
url = args.Url;
|
url = args.Url;
|
||||||
_ = askToDownload(downloadHandle, url, true);
|
AskToDownload(downloadHandle, url, true).ContinueWith(task =>
|
||||||
|
{
|
||||||
|
_updateFunc(false, url);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -203,7 +208,7 @@ namespace v2rayN.Handler
|
|||||||
//convert
|
//convert
|
||||||
if (!Utils.IsNullOrEmpty(item.convertTarget))
|
if (!Utils.IsNullOrEmpty(item.convertTarget))
|
||||||
{
|
{
|
||||||
var subConvertUrl = string.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
|
var subConvertUrl = Utils.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
|
||||||
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
|
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
|
||||||
if (!url.Contains("target="))
|
if (!url.Contains("target="))
|
||||||
{
|
{
|
||||||
@@ -223,7 +228,7 @@ namespace v2rayN.Handler
|
|||||||
//more url
|
//more url
|
||||||
if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
|
if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result))
|
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result!))
|
||||||
{
|
{
|
||||||
result = Utils.Base64Decode(result);
|
result = Utils.Base64Decode(result);
|
||||||
}
|
}
|
||||||
@@ -247,7 +252,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(result2))
|
if (!Utils.IsNullOrEmpty(result2))
|
||||||
{
|
{
|
||||||
if (Utils.IsBase64String(result2))
|
if (Utils.IsBase64String(result2!))
|
||||||
{
|
{
|
||||||
result += Utils.Base64Decode(result2);
|
result += Utils.Base64Decode(result2);
|
||||||
}
|
}
|
||||||
@@ -266,7 +271,7 @@ namespace v2rayN.Handler
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
|
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
|
||||||
if (result!.Length < 99)
|
if (result?.Length < 99)
|
||||||
{
|
{
|
||||||
_updateFunc(false, $"{hashCode}{result}");
|
_updateFunc(false, $"{hashCode}{result}");
|
||||||
}
|
}
|
||||||
@@ -274,8 +279,8 @@ namespace v2rayN.Handler
|
|||||||
int ret = ConfigHandler.AddBatchServers(config, result, id, true);
|
int ret = ConfigHandler.AddBatchServers(config, result, id, true);
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("FailedImportSubscription");
|
Logging.SaveLog("FailedImportSubscription");
|
||||||
Utils.SaveLog(result);
|
Logging.SaveLog(result);
|
||||||
}
|
}
|
||||||
_updateFunc(false,
|
_updateFunc(false,
|
||||||
ret > 0
|
ret > 0
|
||||||
@@ -295,9 +300,6 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
await UpdateGeoFile("geosite", _config, update);
|
await UpdateGeoFile("geosite", _config, update);
|
||||||
await UpdateGeoFile("geoip", _config, update);
|
await UpdateGeoFile("geoip", _config, update);
|
||||||
|
|
||||||
//await UpdateGeoFile4Singbox("geosite", _config, false, update);
|
|
||||||
//await UpdateGeoFile4Singbox("geoip", _config, true, update);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,17 +325,17 @@ namespace v2rayN.Handler
|
|||||||
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
|
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
|
||||||
if (!Utils.IsNullOrEmpty(result))
|
if (!Utils.IsNullOrEmpty(result))
|
||||||
{
|
{
|
||||||
responseHandler(type, result, preRelease);
|
ResponseHandler(type, result, preRelease);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.SaveLog("StatusCode error: " + url);
|
Logging.SaveLog("StatusCode error: " + url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
_updateFunc(false, ex.Message);
|
_updateFunc(false, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -341,7 +343,7 @@ namespace v2rayN.Handler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取V2RayCore版本
|
/// 获取V2RayCore版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private SemanticVersion getCoreVersion(ECoreType type)
|
private SemanticVersion GetCoreVersion(ECoreType type)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -350,7 +352,7 @@ namespace v2rayN.Handler
|
|||||||
foreach (string name in coreInfo.coreExes)
|
foreach (string name in coreInfo.coreExes)
|
||||||
{
|
{
|
||||||
string vName = $"{name}.exe";
|
string vName = $"{name}.exe";
|
||||||
vName = Utils.GetBinPath(vName, coreInfo.coreType);
|
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
|
||||||
if (File.Exists(vName))
|
if (File.Exists(vName))
|
||||||
{
|
{
|
||||||
filePath = vName;
|
filePath = vName;
|
||||||
@@ -366,7 +368,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
using Process p = new();
|
using Process p = new();
|
||||||
p.StartInfo.FileName = filePath;
|
p.StartInfo.FileName = filePath.AppendQuotes();
|
||||||
p.StartInfo.Arguments = coreInfo.versionArg;
|
p.StartInfo.Arguments = coreInfo.versionArg;
|
||||||
p.StartInfo.WorkingDirectory = Utils.StartupPath();
|
p.StartInfo.WorkingDirectory = Utils.StartupPath();
|
||||||
p.StartInfo.UseShellExecute = false;
|
p.StartInfo.UseShellExecute = false;
|
||||||
@@ -388,6 +390,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
case ECoreType.clash:
|
case ECoreType.clash:
|
||||||
case ECoreType.clash_meta:
|
case ECoreType.clash_meta:
|
||||||
|
case ECoreType.mihomo:
|
||||||
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
|
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -399,20 +402,20 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
_updateFunc(false, ex.Message);
|
_updateFunc(false, ex.Message);
|
||||||
return new SemanticVersion("");
|
return new SemanticVersion("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
private void ResponseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gitHubReleases = Utils.FromJson<List<GitHubRelease>>(gitHubReleaseApi);
|
var gitHubReleases = JsonUtils.Deserialize<List<GitHubRelease>>(gitHubReleaseApi);
|
||||||
var gitHubRelease = preRelease ? gitHubReleases!.First() : gitHubReleases!.First(r => r.Prerelease == false);
|
var gitHubRelease = preRelease ? gitHubReleases?.First() : gitHubReleases?.First(r => r.Prerelease == false);
|
||||||
var version = new SemanticVersion(gitHubRelease!.TagName);
|
var version = new SemanticVersion(gitHubRelease?.TagName!);
|
||||||
var body = gitHubRelease!.Body;
|
var body = gitHubRelease?.Body;
|
||||||
|
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
||||||
|
|
||||||
@@ -426,7 +429,7 @@ namespace v2rayN.Handler
|
|||||||
case ECoreType.Xray:
|
case ECoreType.Xray:
|
||||||
case ECoreType.v2fly_v5:
|
case ECoreType.v2fly_v5:
|
||||||
{
|
{
|
||||||
curVersion = getCoreVersion(type);
|
curVersion = GetCoreVersion(type);
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
||||||
string osBit = "64";
|
string osBit = "64";
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
switch (RuntimeInformation.ProcessArchitecture)
|
||||||
@@ -449,8 +452,9 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
case ECoreType.clash:
|
case ECoreType.clash:
|
||||||
case ECoreType.clash_meta:
|
case ECoreType.clash_meta:
|
||||||
|
case ECoreType.mihomo:
|
||||||
{
|
{
|
||||||
curVersion = getCoreVersion(type);
|
curVersion = GetCoreVersion(type);
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion);
|
message = string.Format(ResUI.IsLatestCore, type, curVersion);
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
switch (RuntimeInformation.ProcessArchitecture)
|
||||||
{
|
{
|
||||||
@@ -471,7 +475,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
case ECoreType.sing_box:
|
case ECoreType.sing_box:
|
||||||
{
|
{
|
||||||
curVersion = getCoreVersion(type);
|
curVersion = GetCoreVersion(type);
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
switch (RuntimeInformation.ProcessArchitecture)
|
||||||
{
|
{
|
||||||
@@ -524,12 +528,12 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
_updateFunc(false, ex.Message);
|
_updateFunc(false, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task askToDownload(DownloadHandle downloadHandle, string url, bool blAsk)
|
private async Task AskToDownload(DownloadHandle downloadHandle, string url, bool blAsk)
|
||||||
{
|
{
|
||||||
bool blDownload = false;
|
bool blDownload = false;
|
||||||
if (blAsk)
|
if (blAsk)
|
||||||
@@ -569,7 +573,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
//Global.coreTypes.ForEach(it =>
|
//Global.coreTypes.ForEach(it =>
|
||||||
//{
|
//{
|
||||||
// string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
|
// string targetPath = Utile.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
|
||||||
// File.Copy(fileName, targetPath, true);
|
// File.Copy(fileName, targetPath, true);
|
||||||
//});
|
//});
|
||||||
string targetPath = Utils.GetBinPath($"{geoName}.dat");
|
string targetPath = Utils.GetBinPath($"{geoName}.dat");
|
||||||
@@ -593,55 +597,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
_updateFunc(false, args.GetException().Message);
|
_updateFunc(false, args.GetException().Message);
|
||||||
};
|
};
|
||||||
await askToDownload(downloadHandle, url, false);
|
await AskToDownload(downloadHandle, url, false);
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateGeoFile4Singbox(string geoName, Config config, bool needStop, Action<bool, string> update)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = update;
|
|
||||||
var url = string.Format(Global.SingboxGeoUrl, geoName);
|
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
|
||||||
downloadHandle.UpdateCompleted += async (sender2, args) =>
|
|
||||||
{
|
|
||||||
if (args.Success)
|
|
||||||
{
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
|
|
||||||
var coreHandler = Locator.Current.GetService<CoreHandler>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (needStop)
|
|
||||||
{
|
|
||||||
coreHandler?.CoreStop();
|
|
||||||
await Task.Delay(3000);
|
|
||||||
}
|
|
||||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
{
|
|
||||||
string targetPath = Utils.GetConfigPath($"{geoName}.db");
|
|
||||||
File.Copy(fileName, targetPath, true);
|
|
||||||
|
|
||||||
File.Delete(fileName);
|
|
||||||
}
|
|
||||||
if (needStop) coreHandler?.LoadCore();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
downloadHandle.Error += (sender2, args) =>
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.GetException().Message);
|
|
||||||
};
|
|
||||||
await askToDownload(downloadHandle, url, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion private
|
#endregion private
|
||||||
|
|||||||
@@ -1,440 +0,0 @@
|
|||||||
namespace v2rayN.Mode
|
|
||||||
{
|
|
||||||
[Serializable]
|
|
||||||
public class ConfigOld
|
|
||||||
{
|
|
||||||
#region property
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 允许日志
|
|
||||||
/// </summary>
|
|
||||||
public bool logEnabled
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 日志等级
|
|
||||||
/// </summary>
|
|
||||||
public string loglevel
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string indexId
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 允许Mux多路复用
|
|
||||||
/// </summary>
|
|
||||||
public bool muxEnabled
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public ESysProxyType sysProxyType
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用实时网速和流量统计
|
|
||||||
/// </summary>
|
|
||||||
public bool enableStatistics
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 去重时优先保留较旧(顶部)节点
|
|
||||||
/// </summary>
|
|
||||||
public bool keepOlderDedupl
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 视图刷新率
|
|
||||||
/// </summary>
|
|
||||||
public int statisticsFreshRate
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 自定义远程DNS
|
|
||||||
/// </summary>
|
|
||||||
public string remoteDNS
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Outbound Freedom domainStrategy
|
|
||||||
/// </summary>
|
|
||||||
public string domainStrategy4Freedom
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否允许不安全连接
|
|
||||||
/// </summary>
|
|
||||||
public bool defAllowInsecure
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 域名解析策略
|
|
||||||
/// </summary>
|
|
||||||
public string domainStrategy
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string domainMatcher
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int routingIndex
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool enableRoutingAdvanced
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ignoreGeoUpdateCore
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// systemProxyExceptions
|
|
||||||
/// </summary>
|
|
||||||
public string systemProxyExceptions
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string systemProxyAdvancedProtocol { get; set; }
|
|
||||||
|
|
||||||
public int autoUpdateInterval { get; set; } = 0;
|
|
||||||
|
|
||||||
public int autoUpdateSubInterval { get; set; } = 0;
|
|
||||||
|
|
||||||
public bool checkPreReleaseUpdate { get; set; } = false;
|
|
||||||
|
|
||||||
public bool enableSecurityProtocolTls13
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int trayMenuServersLimit { get; set; }
|
|
||||||
|
|
||||||
#endregion property
|
|
||||||
|
|
||||||
#region other entities
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 本地监听
|
|
||||||
/// </summary>
|
|
||||||
public List<InItem> inbound
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// vmess服务器信息
|
|
||||||
/// </summary>
|
|
||||||
public List<VmessItem> vmess
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// KcpItem
|
|
||||||
/// </summary>
|
|
||||||
public KcpItem kcpItem
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 订阅
|
|
||||||
/// </summary>
|
|
||||||
public List<SubItem> subItem
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// UI
|
|
||||||
/// </summary>
|
|
||||||
public UIItem uiItem
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RoutingItemOld> routings
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConstItem constItem
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<KeyEventItem> globalHotkeys
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<CoreTypeItem> coreTypeItem
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion other entities
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class VmessItem
|
|
||||||
{
|
|
||||||
public VmessItem()
|
|
||||||
{
|
|
||||||
indexId = string.Empty;
|
|
||||||
configType = EConfigType.VMess;
|
|
||||||
configVersion = 2;
|
|
||||||
sort = 0;
|
|
||||||
address = string.Empty;
|
|
||||||
port = 0;
|
|
||||||
id = string.Empty;
|
|
||||||
alterId = 0;
|
|
||||||
security = string.Empty;
|
|
||||||
network = string.Empty;
|
|
||||||
remarks = string.Empty;
|
|
||||||
headerType = string.Empty;
|
|
||||||
requestHost = string.Empty;
|
|
||||||
path = string.Empty;
|
|
||||||
streamSecurity = string.Empty;
|
|
||||||
allowInsecure = string.Empty;
|
|
||||||
testResult = string.Empty;
|
|
||||||
subid = string.Empty;
|
|
||||||
flow = string.Empty;
|
|
||||||
groupId = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string indexId
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// config type(1=normal,2=custom)
|
|
||||||
/// </summary>
|
|
||||||
public EConfigType configType
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 版本(现在=2)
|
|
||||||
/// </summary>
|
|
||||||
public int configVersion
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int sort
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 远程服务器地址
|
|
||||||
/// </summary>
|
|
||||||
public string address
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 远程服务器端口
|
|
||||||
/// </summary>
|
|
||||||
public int port
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 远程服务器ID
|
|
||||||
/// </summary>
|
|
||||||
public string id
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 远程服务器额外ID
|
|
||||||
/// </summary>
|
|
||||||
public int alterId
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 本地安全策略
|
|
||||||
/// </summary>
|
|
||||||
public string security
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// tcp,kcp,ws,h2,quic
|
|
||||||
/// </summary>
|
|
||||||
public string network
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string remarks
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 伪装类型
|
|
||||||
/// </summary>
|
|
||||||
public string headerType
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 伪装的域名
|
|
||||||
/// </summary>
|
|
||||||
public string requestHost
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ws h2 path
|
|
||||||
/// </summary>
|
|
||||||
public string path
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 传输层安全
|
|
||||||
/// </summary>
|
|
||||||
public string streamSecurity
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否允许不安全连接(用于客户端)
|
|
||||||
/// </summary>
|
|
||||||
public string allowInsecure
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string testResult
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// SubItem id
|
|
||||||
/// </summary>
|
|
||||||
public string subid
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// VLESS flow
|
|
||||||
/// </summary>
|
|
||||||
public string flow
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// tls sni
|
|
||||||
/// </summary>
|
|
||||||
public string sni
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string groupId
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
} = string.Empty;
|
|
||||||
|
|
||||||
public ECoreType? coreType
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int preSocksPort
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string fingerprint { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class RoutingItemOld
|
|
||||||
{
|
|
||||||
public string remarks
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string url
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RulesItem> rules
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool enabled { get; set; } = true;
|
|
||||||
|
|
||||||
public bool locked
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string customIcon
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
|
||||||
{
|
|
||||||
public class GitHubReleaseAsset
|
|
||||||
{
|
|
||||||
[JsonProperty("url")] public string Url { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("id")] public int Id { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("node_id")] public string NodeId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("name")] public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("label")] public object Label { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("content_type")] public string ContentType { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("state")] public string State { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("size")] public int Size { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("download_count")] public int DownloadCount { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("created_at")] public DateTime CreatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("updated_at")] public DateTime UpdatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("browser_download_url")] public string BrowserDownloadUrl { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GitHubRelease
|
|
||||||
{
|
|
||||||
[JsonProperty("url")] public string Url { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("assets_url")] public string AssetsUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("upload_url")] public string UploadUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("html_url")] public string HtmlUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("id")] public int Id { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("node_id")] public string NodeId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("tag_name")] public string TagName { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("target_commitish")] public string TargetCommitish { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("name")] public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("draft")] public bool Draft { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("prerelease")] public bool Prerelease { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("created_at")] public DateTime CreatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("published_at")] public DateTime PublishedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("assets")] public List<GitHubReleaseAsset> Assets { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("tarball_url")] public string TarballUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("zipball_url")] public string ZipballUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("body")] public string Body { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
namespace v2rayN.Mode
|
|
||||||
{
|
|
||||||
[Serializable]
|
|
||||||
public class RulesItem
|
|
||||||
{
|
|
||||||
public string id { get; set; }
|
|
||||||
public string type { get; set; }
|
|
||||||
|
|
||||||
public string port { get; set; }
|
|
||||||
|
|
||||||
public List<string> inboundTag { get; set; }
|
|
||||||
|
|
||||||
public string outboundTag { get; set; }
|
|
||||||
|
|
||||||
public List<string> ip { get; set; }
|
|
||||||
|
|
||||||
public List<string> domain { get; set; }
|
|
||||||
|
|
||||||
public List<string> protocol { get; set; }
|
|
||||||
|
|
||||||
public List<string> process { get; set; }
|
|
||||||
|
|
||||||
public bool enabled { get; set; } = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
namespace v2rayN.Mode
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// https://github.com/2dust/v2rayN/wiki/
|
|
||||||
/// </summary>
|
|
||||||
[Serializable]
|
|
||||||
internal class VmessQRCode
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string v { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string ps { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string add { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string port { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string id { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string aid { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string scy { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string net { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string type { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string host { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string path { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TLS
|
|
||||||
/// </summary>
|
|
||||||
public string tls { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TLS SNI
|
|
||||||
/// </summary>
|
|
||||||
public string sni { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TLS alpn
|
|
||||||
/// </summary>
|
|
||||||
public string alpn { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TLS fingerprint
|
|
||||||
/// </summary>
|
|
||||||
public string fp { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
17
v2rayN/v2rayN/Models/ClashConnectionModel.cs
Normal file
17
v2rayN/v2rayN/Models/ClashConnectionModel.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class ClashConnectionModel
|
||||||
|
{
|
||||||
|
public string id { get; set; }
|
||||||
|
public string network { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string host { get; set; }
|
||||||
|
public ulong upload { get; set; }
|
||||||
|
public ulong download { get; set; }
|
||||||
|
public string uploadTraffic { get; set; }
|
||||||
|
public string downloadTraffic { get; set; }
|
||||||
|
public double time { get; set; }
|
||||||
|
public string elapsed { get; set; }
|
||||||
|
public string chain { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
37
v2rayN/v2rayN/Models/ClashConnections.cs
Normal file
37
v2rayN/v2rayN/Models/ClashConnections.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class ClashConnections
|
||||||
|
{
|
||||||
|
public ulong downloadTotal { get; set; }
|
||||||
|
public ulong uploadTotal { get; set; }
|
||||||
|
public List<ConnectionItem>? connections { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConnectionItem
|
||||||
|
{
|
||||||
|
public string id { get; set; } = string.Empty;
|
||||||
|
public MetadataItem metadata { get; set; }
|
||||||
|
public ulong upload { get; set; }
|
||||||
|
public ulong download { get; set; }
|
||||||
|
public DateTime start { get; set; }
|
||||||
|
public List<string>? chains { get; set; }
|
||||||
|
public string rule { get; set; }
|
||||||
|
public string rulePayload { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MetadataItem
|
||||||
|
{
|
||||||
|
public string network { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string sourceIP { get; set; }
|
||||||
|
public string destinationIP { get; set; }
|
||||||
|
public string sourcePort { get; set; }
|
||||||
|
public string destinationPort { get; set; }
|
||||||
|
public string host { get; set; }
|
||||||
|
public string nsMode { get; set; }
|
||||||
|
public object uid { get; set; }
|
||||||
|
public string process { get; set; }
|
||||||
|
public string processPath { get; set; }
|
||||||
|
public string remoteDestination { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
17
v2rayN/v2rayN/Models/ClashProviders.cs
Normal file
17
v2rayN/v2rayN/Models/ClashProviders.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using static v2rayN.Models.ClashProxies;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class ClashProviders
|
||||||
|
{
|
||||||
|
public Dictionary<String, ProvidersItem> providers { get; set; }
|
||||||
|
|
||||||
|
public class ProvidersItem
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public ProxiesItem[] proxies { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string vehicleType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
v2rayN/v2rayN/Models/ClashProxies.cs
Normal file
24
v2rayN/v2rayN/Models/ClashProxies.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class ClashProxies
|
||||||
|
{
|
||||||
|
public Dictionary<String, ProxiesItem> proxies { get; set; }
|
||||||
|
|
||||||
|
public class ProxiesItem
|
||||||
|
{
|
||||||
|
public string[] all { get; set; }
|
||||||
|
public List<HistoryItem> history { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public bool udp { get; set; }
|
||||||
|
public string now { get; set; }
|
||||||
|
public int delay { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HistoryItem
|
||||||
|
{
|
||||||
|
public string time { get; set; }
|
||||||
|
public int delay { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
v2rayN/v2rayN/Models/ClashProxyModel.cs
Normal file
26
v2rayN/v2rayN/Models/ClashProxyModel.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class ClashProxyModel
|
||||||
|
{
|
||||||
|
[Reactive]
|
||||||
|
public string name { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string type { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string now { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public int delay { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string delayName { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool isActive { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public class ComboItem
|
public class ComboItem
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace v2rayN.Mode
|
using v2rayN.Enums;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 本软件配置文件实体类
|
/// 本软件配置文件实体类
|
||||||
@@ -10,10 +12,24 @@
|
|||||||
|
|
||||||
public string indexId { get; set; }
|
public string indexId { get; set; }
|
||||||
public string subIndexId { get; set; }
|
public string subIndexId { get; set; }
|
||||||
public ESysProxyType sysProxyType { get; set; }
|
|
||||||
public string systemProxyExceptions { get; set; }
|
public string systemProxyExceptions { get; set; }
|
||||||
public string systemProxyAdvancedProtocol { get; set; }
|
public string systemProxyAdvancedProtocol { get; set; }
|
||||||
|
|
||||||
|
public ECoreType runningCoreType { get; set; }
|
||||||
|
|
||||||
|
public bool IsRunningCore(ECoreType type)
|
||||||
|
{
|
||||||
|
if (type == ECoreType.Xray && runningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5 or ECoreType.SagerNet)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (type == ECoreType.clash && runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion property
|
#endregion property
|
||||||
|
|
||||||
#region other entities
|
#region other entities
|
||||||
@@ -29,6 +45,8 @@
|
|||||||
public SpeedTestItem speedTestItem { get; set; }
|
public SpeedTestItem speedTestItem { get; set; }
|
||||||
public Mux4SboxItem mux4SboxItem { get; set; }
|
public Mux4SboxItem mux4SboxItem { get; set; }
|
||||||
public HysteriaItem hysteriaItem { get; set; }
|
public HysteriaItem hysteriaItem { get; set; }
|
||||||
|
public ClashUIItem clashUIItem { get; set; }
|
||||||
|
public SystemProxyItem systemProxyItem { get; set; }
|
||||||
public List<InItem> inbound { get; set; }
|
public List<InItem> inbound { get; set; }
|
||||||
public List<KeyEventItem> globalHotkeys { get; set; }
|
public List<KeyEventItem> globalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> coreTypeItem { get; set; }
|
public List<CoreTypeItem> coreTypeItem { get; set; }
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreBasicItem
|
public class CoreBasicItem
|
||||||
@@ -31,6 +32,10 @@ namespace v2rayN.Mode
|
|||||||
/// 默认用户代理
|
/// 默认用户代理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string defUserAgent { get; set; }
|
public string defUserAgent { get; set; }
|
||||||
|
|
||||||
|
public bool enableFragment { get; set; }
|
||||||
|
|
||||||
|
public bool enableCacheFile4Sbox { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -43,8 +48,8 @@ namespace v2rayN.Mode
|
|||||||
public bool udpEnabled { get; set; }
|
public bool udpEnabled { get; set; }
|
||||||
|
|
||||||
public bool sniffingEnabled { get; set; } = true;
|
public bool sniffingEnabled { get; set; } = true;
|
||||||
|
public List<string>? destOverride { get; set; } = ["http", "tls"];
|
||||||
public bool routeOnly { get; set; }
|
public bool routeOnly { get; set; }
|
||||||
|
|
||||||
public bool allowLANConn { get; set; }
|
public bool allowLANConn { get; set; }
|
||||||
|
|
||||||
public bool newPort4LAN { get; set; }
|
public bool newPort4LAN { get; set; }
|
||||||
@@ -109,10 +114,12 @@ namespace v2rayN.Mode
|
|||||||
public class UIItem
|
public class UIItem
|
||||||
{
|
{
|
||||||
public bool enableAutoAdjustMainLvColWidth { get; set; }
|
public bool enableAutoAdjustMainLvColWidth { get; set; }
|
||||||
|
public bool enableUpdateSubOnlyRemarksExist { get; set; }
|
||||||
public double mainWidth { get; set; }
|
public double mainWidth { get; set; }
|
||||||
public double mainHeight { get; set; }
|
public double mainHeight { get; set; }
|
||||||
public double mainGirdHeight1 { get; set; }
|
public double mainGirdHeight1 { get; set; }
|
||||||
public double mainGirdHeight2 { get; set; }
|
public double mainGirdHeight2 { get; set; }
|
||||||
|
public EGirdOrientation mainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||||
public bool colorModeDark { get; set; }
|
public bool colorModeDark { get; set; }
|
||||||
public bool followSystemTheme { get; set; }
|
public bool followSystemTheme { get; set; }
|
||||||
public string? colorPrimaryName { get; set; }
|
public string? colorPrimaryName { get; set; }
|
||||||
@@ -121,10 +128,10 @@ namespace v2rayN.Mode
|
|||||||
public int currentFontSize { get; set; }
|
public int currentFontSize { get; set; }
|
||||||
public bool enableDragDropSort { get; set; }
|
public bool enableDragDropSort { get; set; }
|
||||||
public bool doubleClick2Activate { get; set; }
|
public bool doubleClick2Activate { get; set; }
|
||||||
public bool autoHideStartup { get; set; } = true;
|
public bool autoHideStartup { get; set; }
|
||||||
public string mainMsgFilter { get; set; }
|
public string mainMsgFilter { get; set; }
|
||||||
public bool showTrayTip { get; set; }
|
|
||||||
public List<ColumnItem> mainColumnItem { get; set; }
|
public List<ColumnItem> mainColumnItem { get; set; }
|
||||||
|
public bool showInTaskbar { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -164,7 +171,7 @@ namespace v2rayN.Mode
|
|||||||
public string stack { get; set; }
|
public string stack { get; set; }
|
||||||
public int mtu { get; set; }
|
public int mtu { get; set; }
|
||||||
public bool enableExInbound { get; set; }
|
public bool enableExInbound { get; set; }
|
||||||
public bool enableIPv6Address { get; set; } = true;
|
public bool enableIPv6Address { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -178,13 +185,8 @@ namespace v2rayN.Mode
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingBasicItem
|
public class RoutingBasicItem
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 域名解析策略
|
|
||||||
/// </summary>
|
|
||||||
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 domainMatcher { get; set; }
|
||||||
public string routingIndexId { get; set; }
|
public string routingIndexId { get; set; }
|
||||||
public bool enableRoutingAdvanced { get; set; }
|
public bool enableRoutingAdvanced { get; set; }
|
||||||
@@ -203,9 +205,6 @@ namespace v2rayN.Mode
|
|||||||
{
|
{
|
||||||
public string protocol { get; set; }
|
public string protocol { get; set; }
|
||||||
public int max_connections { get; set; }
|
public int max_connections { get; set; }
|
||||||
public int min_streams { get; set; }
|
|
||||||
public int max_streams { get; set; }
|
|
||||||
public bool padding { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -214,4 +213,27 @@ namespace v2rayN.Mode
|
|||||||
public int up_mbps { get; set; }
|
public int up_mbps { get; set; }
|
||||||
public int down_mbps { get; set; }
|
public int down_mbps { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ClashUIItem
|
||||||
|
{
|
||||||
|
public ERuleMode ruleMode { get; set; }
|
||||||
|
public bool enableIPv6 { get; set; }
|
||||||
|
public bool enableMixinContent { get; set; }
|
||||||
|
public int proxiesSorting { get; set; }
|
||||||
|
public bool proxiesAutoRefresh { get; set; }
|
||||||
|
public int proxiesAutoDelayTestInterval { get; set; } = 10;
|
||||||
|
public int connectionsSorting { get; set; }
|
||||||
|
public bool connectionsAutoRefresh { get; set; }
|
||||||
|
public int connectionsRefreshInterval { get; set; } = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class SystemProxyItem
|
||||||
|
{
|
||||||
|
public ESysProxyType sysProxyType { get; set; }
|
||||||
|
public string systemProxyExceptions { get; set; }
|
||||||
|
public bool notProxyLocalAddress { get; set; } = true;
|
||||||
|
public string systemProxyAdvancedProtocol { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace v2rayN.Mode
|
using v2rayN.Enums;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreInfo
|
public class CoreInfo
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class DNSItem
|
public class DNSItem
|
||||||
@@ -15,5 +16,6 @@ namespace v2rayN.Mode
|
|||||||
public string? normalDNS { get; set; }
|
public string? normalDNS { get; set; }
|
||||||
public string? tunDNS { get; set; }
|
public string? tunDNS { get; set; }
|
||||||
public string? domainStrategy4Freedom { get; set; }
|
public string? domainStrategy4Freedom { get; set; }
|
||||||
|
public string? domainDNSAddress { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
68
v2rayN/v2rayN/Models/GitHubRelease.cs
Normal file
68
v2rayN/v2rayN/Models/GitHubRelease.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class GitHubReleaseAsset
|
||||||
|
{
|
||||||
|
[JsonPropertyName("url")] public string Url { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("node_id")] public string NodeId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")] public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("label")] public object Label { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("content_type")] public string ContentType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("state")] public string State { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("size")] public int Size { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("download_count")] public int DownloadCount { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("updated_at")] public DateTime UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("browser_download_url")] public string BrowserDownloadUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GitHubRelease
|
||||||
|
{
|
||||||
|
[JsonPropertyName("url")] public string Url { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("assets_url")] public string AssetsUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("upload_url")] public string UploadUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("html_url")] public string HtmlUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("node_id")] public string NodeId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("tag_name")] public string TagName { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("target_commitish")] public string TargetCommitish { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")] public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("draft")] public bool Draft { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("prerelease")] public bool Prerelease { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("published_at")] public DateTime PublishedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("assets")] public List<GitHubReleaseAsset> Assets { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("tarball_url")] public string TarballUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("zipball_url")] public string ZipballUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("body")] public string Body { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileExItem
|
public class ProfileExItem
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using v2rayN.Base;
|
using v2rayN.Enums;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItem
|
public class ProfileItem
|
||||||
@@ -48,18 +48,12 @@ namespace v2rayN.Mode
|
|||||||
}
|
}
|
||||||
switch (configType)
|
switch (configType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.Custom:
|
||||||
case EConfigType.Shadowsocks:
|
summary += string.Format("[{1}]{0}", remarks, coreType.ToString());
|
||||||
case EConfigType.Socks:
|
|
||||||
case EConfigType.VLESS:
|
|
||||||
case EConfigType.Trojan:
|
|
||||||
case EConfigType.Hysteria2:
|
|
||||||
case EConfigType.Tuic:
|
|
||||||
summary += string.Format("{0}({1}:{2})", remarks, addr, port);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
summary += string.Format("{0}", remarks);
|
summary += string.Format("{0}({1}:{2})", remarks, addr, port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return summary;
|
return summary;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItemModel : ProfileItem
|
public class ProfileItemModel : ProfileItem
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItem
|
public class RoutingItem
|
||||||
@@ -15,6 +15,7 @@ namespace v2rayN.Mode
|
|||||||
public bool enabled { get; set; } = true;
|
public bool enabled { get; set; } = true;
|
||||||
public bool locked { get; set; }
|
public bool locked { get; set; }
|
||||||
public string customIcon { get; set; }
|
public string customIcon { get; set; }
|
||||||
|
public string customRulesetPath4Singbox { get; set; }
|
||||||
public string domainStrategy { get; set; }
|
public string domainStrategy { get; set; }
|
||||||
public string domainStrategy4Singbox { get; set; }
|
public string domainStrategy4Singbox { get; set; }
|
||||||
public int sort { get; set; }
|
public int sort { get; set; }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItemModel : RoutingItem
|
public class RoutingItemModel : RoutingItem
|
||||||
26
v2rayN/v2rayN/Models/RulesItem.cs
Normal file
26
v2rayN/v2rayN/Models/RulesItem.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class RulesItem
|
||||||
|
{
|
||||||
|
public string id { get; set; }
|
||||||
|
public string? type { get; set; }
|
||||||
|
|
||||||
|
public string? port { get; set; }
|
||||||
|
public string? network { get; set; }
|
||||||
|
|
||||||
|
public List<string>? inboundTag { get; set; }
|
||||||
|
|
||||||
|
public string? outboundTag { get; set; }
|
||||||
|
|
||||||
|
public List<string>? ip { get; set; }
|
||||||
|
|
||||||
|
public List<string>? domain { get; set; }
|
||||||
|
|
||||||
|
public List<string>? protocol { get; set; }
|
||||||
|
|
||||||
|
public List<string>? process { get; set; }
|
||||||
|
|
||||||
|
public bool enabled { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RulesItemModel : RulesItem
|
public class RulesItemModel : RulesItem
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class ServerSpeedItem : ServerStatItem
|
public class ServerSpeedItem : ServerStatItem
|
||||||
{
|
{
|
||||||
public long proxyUp
|
public long proxyUp
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ServerStatItem
|
public class ServerStatItem
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace v2rayN.Mode
|
using v2rayN.Enums;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class ServerTestItem
|
internal class ServerTestItem
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public class SingboxConfig
|
public class SingboxConfig
|
||||||
{
|
{
|
||||||
public Log4Sbox log { get; set; }
|
public Log4Sbox log { get; set; }
|
||||||
public object dns { get; set; }
|
public Dns4Sbox? dns { get; set; }
|
||||||
public List<Inbound4Sbox> inbounds { get; set; }
|
public List<Inbound4Sbox> inbounds { get; set; }
|
||||||
public List<Outbound4Sbox> outbounds { get; set; }
|
public List<Outbound4Sbox> outbounds { get; set; }
|
||||||
public Route4Sbox route { get; set; }
|
public Route4Sbox route { get; set; }
|
||||||
public Experimental4Sbox experimental { get; set; }
|
public Experimental4Sbox? experimental { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Log4Sbox
|
public class Log4Sbox
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
public bool? disabled { get; set; }
|
public bool? disabled { get; set; }
|
||||||
public string level { get; set; }
|
public string level { get; set; }
|
||||||
public string output { get; set; }
|
public string output { get; set; }
|
||||||
public bool timestamp { get; set; }
|
public bool? timestamp { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Dns4Sbox
|
public class Dns4Sbox
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
public bool? disable_expire { get; set; }
|
public bool? disable_expire { get; set; }
|
||||||
public bool? independent_cache { get; set; }
|
public bool? independent_cache { get; set; }
|
||||||
public bool? reverse_mapping { get; set; }
|
public bool? reverse_mapping { get; set; }
|
||||||
|
public string? client_subnet { get; set; }
|
||||||
public Fakeip4Sbox? fakeip { get; set; }
|
public Fakeip4Sbox? fakeip { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,19 +36,24 @@
|
|||||||
{
|
{
|
||||||
public bool? auto_detect_interface { get; set; }
|
public bool? auto_detect_interface { get; set; }
|
||||||
public List<Rule4Sbox> rules { get; set; }
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
|
public List<Ruleset4Sbox>? rule_set { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Rule4Sbox
|
public class Rule4Sbox
|
||||||
{
|
{
|
||||||
public string outbound { get; set; }
|
public string? outbound { get; set; }
|
||||||
public string server { get; set; }
|
public string? server { get; set; }
|
||||||
public bool? disable_cache { get; set; }
|
public bool? disable_cache { get; set; }
|
||||||
|
public string? type { get; set; }
|
||||||
|
public string? mode { get; set; }
|
||||||
|
public bool? ip_is_private { get; set; }
|
||||||
|
public string? client_subnet { get; set; }
|
||||||
|
public bool? invert { get; set; }
|
||||||
|
public string? clash_mode { get; set; }
|
||||||
public List<string>? inbound { get; set; }
|
public List<string>? inbound { get; set; }
|
||||||
public List<string>? protocol { get; set; }
|
public List<string>? protocol { get; set; }
|
||||||
public string type { get; set; }
|
public List<string>? network { get; set; }
|
||||||
public string mode { get; set; }
|
|
||||||
public string network { get; set; }
|
|
||||||
public List<int>? port { get; set; }
|
public List<int>? port { get; set; }
|
||||||
public List<string>? port_range { get; set; }
|
public List<string>? port_range { get; set; }
|
||||||
public List<string>? geosite { get; set; }
|
public List<string>? geosite { get; set; }
|
||||||
@@ -58,8 +64,9 @@
|
|||||||
public List<string>? geoip { get; set; }
|
public List<string>? geoip { get; set; }
|
||||||
public List<string>? ip_cidr { get; set; }
|
public List<string>? ip_cidr { get; set; }
|
||||||
public List<string>? source_ip_cidr { get; set; }
|
public List<string>? source_ip_cidr { get; set; }
|
||||||
|
|
||||||
public List<string>? process_name { get; set; }
|
public List<string>? process_name { get; set; }
|
||||||
|
public List<string>? rule_set { get; set; }
|
||||||
|
public List<Rule4Sbox>? rules { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -93,7 +100,7 @@
|
|||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
public string server { get; set; }
|
public string? server { get; set; }
|
||||||
public int? server_port { get; set; }
|
public int? server_port { get; set; }
|
||||||
public string uuid { get; set; }
|
public string uuid { get; set; }
|
||||||
public string security { get; set; }
|
public string security { get; set; }
|
||||||
@@ -112,10 +119,20 @@
|
|||||||
public string congestion_control { get; set; }
|
public string congestion_control { get; set; }
|
||||||
public string? version { get; set; }
|
public string? version { get; set; }
|
||||||
public string? network { get; set; }
|
public string? network { get; set; }
|
||||||
public string packet_encoding { get; set; }
|
public string? packet_encoding { get; set; }
|
||||||
public Tls4Sbox tls { get; set; }
|
public string[]? local_address { get; set; }
|
||||||
public Multiplex4Sbox multiplex { get; set; }
|
public string? private_key { get; set; }
|
||||||
public Transport4Sbox transport { get; set; }
|
public string? peer_public_key { get; set; }
|
||||||
|
public int[]? reserved { get; set; }
|
||||||
|
public int? mtu { get; set; }
|
||||||
|
public string? plugin { get; set; }
|
||||||
|
public string? plugin_opts { get; set; }
|
||||||
|
public Tls4Sbox? tls { get; set; }
|
||||||
|
public Multiplex4Sbox? multiplex { get; set; }
|
||||||
|
public Transport4Sbox? transport { get; set; }
|
||||||
|
public HyObfs4Sbox? obfs { get; set; }
|
||||||
|
public List<string>? outbounds { get; set; }
|
||||||
|
public bool? interrupt_exist_connections { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Tls4Sbox
|
public class Tls4Sbox
|
||||||
@@ -133,9 +150,6 @@
|
|||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
public string protocol { get; set; }
|
public string protocol { get; set; }
|
||||||
public int max_connections { get; set; }
|
public int max_connections { get; set; }
|
||||||
public int min_streams { get; set; }
|
|
||||||
public int max_streams { get; set; }
|
|
||||||
public bool padding { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Utls4Sbox
|
public class Utls4Sbox
|
||||||
@@ -153,14 +167,14 @@
|
|||||||
|
|
||||||
public class Transport4Sbox
|
public class Transport4Sbox
|
||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public List<string>? host { get; set; }
|
public object? host { get; set; }
|
||||||
public string? path { get; set; }
|
public string? path { get; set; }
|
||||||
public Headers4Sbox? headers { get; set; }
|
public Headers4Sbox? headers { get; set; }
|
||||||
|
|
||||||
public string service_name { get; set; }
|
public string? service_name { get; set; }
|
||||||
public string idle_timeout { get; set; }
|
public string? idle_timeout { get; set; }
|
||||||
public string ping_timeout { get; set; }
|
public string? ping_timeout { get; set; }
|
||||||
public bool? permit_without_stream { get; set; }
|
public bool? permit_without_stream { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,13 +183,21 @@
|
|||||||
public string? Host { get; set; }
|
public string? Host { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class HyObfs4Sbox
|
||||||
|
{
|
||||||
|
public string? type { get; set; }
|
||||||
|
public string? password { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Server4Sbox
|
public class Server4Sbox
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string? tag { get; set; }
|
||||||
public string address { get; set; }
|
public string? address { get; set; }
|
||||||
public string address_resolver { get; set; }
|
public string? address_resolver { get; set; }
|
||||||
public string strategy { get; set; }
|
public string? address_strategy { get; set; }
|
||||||
public string detour { get; set; }
|
public string? strategy { get; set; }
|
||||||
|
public string? detour { get; set; }
|
||||||
|
public string? client_subnet { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Experimental4Sbox
|
public class Experimental4Sbox
|
||||||
@@ -219,4 +241,15 @@
|
|||||||
public string? cache_id { get; set; }
|
public string? cache_id { get; set; }
|
||||||
public bool? store_fakeip { get; set; }
|
public bool? store_fakeip { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Ruleset4Sbox
|
||||||
|
{
|
||||||
|
public string? tag { get; set; }
|
||||||
|
public string? type { get; set; }
|
||||||
|
public string? format { get; set; }
|
||||||
|
public string? path { get; set; }
|
||||||
|
public string? url { get; set; }
|
||||||
|
public string? download_detour { get; set; }
|
||||||
|
public string? update_interval { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public class SsSIP008
|
public class SsSIP008
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class SubItem
|
public class SubItem
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user