Compare commits

...

110 Commits
6.42 ... 6.54

Author SHA1 Message Date
2dust
7ede3af762 up 6.54 2024-08-03 16:02:42 +08:00
2dust
97ea1c7a9e Add toolTip 2024-08-03 15:59:00 +08:00
2dust
43bb2c0fb8 Bug fix
https://github.com/2dust/v2rayN/issues/5462
2024-08-03 15:37:47 +08:00
2dust
6e7196bb27 Bug fix
https://github.com/2dust/v2rayN/issues/5437
2024-07-31 20:13:41 +08:00
2dust
87a71d58e8 Fix
https://github.com/2dust/v2rayN/issues/5438
2024-07-30 16:22:54 +08:00
2dust
32ffd43fe3 Bug fix
https://github.com/2dust/v2rayN/issues/5425
2024-07-30 16:06:43 +08:00
2dust
6500c8d85e up 6.53 2024-07-26 11:05:53 +08:00
2dust
9866d436da Add Outbound DNS address
https://github.com/2dust/v2rayN/issues/5387
2024-07-26 11:00:07 +08:00
2dust
0f4884d9d8 Improve and refactor the code 2024-07-25 10:26:39 +08:00
2dust
5a81441351 Adjust resx 2024-07-24 20:14:07 +08:00
2dust
e8721bfb6b Default dns changed to whitelist 2024-07-24 20:01:26 +08:00
2dust
1b09d95209 Improve UI 2024-07-24 19:51:13 +08:00
Jabin Kong
35f3b5a50e 1 (#5394) 2024-07-23 20:41:00 +08:00
2dust
ff5203a561 alpn h2,h3 2024-07-23 20:33:02 +08:00
2dust
c3c1ced309 up 6.52 2024-07-21 15:15:51 +08:00
2dust
08b1c8ec83 Improve latency testing 2024-07-21 15:15:00 +08:00
NagisaEfi
1dd3ee4e0a Update English translations (#5381)
* Update ResUI.resx

* Update ResUI.resx
2024-07-21 11:48:55 +08:00
Random Guy
06d0c6517d fix: add real delay test for custom config (#5377) 2024-07-21 11:44:12 +08:00
2dust
4938ce6364 Code clean 2024-07-21 11:37:11 +08:00
2dust
25f3fc354f Add multi-server load balancing 2024-07-21 11:26:10 +08:00
2dust
ad1a1f8015 Main window layout orientation setting 2024-07-19 20:31:07 +08:00
2dust
5c070e2ca8 Improve UI 2024-07-19 10:51:14 +08:00
2dust
70ea21fca2 Improve UI 2024-07-18 19:59:46 +08:00
2dust
bc3593871b Refactor the main interface 2024-07-18 17:39:11 +08:00
2dust
355a424be2 Code clean 2024-07-18 17:31:49 +08:00
2dust
0ffa9a0cc8 Remove unused resx
Remove Batch export subscription to clipboard
2024-07-15 20:17:55 +08:00
2dust
72fecb2b9a Add clash_mode to rule 2024-07-14 20:17:48 +08:00
2dust
4e9dfe5478 Improve 2024-07-14 17:16:07 +08:00
2dust
c79e2e3ad4 Add functionality multi-server set as active
Implemented using sing-box Selector, which can be switched using the clash api
2024-07-14 16:13:28 +08:00
2dust
7c33c1c322 Add reload for ClashProxiesView 2024-07-14 14:28:45 +08:00
2dust
ea32f75925 Code clean 2024-07-14 11:00:22 +08:00
2dust
7eaed21b9a Improve 2024-07-14 10:59:36 +08:00
2dust
cfe8fcd28d up 6.51 2024-07-12 14:23:29 +08:00
2dust
9f4718af70 Code clean
Add allowInsecure to Share
2024-07-11 14:42:01 +08:00
2dust
39faccfd0b Bug fix 2024-07-10 17:32:26 +08:00
2dust
7545763dae Default domain strategy for resolving the outbound domain names -- singbox 2024-07-08 18:45:29 +08:00
2dust
c2928be35d Log messages are not displayed when in the background 2024-07-08 17:16:49 +08:00
2dust
449bb40d48 sing-box prioritizes the use of local srs 2024-07-08 14:20:41 +08:00
2dust
4caf1a1e63 Improve and refactor the code 2024-07-08 09:52:11 +08:00
2dust
01b205e6f1 Adjust information DispatcherPriority 2024-07-07 21:11:04 +08:00
2dust
160d3843a6 Bug fix 2024-07-05 15:28:28 +08:00
2dust
5efb784115 up 6.50 2024-07-05 11:18:36 +08:00
2dust
acde5b8384 Bug fix 2024-07-05 11:18:14 +08:00
2dust
373ee6586a Optimize system proxy code 2024-07-04 17:07:05 +08:00
2dust
215308c329 Change srs source
https://github.com/2dust/sing-box-rules
2024-07-04 16:27:44 +08:00
2dust
478cadba5e Bug fix 2024-06-30 20:43:06 +08:00
2dust
f4af4da791 Adjust res 2024-06-30 10:00:28 +08:00
2dust
22d4f435de Add tun and mixin functions to clash 2024-06-28 20:29:44 +08:00
2dust
ccb8cd5c04 up 6.49 2024-06-28 16:14:45 +08:00
2dust
e963f9e349 Add clash display in the main interface 2024-06-28 16:14:19 +08:00
2dust
e3c2a4b8da Bug fix 2024-06-28 10:41:17 +08:00
2dust
324f46cdad Bug fix
https://github.com/2dust/v2rayN/discussions/5268
2024-06-27 17:59:39 +08:00
2dust
691b19b5fd Adding support for the clash proxies interface 2024-06-27 16:36:36 +08:00
2dust
63ed2311dc Bug fix 2024-06-26 16:00:37 +08:00
2dust
d59e59ca40 up 6.48 2024-06-24 17:42:37 +08:00
2dust
c9a278b4a2 Check for updates mihomo 2024-06-24 17:41:53 +08:00
2dust
8ee5304148 Bug fix 2024-06-24 16:42:17 +08:00
2dust
3beaa8145f Bug fix 2024-06-24 16:19:00 +08:00
2dust
e30c55a0af up 6.47 2024-06-24 15:34:41 +08:00
2dust
b583590a64 Update ConfigHandler.cs
https://github.com/2dust/v2rayN/pull/5264
2024-06-24 15:25:00 +08:00
OnceUponATimeInAmerica
a28c63168a Support for setting subs-group remarks (group's name) from the (optional) "remark" query parameter in the pasted subs url (#5264) 2024-06-24 15:20:16 +08:00
2dust
620422350f Improved tun mode
Enabling tun mode.
Only one core will be run when using sing-box core;
When using a non-sing-box, the sing-box will be used to start an additional front Socks service to provide a tun entry, which will then run two cores
2024-06-24 15:19:42 +08:00
2dust
b77cc3c33b Add network attribute to route rule
https://github.com/2dust/v2rayN/discussions/5256
2024-06-22 16:44:15 +08:00
2dust
71bf9b4887 up 6.46 2024-06-21 16:02:08 +08:00
2dust
9039d401da set DOTNET_EnableWriteXorExecute=0 under win10
https://github.com/2dust/v2rayN/issues/5186
2024-06-21 14:09:57 +08:00
2dust
74a0a93201 Improve and refactor the code 2024-06-21 11:15:35 +08:00
2dust
522571f0b3 Add splithttp transport for xray
https://github.com/XTLS/Xray-core/releases/tag/v1.8.15
2024-06-20 16:20:05 +08:00
Lsyx-Good
123c49c22d Adjust singbox DNS server and rule position (#5229) 2024-06-20 16:08:08 +08:00
OnceUponATimeInAmerica
1ff88d29be Extend stats reporting to support custom configs with several load-balanced outbounds in them, with tags starting with "proxy" e.g. proxy1, proxy2 (fully compatible with existing configs) (#5225) 2024-06-20 15:32:10 +08:00
Lsyx-Good
63d5a2a1be Fix bug (#5213) 2024-06-10 15:12:39 +08:00
2dust
1e9a6cb06b Refactor code 2024-06-04 09:48:04 +08:00
2dust
31748aa660 Refactor code 2024-06-03 17:50:18 +08:00
2dust
d0c6ea6a63 remove http://cachefly.cachefly.net/100mb.test 2024-06-03 14:06:59 +08:00
2dust
7ffe286a56 Up PackageReference 2024-06-03 07:37:49 +08:00
2dust
b99b30163b Bug fix 2024-06-03 07:37:26 +08:00
kirilllivanov
83b4f1e660 Fix incorrect filenames (#5122) 2024-05-18 17:11:38 +08:00
2dust
b57ba6a98b up 6.45 2024-05-18 09:53:15 +08:00
2dust
d748e6eff4 Add destOverride 2024-05-14 15:31:19 +08:00
2dust
315d4b75b2 Optimize code 2024-05-14 13:42:42 +08:00
2dust
31267cbc33 Adjust Scan screen qrcode 2024-05-12 17:07:56 +08:00
2dust
c23379b3b6 Adjust sing-box dns 2024-05-12 15:42:28 +08:00
2dust
568144d6a2 TransitionAssist DisableTransitions 2024-05-12 14:59:23 +08:00
2dust
5857042963 Up 6.44 2024-05-08 13:40:24 +08:00
2dust
28e41dc621 Add open the file location 2024-05-08 11:43:03 +08:00
2dust
baef3b364b Bug fix 2024-05-08 11:42:01 +08:00
2dust
4b9ddb803f Bug fix 2024-05-07 14:15:08 +08:00
2dust
c07c7ad82f Added reminder that a reboot is required to modify settings 2024-05-06 17:19:29 +08:00
2dust
e223b80b95 Merge pull request #5066 from sincereliu/master
Optimize code for better performance
2024-05-06 09:55:30 +08:00
sincere liu
5fe468fa1b Optimize code for better performance 2024-05-05 22:07:51 +08:00
2dust
60068d8d16 Themes migrate 2024-05-05 16:19:47 +08:00
2dust
b6c5b46afe Up PackageReference 2024-05-05 10:10:19 +08:00
2dust
124cbfadb4 Add custom sing-box rule-set support 2024-05-04 13:54:22 +08:00
2dust
8d21f9b900 Bug fix 2024-05-04 13:24:13 +08:00
2dust
398dbbd2e5 Bug fix
https://github.com/2dust/v2rayN/issues/5035
2024-05-03 10:29:32 +08:00
2dust
e9b392d1c0 Optimized sorted storage 2024-04-30 14:44:02 +08:00
2dust
9d7c7e3225 Adjust the experimental and mux of sing-box 2024-04-27 10:05:13 +08:00
2dust
855fd4f0b7 Merge pull request #5026 from GibMeMyPacket/feat/singbox/exp_cachefile
Add `Enable cache file for sing-box`
2024-04-27 09:42:31 +08:00
GibMeMyPacket
807839929d Add Enable cache file for sing-box 2024-04-25 12:07:53 +00:00
2dust
870955fee1 Bug fix 2024-04-11 08:07:21 +08:00
2dust
e0cea929ea Up 6.43 2024-04-10 13:52:38 +08:00
2dust
315f4c35f0 Code clean 2024-04-10 13:32:50 +08:00
2dust
d961ea22a6 Built-in routing rule set upgraded to V2 2024-04-10 10:50:52 +08:00
2dust
5c0c07c78f Migrate geosite & geoip to rule sets (sing-box) 2024-04-10 08:42:53 +08:00
2dust
bba93a0fb7 Added tls fragment support (Xray-core)
https://github.com/2dust/v2rayN/issues/4900
2024-04-08 17:06:48 +08:00
2dust
5683df2fc0 Added outbound HTTP support (support group prefix proxy)
https://github.com/2dust/v2rayN/discussions/4550
2024-04-08 14:02:56 +08:00
2dust
b5cb9ce67e Set autoHideStartup default value is false 2024-04-05 17:24:53 +08:00
2dust
06a32dc895 Adjust sing-box dns default example 2024-04-05 11:05:45 +08:00
2dust
dff12a8a3a fix
https://github.com/2dust/v2rayN/issues/4928
2024-04-05 11:04:35 +08:00
2dust
dc3f07ee84 Bug fix 2024-04-03 09:51:07 +08:00
2dust
1aef49ee11 Custom configuration file to use Xray prefix in non-Tun mode
https://github.com/2dust/v2rayN/issues/4855
2024-04-01 08:22:14 +08:00
132 changed files with 8969 additions and 5443 deletions

View File

@@ -9,9 +9,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.26.1" />
<PackageReference Include="Grpc.Net.Client" Version="2.62.0" />
<PackageReference Include="Grpc.Tools" Version="2.62.0">
<PackageReference Include="Google.Protobuf" Version="3.27.3" />
<PackageReference Include="Grpc.Net.Client" Version="2.65.0" />
<PackageReference Include="Grpc.Tools" Version="2.65.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,9 +1,9 @@
<Application
x:Class="v2rayN.App"
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:conv="clr-namespace:v2rayN.Converters"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
ShutdownMode="OnExplicitShutdown"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
@@ -13,13 +13,14 @@
BaseTheme="Light"
PrimaryColor="Blue"
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>
<system:Double x:Key="MenuItemHeight">26</system:Double>
<system:Double x:Key="StdFontSize">12</system:Double>
<system:Double x:Key="StdFontSize1">13</system:Double>
<system:Double x:Key="StdFontSize2">14</system:Double>
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
<system:Double x:Key="StdFontSize-1">11</system:Double>
<conv:InverseBooleanConverter x:Key="InverseBooleanConverter" />
<Thickness
@@ -61,23 +62,26 @@
</Style>
<Style TargetType="{x:Type TextElement}">
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
</Style>
<Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}">
<Setter Property="Height" Value="20" />
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{DynamicResource PrimaryHueMidBrush}" />
</Trigger>
</Style.Triggers>
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<materialDesign:Card Name="_Card" SnapsToDevicePixels="true">
<ContentPresenter />
</materialDesign:Card>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="_Card" Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="GridViewColumnHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
@@ -156,6 +160,27 @@
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
<Setter Property="Padding" Value="{StaticResource OutlinedTextBoxDefaultPadding}" />
</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>
</Application.Resources>
</Application>

View File

@@ -43,6 +43,7 @@ namespace v2rayN
Init();
Logging.LoggingEnabled(_config.guiItem.enableLog);
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
Logging.ClearLogs();
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
@@ -58,10 +59,12 @@ namespace v2rayN
Environment.Exit(0);
return;
}
//if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64)
//{
// _config.guiItem.enableStatistics = false;
//}
//Under Win10
if (Environment.OSVersion.Version.Major < 10)
{
Environment.SetEnvironmentVariable("DOTNET_EnableWriteXorExecute", "0", EnvironmentVariableTarget.User);
}
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)

View File

@@ -1,5 +1,6 @@
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
@@ -21,6 +22,22 @@ namespace v2rayN
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)
{
if (Utils.IsNullOrEmpty(url)) return null;
@@ -41,6 +58,21 @@ namespace v2rayN
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)
{
ArgumentNullException.ThrowIfNull(url);

View File

@@ -105,9 +105,12 @@ namespace v2rayN
/// <param name="filePath"></param>
/// <param name="nullValue"></param>
/// <returns></returns>
public static int ToFile(object? obj, string filePath, bool nullValue = true)
public static int ToFile(object? obj, string? filePath, bool nullValue = true)
{
int result;
if (filePath is null)
{
return -1;
}
try
{
using FileStream file = File.Create(filePath);
@@ -119,14 +122,13 @@ namespace v2rayN
};
JsonSerializer.Serialize(file, obj, options);
result = 0;
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
result = -1;
return -1;
}
return result;
}
}
}

View File

@@ -1,10 +1,38 @@
using System.Runtime.InteropServices;
using static v2rayN.Handler.ProxySetting.InternetConnectionOption;
using static v2rayN.Common.ProxySetting.InternetConnectionOption;
namespace v2rayN.Handler
namespace v2rayN.Common
{
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>
// set to use no proxy
/// </summary>
@@ -29,15 +57,24 @@ namespace v2rayN.Handler
/// <returns>true: one of connection is successfully updated proxy settings</returns>
public static bool SetProxy(string? strProxy, string? exceptions, int 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)
try
{
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)
@@ -94,25 +131,25 @@ namespace v2rayN.Handler
}
else
{
list.szConnection = IntPtr.Zero;
list.szConnection = nint.Zero;
}
list.dwOptionCount = options.Length;
list.dwOptionError = 0;
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
// 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 ...
for (int i = 0; i < options.Length; ++i)
{
if (Environment.Is64BitOperatingSystem)
{
IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize));
nint opt = new(optionsPtr.ToInt64() + i * optSize);
Marshal.StructureToPtr(options[i], opt, false);
}
else
{
IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize));
nint opt = new(optionsPtr.ToInt32() + i * optSize);
Marshal.StructureToPtr(options[i], opt, false);
}
}
@@ -120,11 +157,11 @@ namespace v2rayN.Handler
list.options = optionsPtr;
// 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);
// and finally, call the API method!
bool isSuccess = NativeMethods.InternetSetOption(IntPtr.Zero,
bool isSuccess = NativeMethods.InternetSetOption(nint.Zero,
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
ipcoListPtr, list.dwSize);
int returnvalue = 0; // ERROR_SUCCESS
@@ -135,12 +172,12 @@ namespace v2rayN.Handler
else
{
// 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(IntPtr.Zero, InternetOption.INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
}
// 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)
{
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
@@ -204,12 +241,12 @@ namespace v2rayN.Handler
public struct InternetPerConnOptionList
{
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 dwOptionError; // on error, which option failed
//[MarshalAs(UnmanagedType.)]
public IntPtr options;
public nint options;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
@@ -236,7 +273,7 @@ namespace v2rayN.Handler
public int m_Int;
[FieldOffset(0)]
public IntPtr m_StringPtr;
public nint m_StringPtr;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
@@ -308,7 +345,7 @@ namespace v2rayN.Handler
{
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
[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)]
public static extern uint RasEnumEntries(

View File

@@ -1,6 +1,13 @@
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
{
@@ -28,5 +35,70 @@ namespace v2rayN
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);
}
}
}

View File

@@ -18,10 +18,6 @@ using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ZXing;
using ZXing.Common;
using ZXing.QrCode;
using ZXing.Windows.Compatibility;
namespace v2rayN
{
@@ -57,11 +53,14 @@ namespace v2rayN
/// 取得存储资源
/// </summary>
/// <returns></returns>
public static string? LoadResource(string res)
public static string? LoadResource(string? res)
{
try
{
if (!File.Exists(res)) return null;
if (!File.Exists(res))
{
return null;
}
return File.ReadAllText(res);
}
catch (Exception ex)
@@ -80,7 +79,7 @@ namespace v2rayN
/// </summary>
/// <param name="lst"></param>
/// <returns></returns>
public static string List2String(List<string> lst, bool wrap = false)
public static string List2String(List<string>? lst, bool wrap = false)
{
try
{
@@ -478,7 +477,7 @@ namespace v2rayN
/// 验证Domain地址是否合法
/// </summary>
/// <param name="domain"></param>
public static bool IsDomain(string domain)
public static bool IsDomain(string? domain)
{
//如果为空
if (IsNullOrEmpty(domain))
@@ -741,11 +740,11 @@ namespace v2rayN
return Guid.TryParse(strSrc, out Guid g);
}
public static void ProcessStart(string fileName)
public static void ProcessStart(string fileName, string arguments = "")
{
try
{
Process.Start(new ProcessStartInfo(fileName) { UseShellExecute = true });
Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = true });
}
catch (Exception ex)
{
@@ -947,66 +946,6 @@ namespace v2rayN
#endregion TempPath
#region scan screen
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);
BinaryBitmap bitmap = new(new HybridBinarizer(source));
QRCodeReader reader = new();
Result result = reader.decode(bitmap);
if (result != null)
{
string ret = result.Text;
return ret;
}
}
}
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);
}
#endregion scan screen
#region
/// <summary>
@@ -1145,8 +1084,10 @@ namespace v2rayN
{
try
{
var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
var guid = new Guid(sum);
string pnputilPath = @"C:\Windows\System32\pnputil.exe";
string arg = $" /remove-device /deviceid \"wintun\"";
string arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
// Try to remove the device
Process proc = new()
@@ -1186,4 +1127,4 @@ namespace v2rayN
#endregion Windows API
}
}
}

View 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
}
}

View File

@@ -11,7 +11,7 @@ namespace v2rayN.Converters
if (delay <= 0)
return new SolidColorBrush(Colors.Red);
if (delay <= 200)
if (delay <= 500)
return new SolidColorBrush(Colors.Green);
else
return new SolidColorBrush(Colors.IndianRed);

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum EConfigType
{
@@ -10,6 +10,7 @@
Trojan = 6,
Hysteria2 = 7,
Tuic = 8,
Wireguard = 9
Wireguard = 9,
Http = 10
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum ECoreType
{

View File

@@ -0,0 +1,9 @@
namespace v2rayN.Enums
{
public enum EGirdOrientation
{
Horizontal,
Vertical,
Tab,
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum EGlobalHotkey
{

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum EInboundProtocol
{
@@ -8,6 +8,7 @@
http2,
pac,
api,
api2,
speedtest = 21
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum EMove
{

View File

@@ -0,0 +1,10 @@
namespace v2rayN.Enums
{
public enum ERuleMode
{
Rule = 0,
Global = 1,
Direct = 2,
Unchanged = 3
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum EServerColName
{

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum ESpeedActionType
{

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum ESysProxyType
{

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum ETransport
{
@@ -6,6 +6,7 @@
kcp,
ws,
httpupgrade,
splithttp,
h2,
http,
quic,

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace v2rayN.Enums
{
public enum EViewAction
{

View File

@@ -1,4 +1,4 @@
using v2rayN.Models;
using v2rayN.Enums;
namespace v2rayN
{
@@ -23,12 +23,15 @@ namespace v2rayN
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
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 ConfigFileName = "guiNConfig.json";
public const string CoreConfigFileName = "config.json";
public const string CorePreConfigFileName = "configPre.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 SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
public const string V2raySampleHttpRequestFileName = "v2rayN.Sample.SampleHttpRequest";
@@ -42,6 +45,8 @@ namespace v2rayN
public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_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 DefaultNetwork = "tcp";
@@ -69,6 +74,7 @@ namespace v2rayN
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 SpeedUnit = "";
public const int MinFontSize = 10;
@@ -105,12 +111,12 @@ namespace v2rayN
@"https://speed.cloudflare.com/__down?bytes=100000000",
@"https://speed.cloudflare.com/__down?bytes=10000000",
@"http://cachefly.cachefly.net/50mb.test",
@"http://cachefly.cachefly.net/100mb.test",
@"http://cachefly.cachefly.net/10mb.test"
};
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",
};
@@ -143,6 +149,7 @@ namespace v2rayN
{EConfigType.VMess,"vmess"},
{EConfigType.Shadowsocks,"shadowsocks"},
{EConfigType.Socks,"socks"},
{EConfigType.Http,"http"},
{EConfigType.VLESS,"vless"},
{EConfigType.Trojan,"trojan"},
{EConfigType.Hysteria2,"hysteria2"},
@@ -156,7 +163,7 @@ namespace v2rayN
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> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "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> CoreTypes = new() { "v2fly", "SagerNet", "Xray", "sing_box" };
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
@@ -168,17 +175,26 @@ namespace v2rayN
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> 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> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2,http/1.1", "h3,h2", "h2,http/1.1", "" };
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> InboundTags = new() { "socks", "http", "socks2", "http2" };
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
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> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
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> 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
}
}

View 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}";
}
}
}

View File

@@ -1,6 +1,10 @@
using System.Data;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using v2rayN.Enums;
using v2rayN.Handler.CoreConfig;
using v2rayN.Handler.Fmt;
using v2rayN.Models;
namespace v2rayN.Handler
@@ -50,7 +54,6 @@ namespace v2rayN.Handler
{
logEnabled = false,
loglevel = "warning",
muxEnabled = false,
};
}
@@ -180,7 +183,7 @@ namespace v2rayN.Handler
config.mux4SboxItem = new()
{
protocol = Global.SingboxMuxs[0],
max_connections = 4
max_connections = 8
};
}
@@ -192,6 +195,16 @@ namespace v2rayN.Handler
down_mbps = 100
};
}
config.clashUIItem ??= new();
if (config.systemProxyItem == null)
{
config.systemProxyItem = new()
{
systemProxyExceptions = config.systemProxyExceptions,
systemProxyAdvancedProtocol = config.systemProxyAdvancedProtocol,
};
}
LazyConfig.Instance.SetConfig(config);
return 0;
@@ -241,103 +254,103 @@ namespace v2rayN.Handler
}
}
public static int ImportOldGuiConfig(Config config, string fileName)
{
var result = Utils.LoadResource(fileName);
if (Utils.IsNullOrEmpty(result))
{
return -1;
}
//public static int ImportOldGuiConfig(Config config, string fileName)
//{
// var result = Utils.LoadResource(fileName);
// if (Utils.IsNullOrEmpty(result))
// {
// return -1;
// }
var configOld = JsonUtils.Deserialize<ConfigOld>(result);
if (configOld == null)
{
return -1;
}
// var configOld = JsonUtils.Deserialize<ConfigOld>(result);
// if (configOld == null)
// {
// return -1;
// }
var subItem = JsonUtils.Deserialize<List<SubItem>>(JsonUtils.Serialize(configOld.subItem));
foreach (var it in subItem)
{
if (Utils.IsNullOrEmpty(it.id))
{
it.id = Utils.GetGUID(false);
}
SQLiteHelper.Instance.Replace(it);
}
// var subItem = JsonUtils.Deserialize<List<SubItem>>(JsonUtils.Serialize(configOld.subItem));
// foreach (var it in subItem)
// {
// if (Utils.IsNullOrEmpty(it.id))
// {
// it.id = Utils.GetGUID(false);
// }
// SQLiteHelper.Instance.Replace(it);
// }
var profileItems = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(configOld.vmess));
foreach (var it in profileItems)
{
if (Utils.IsNullOrEmpty(it.indexId))
{
it.indexId = Utils.GetGUID(false);
}
SQLiteHelper.Instance.Replace(it);
}
// var profileItems = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(configOld.vmess));
// foreach (var it in profileItems)
// {
// if (Utils.IsNullOrEmpty(it.indexId))
// {
// it.indexId = Utils.GetGUID(false);
// }
// SQLiteHelper.Instance.Replace(it);
// }
foreach (var it in configOld.routings)
{
if (it.locked)
{
continue;
}
var routing = JsonUtils.Deserialize<RoutingItem>(JsonUtils.Serialize(it));
foreach (var it2 in it.rules)
{
it2.id = Utils.GetGUID(false);
}
routing.ruleNum = it.rules.Count;
routing.ruleSet = JsonUtils.Serialize(it.rules, false);
// foreach (var it in configOld.routings)
// {
// if (it.locked)
// {
// continue;
// }
// var routing = JsonUtils.Deserialize<RoutingItem>(JsonUtils.Serialize(it));
// foreach (var it2 in it.rules)
// {
// it2.id = Utils.GetGUID(false);
// }
// routing.ruleNum = it.rules.Count;
// routing.ruleSet = JsonUtils.Serialize(it.rules, false);
if (Utils.IsNullOrEmpty(routing.id))
{
routing.id = Utils.GetGUID(false);
}
SQLiteHelper.Instance.Replace(routing);
}
// if (Utils.IsNullOrEmpty(routing.id))
// {
// routing.id = Utils.GetGUID(false);
// }
// SQLiteHelper.Instance.Replace(routing);
// }
config = JsonUtils.Deserialize<Config>(JsonUtils.Serialize(configOld));
// config = JsonUtils.Deserialize<Config>(JsonUtils.Serialize(configOld));
if (config.coreBasicItem == null)
{
config.coreBasicItem = new()
{
logEnabled = configOld.logEnabled,
loglevel = configOld.loglevel,
muxEnabled = configOld.muxEnabled,
};
}
// if (config.coreBasicItem == null)
// {
// config.coreBasicItem = new()
// {
// logEnabled = configOld.logEnabled,
// loglevel = configOld.loglevel,
// muxEnabled = configOld.muxEnabled,
// };
// }
if (config.routingBasicItem == null)
{
config.routingBasicItem = new()
{
enableRoutingAdvanced = configOld.enableRoutingAdvanced,
domainStrategy = configOld.domainStrategy
};
}
// if (config.routingBasicItem == null)
// {
// config.routingBasicItem = new()
// {
// enableRoutingAdvanced = configOld.enableRoutingAdvanced,
// domainStrategy = configOld.domainStrategy
// };
// }
if (config.guiItem == null)
{
config.guiItem = new()
{
enableStatistics = configOld.enableStatistics,
keepOlderDedupl = configOld.keepOlderDedupl,
ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore,
autoUpdateInterval = configOld.autoUpdateInterval,
checkPreReleaseUpdate = configOld.checkPreReleaseUpdate,
enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13,
trayMenuServersLimit = configOld.trayMenuServersLimit,
};
}
// if (config.guiItem == null)
// {
// config.guiItem = new()
// {
// enableStatistics = configOld.enableStatistics,
// keepOlderDedupl = configOld.keepOlderDedupl,
// ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore,
// autoUpdateInterval = configOld.autoUpdateInterval,
// checkPreReleaseUpdate = configOld.checkPreReleaseUpdate,
// enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13,
// trayMenuServersLimit = configOld.trayMenuServersLimit,
// };
// }
GetDefaultServer(config);
GetDefaultRouting(config);
SaveConfig(config);
LoadConfig(ref config);
// GetDefaultServer(config);
// GetDefaultRouting(config);
// SaveConfig(config);
// LoadConfig(ref config);
return 0;
}
// return 0;
//}
#endregion ConfigHandler
@@ -664,6 +677,23 @@ namespace v2rayN.Handler
return 0;
}
/// <summary>
/// Add or edit server
/// </summary>
/// <param name="config"></param>
/// <param name="profileItem"></param>
/// <returns></returns>
public static int AddHttpServer(Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configType = EConfigType.Http;
profileItem.address = profileItem.address.TrimEx();
AddServerCommon(config, profileItem, toFile);
return 0;
}
/// <summary>
/// Add or edit server
/// </summary>
@@ -1045,6 +1075,33 @@ namespace v2rayN.Handler
return 0;
}
public static int AddCustomServer4Multiple(Config config, List<ProfileItem> selecteds, ECoreType coreType, out string indexId)
{
indexId = Utils.GetMD5(Global.CoreMultipleLoadConfigFileName);
string configPath = Utils.GetConfigPath(Global.CoreMultipleLoadConfigFileName);
if (CoreConfigHandler.GenerateClientMultipleLoadConfig(config, configPath, selecteds, coreType, out string msg) != 0)
{
return -1;
}
var fileName = configPath;
if (!File.Exists(fileName))
{
return -1;
}
var profileItem = LazyConfig.Instance.GetProfileItem(indexId) ?? new();
profileItem.indexId = indexId;
profileItem.remarks = coreType == ECoreType.sing_box ? Resx.ResUI.menuSetDefaultMultipleServer : Resx.ResUI.menuSetDefaultLoadBalanceServer;
profileItem.address = Global.CoreMultipleLoadConfigFileName;
profileItem.configType = EConfigType.Custom;
profileItem.coreType = coreType;
AddServerCommon(config, profileItem, true);
return 0;
}
#endregion Server
#region Batch add servers
@@ -1053,12 +1110,12 @@ namespace v2rayN.Handler
/// 批量添加服务器
/// </summary>
/// <param name="config"></param>
/// <param name="clipboardData"></param>
/// <param name="strData"></param>
/// <param name="subid"></param>
/// <returns>成功导入的数量</returns>
private static int AddBatchServers(Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
private static int AddBatchServers(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
{
if (Utils.IsNullOrEmpty(clipboardData))
if (Utils.IsNullOrEmpty(strData))
{
return -1;
}
@@ -1075,7 +1132,7 @@ namespace v2rayN.Handler
//Check for duplicate indexId
List<string>? lstDbIndexId = null;
List<ProfileItem> lstAdd = new();
var arrData = clipboardData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
var arrData = strData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
if (isSub)
{
arrData = arrData.Distinct();
@@ -1091,7 +1148,7 @@ namespace v2rayN.Handler
}
continue;
}
var profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg);
var profileItem = FmtHandler.ResolveConfig(str, out string msg);
if (profileItem is null)
{
continue;
@@ -1160,55 +1217,39 @@ namespace v2rayN.Handler
return countServers;
}
private static int AddBatchServers4Custom(Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
private static int AddBatchServers4Custom(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
{
if (Utils.IsNullOrEmpty(clipboardData))
if (Utils.IsNullOrEmpty(strData))
{
return -1;
}
var subRemarks = LazyConfig.Instance.GetSubItem(subid)?.remarks;
//判断str是否包含s的任意一个字符串
static bool Contains(string str, params string[] s)
List<ProfileItem>? lstProfiles = null;
//Is sing-box array configuration
if (lstProfiles is null || lstProfiles.Count <= 0)
{
foreach (var item in s)
{
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
}
return false;
lstProfiles = SingboxFmt.ResolveFullArray(strData, subRemarks);
}
//Is v2ray array configuration
var configObjects = JsonUtils.Deserialize<Object[]>(clipboardData);
if (configObjects != null && configObjects.Length > 0)
if (lstProfiles is null || lstProfiles.Count <= 0)
{
lstProfiles = V2rayFmt.ResolveFullArray(strData, subRemarks);
}
if (lstProfiles != null && lstProfiles.Count > 0)
{
if (isSub && !Utils.IsNullOrEmpty(subid))
{
RemoveServerViaSubid(config, subid, isSub);
}
int count = 0;
foreach (var configObject in configObjects)
foreach (var it in lstProfiles)
{
var objectString = JsonUtils.Serialize(configObject);
var v2rayCon = JsonUtils.Deserialize<V2rayConfig>(objectString);
if (v2rayCon?.inbounds?.Count > 0 && v2rayCon.outbounds?.Count > 0)
it.subid = subid;
it.isSub = isSub;
if (AddCustomServer(config, it, true) == 0)
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, objectString);
var profileIt = new ProfileItem
{
coreType = ECoreType.Xray,
address = fileName,
remarks = v2rayCon.remarks ?? "v2ray_custom",
subid = subid,
isSub = isSub
};
if (AddCustomServer(config, profileIt, true) == 0)
{
count++;
}
count++;
}
}
if (count > 0)
@@ -1217,58 +1258,39 @@ namespace v2rayN.Handler
}
}
ProfileItem profileItem = new();
//Is v2ray configuration
var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(clipboardData);
if (v2rayConfig?.inbounds?.Count > 0
&& v2rayConfig.outbounds?.Count > 0)
ProfileItem? profileItem = null;
//Is sing-box configuration
if (profileItem is null)
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData);
profileItem.coreType = ECoreType.Xray;
profileItem.address = fileName;
profileItem.remarks = v2rayConfig.remarks ?? "v2ray_custom";
profileItem = SingboxFmt.ResolveFull(strData, subRemarks);
}
//Is v2ray configuration
if (profileItem is null)
{
profileItem = V2rayFmt.ResolveFull(strData, subRemarks);
}
//Is Clash configuration
else if (Contains(clipboardData, "port", "socks-port", "proxies"))
if (profileItem is null)
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
File.WriteAllText(fileName, clipboardData);
profileItem.coreType = ECoreType.mihomo;
profileItem.address = fileName;
profileItem.remarks = "clash_custom";
profileItem = ClashFmt.ResolveFull(strData, subRemarks);
}
//Is hysteria configuration
else if (Contains(clipboardData, "server", "up", "down", "listen", "<html>", "<body>"))
if (profileItem is null)
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData);
profileItem.coreType = ECoreType.hysteria;
profileItem.address = fileName;
profileItem.remarks = "hysteria_custom";
profileItem = Hysteria2Fmt.ResolveFull2(strData, subRemarks);
}
if (profileItem is null)
{
profileItem = Hysteria2Fmt.ResolveFull(strData, subRemarks);
}
//Is naiveproxy configuration
else if (Contains(clipboardData, "listen", "proxy", "<html>", "<body>"))
if (profileItem is null)
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData);
profileItem.coreType = ECoreType.naiveproxy;
profileItem.address = fileName;
profileItem.remarks = "naiveproxy_custom";
profileItem = NaiveproxyFmt.ResolveFull(strData, subRemarks);
}
//Is Other configuration
else
if (profileItem is null || Utils.IsNullOrEmpty(profileItem.address))
{
return -1;
//var fileName = Utile.GetTempPath($"{Utile.GetGUID(false)}.txt");
//File.WriteAllText(fileName, clipboardData);
//profileItem.address = fileName;
//profileItem.remarks = "other_custom";
}
if (isSub && !Utils.IsNullOrEmpty(subid))
@@ -1281,12 +1303,6 @@ namespace v2rayN.Handler
}
profileItem.subid = subid;
profileItem.isSub = isSub;
if (Utils.IsNullOrEmpty(profileItem.address))
{
return -1;
}
if (AddCustomServer(config, profileItem, true) == 0)
{
return 1;
@@ -1297,9 +1313,9 @@ namespace v2rayN.Handler
}
}
private static int AddBatchServers4SsSIP008(Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
private static int AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
{
if (Utils.IsNullOrEmpty(clipboardData))
if (Utils.IsNullOrEmpty(strData))
{
return -1;
}
@@ -1309,31 +1325,12 @@ namespace v2rayN.Handler
RemoveServerViaSubid(config, subid, isSub);
}
//SsSIP008
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(clipboardData);
if (lstSsServer?.Count <= 0)
{
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(clipboardData);
if (ssSIP008?.servers?.Count > 0)
{
lstSsServer = ssSIP008.servers;
}
}
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
if (lstSsServer?.Count > 0)
{
int counter = 0;
foreach (var it in lstSsServer)
foreach (var ssItem in lstSsServer)
{
var ssItem = new ProfileItem()
{
subid = subid,
remarks = it.remarks,
security = it.method,
id = it.password,
address = it.server,
port = Utils.ToInt(it.server_port)
};
ssItem.subid = subid;
ssItem.isSub = isSub;
if (AddShadowsocksServer(config, ssItem) == 0)
@@ -1348,7 +1345,7 @@ namespace v2rayN.Handler
return -1;
}
public static int AddBatchServers(Config config, string clipboardData, string subid, bool isSub)
public static int AddBatchServers(Config config, string strData, string subid, bool isSub)
{
List<ProfileItem>? lstOriSub = null;
if (isSub && !Utils.IsNullOrEmpty(subid))
@@ -1357,28 +1354,28 @@ namespace v2rayN.Handler
}
var counter = 0;
if (Utils.IsBase64String(clipboardData))
if (Utils.IsBase64String(strData))
{
counter = AddBatchServers(config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
counter = AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub);
}
if (counter < 1)
{
counter = AddBatchServers(config, clipboardData, subid, isSub, lstOriSub);
counter = AddBatchServers(config, strData, subid, isSub, lstOriSub);
}
if (counter < 1)
{
counter = AddBatchServers(config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
counter = AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub);
}
if (counter < 1)
{
counter = AddBatchServers4SsSIP008(config, clipboardData, subid, isSub, lstOriSub);
counter = AddBatchServers4SsSIP008(config, strData, subid, isSub, lstOriSub);
}
//maybe other sub
if (counter < 1)
{
counter = AddBatchServers4Custom(config, clipboardData, subid, isSub, lstOriSub);
counter = AddBatchServers4Custom(config, strData, subid, isSub, lstOriSub);
}
return counter;
@@ -1397,18 +1394,27 @@ namespace v2rayN.Handler
public static int AddSubItem(Config config, string url)
{
//already exists
if (SQLiteHelper.Instance.Table<SubItem>().Where(e => e.url == url).Count() > 0)
if (SQLiteHelper.Instance.Table<SubItem>().Any(e => e.url == url))
{
return 0;
}
SubItem subItem = new()
{
id = string.Empty,
remarks = "import_sub",
url = url
};
try
{
var uri = new Uri(url);
var queryVars = HttpUtility.ParseQueryString(uri.Query);
subItem.remarks = queryVars["remarks"] ?? "import_sub";
}
catch (UriFormatException)
{
return 0;
}
return AddSubItem(config, subItem);
}
@@ -1516,16 +1522,16 @@ namespace v2rayN.Handler
/// AddBatchRoutingRules
/// </summary>
/// <param name="config"></param>
/// <param name="clipboardData"></param>
/// <param name="strData"></param>
/// <returns></returns>
public static int AddBatchRoutingRules(ref RoutingItem routingItem, string clipboardData)
public static int AddBatchRoutingRules(ref RoutingItem routingItem, string strData)
{
if (Utils.IsNullOrEmpty(clipboardData))
if (Utils.IsNullOrEmpty(strData))
{
return -1;
}
var lstRules = JsonUtils.Deserialize<List<RulesItem>>(clipboardData);
var lstRules = JsonUtils.Deserialize<List<RulesItem>>(strData);
if (lstRules == null)
{
return -1;
@@ -1657,14 +1663,15 @@ namespace v2rayN.Handler
public static int InitBuiltinRouting(Config config, bool blImportAdvancedRules = false)
{
var ver = "V3-";
var items = LazyConfig.Instance.RoutingItems();
if (blImportAdvancedRules || items.Count <= 0)
if (blImportAdvancedRules || items.Where(t => t.remarks.StartsWith(ver)).ToList().Count <= 0)
{
var maxSort = items.Count;
//Bypass the mainland
var item2 = new RoutingItem()
{
remarks = "绕过大陆(Whitelist)",
remarks = $"{ver}绕过大陆(Whitelist)",
url = string.Empty,
sort = maxSort + 1,
};
@@ -1673,7 +1680,7 @@ namespace v2rayN.Handler
//Blacklist
var item3 = new RoutingItem()
{
remarks = "黑名单(Blacklist)",
remarks = $"{ver}黑名单(Blacklist)",
url = string.Empty,
sort = maxSort + 2,
};
@@ -1682,7 +1689,7 @@ namespace v2rayN.Handler
//Global
var item1 = new RoutingItem()
{
remarks = "全局(Global)",
remarks = $"{ver}全局(Global)",
url = string.Empty,
sort = maxSort + 3,
};

View 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;
}
}
}
}

View File

@@ -1,8 +1,9 @@
using System.IO;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler
namespace v2rayN.Handler.CoreConfig
{
/// <summary>
/// Core configuration file processing class
@@ -24,9 +25,22 @@ namespace v2rayN.Handler
msg = ResUI.InitialConfiguration;
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);
if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
@@ -104,41 +118,6 @@ namespace v2rayN.Handler
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(EInboundProtocol.http)}");
fileContent.Add($"socks-port: {LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)}");
break;
}
File.WriteAllLines(fileName, fileContent);
}
msg = string.Format(ResUI.SuccessfulConfiguration, "");
}
catch (Exception ex)
@@ -154,7 +133,7 @@ namespace v2rayN.Handler
{
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;
}
@@ -162,7 +141,7 @@ namespace v2rayN.Handler
}
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;
}
@@ -170,5 +149,28 @@ namespace v2rayN.Handler
}
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;
}
}
}

View File

@@ -1,7 +1,8 @@
using System.Diagnostics;
using System.IO;
using System.Reactive.Linq;
using System.Text;
using v2rayN.Enums;
using v2rayN.Handler.CoreConfig;
using v2rayN.Models;
using v2rayN.Resx;
@@ -26,9 +27,8 @@ namespace v2rayN.Handler
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)
{
ShowMsg(false, ResUI.CheckServerSettings);
@@ -39,6 +39,7 @@ namespace v2rayN.Handler
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
{
ShowMsg(false, msg);
return;
}
else
{
@@ -54,22 +55,22 @@ namespace v2rayN.Handler
CoreStart(node);
//In tun mode, do a delay check and restart the core
if (_config.tunModeItem.enableTun)
{
Observable.Range(1, 1)
.Delay(TimeSpan.FromSeconds(15))
.Subscribe(x =>
{
{
if (_process == null || _process.HasExited)
{
CoreStart(node);
ShowMsg(false, "Tun mode restart the core once");
Logging.SaveLog("Tun mode restart the core once");
}
}
});
}
//if (_config.tunModeItem.enableTun)
//{
// Observable.Range(1, 1)
// .Delay(TimeSpan.FromSeconds(15))
// .Subscribe(x =>
// {
// {
// if (_process == null || _process.HasExited)
// {
// CoreStart(node);
// ShowMsg(false, "Tun mode restart the core once");
// Logging.SaveLog("Tun mode restart the core once");
// }
// }
// });
//}
}
}
@@ -183,15 +184,16 @@ namespace v2rayN.Handler
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ECoreType coreType;
if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
{
coreType = ECoreType.sing_box;
}
else
{
coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
}
//ECoreType coreType;
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
//{
// coreType = ECoreType.sing_box;
//}
//else
//{
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
//}
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
_config.runningCoreType = coreType;
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
@@ -203,23 +205,40 @@ namespace v2rayN.Handler
}
_process = proc;
//start a socks service
//start a pre service
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,
address = Global.Loopback,
port = node.preSocksPort
};
_config.runningCoreType = ECoreType.sing_box;
_config.runningCoreType = preCoreType;
}
if (itemSocks != null)
{
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
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);
if (proc2 is not null)
{

View File

@@ -4,7 +4,7 @@ using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Sockets;
using v2rayN.Models;
using v2rayN.Enums;
using v2rayN.Resx;
namespace v2rayN.Handler
@@ -286,8 +286,6 @@ namespace v2rayN.Handler
int responseTime = -1;
try
{
Stopwatch timer = Stopwatch.StartNew();
using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
using var client = new HttpClient(new SocketsHttpHandler()
@@ -295,9 +293,17 @@ namespace v2rayN.Handler
Proxy = webProxy,
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)
{

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;

View File

@@ -1,4 +1,5 @@
using System.Runtime.Intrinsics.X86;
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler
@@ -12,20 +13,26 @@ namespace v2rayN.Handler
public static LazyConfig Instance => _instance.Value;
private int? _statePort;
private int? _statePort2;
public int StatePort
{
get
{
if (_statePort is null)
{
_statePort = Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
}
_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()
@@ -329,7 +336,11 @@ namespace v2rayN.Handler
arguments = "-f config.json",
coreUrl = Global.MihomoCoreUrl,
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",
versionArg = "-v",
redirectInfo = true,
});

View File

@@ -2,7 +2,12 @@
using Splat;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using v2rayN.Enums;
using v2rayN.Handler.CoreConfig;
using v2rayN.Models;
using v2rayN.Resx;
@@ -17,7 +22,7 @@ namespace v2rayN.Handler
{
try
{
int index = (int)config.sysProxyType;
int index = (int)config.systemProxyItem.sysProxyType;
//Load from routing setting
var createdIcon = GetNotifyIcon4Routing(config);
@@ -51,7 +56,7 @@ namespace v2rayN.Handler
public System.Windows.Media.ImageSource GetAppIcon(Config config)
{
int index = 1;
switch (config.sysProxyType)
switch (config.systemProxyItem.sysProxyType)
{
case ESysProxyType.ForcedClear:
index = 1;
@@ -85,7 +90,7 @@ namespace v2rayN.Handler
}
Color color = ColorTranslator.FromHtml("#3399CC");
int index = (int)config.sysProxyType;
int index = (int)config.systemProxyItem.sysProxyType;
if (index > 0)
{
color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1];
@@ -124,11 +129,6 @@ namespace v2rayN.Handler
{
return;
}
if (item.configType == EConfigType.Custom)
{
Locator.Current.GetService<NoticeHandler>()?.Enqueue(ResUI.NonVmessService);
return;
}
SaveFileDialog fileDialog = new()
{
@@ -226,5 +226,27 @@ namespace v2rayN.Handler
HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
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;
});
}
}
}

View File

@@ -12,7 +12,7 @@ namespace v2rayN.Handler
_snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue));
}
public void Enqueue(string content)
public void Enqueue(string? content)
{
if (content.IsNullOrEmpty())
{
@@ -21,18 +21,26 @@ namespace v2rayN.Handler
_snackbarMessageQueue?.Enqueue(content);
}
public void SendMessage(string msg)
public void SendMessage(string? content)
{
MessageBus.Current.SendMessage(msg, Global.CommandSendMsgView);
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}";
SendMessage(msg);
if (content.IsNullOrEmpty())
{
return;
}
content = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {content}";
SendMessage(content);
}
public void SendMessageAndEnqueue(string msg)
public void SendMessageAndEnqueue(string? msg)
{
Enqueue(msg);
SendMessage(msg);

View File

@@ -7,7 +7,7 @@ namespace v2rayN.Handler
internal class ProfileExHandler
{
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx;
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
private Queue<string> _queIndexIds = new();
public ConcurrentBag<ProfileExItem> ProfileExs => _lstProfileEx;
public static ProfileExHandler Instance => _instance.Value;
@@ -15,6 +15,15 @@ namespace v2rayN.Handler
public ProfileExHandler()
{
Init();
Task.Run(async () =>
{
while (true)
{
SaveQueueIndexIds();
await Task.Delay(1000 * 600);
}
});
}
private void Init()
@@ -22,24 +31,6 @@ namespace v2rayN.Handler
SQLiteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
_lstProfileEx = new(SQLiteHelper.Instance.Table<ProfileExItem>());
Task.Run(async () =>
{
while (true)
{
var cnt = _queIndexIds.Count;
for (int i = 0; i < cnt; i++)
{
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 IndexIdEnqueue(string indexId)
@@ -50,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)
{
profileEx = new()
@@ -73,11 +107,7 @@ namespace v2rayN.Handler
{
try
{
//foreach (var item in _lstProfileEx)
//{
// SQLiteHelper.Instance.Replace(item);
//}
SQLiteHelper.Instance.UpdateAll(_lstProfileEx);
SaveQueueIndexIds();
}
catch (Exception ex)
{

View File

@@ -1,998 +0,0 @@
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using v2rayN.Models;
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),
EConfigType.Wireguard => ShareWireguard(item),
_ => null,
};
return url;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return "";
}
}
private static string ShareVmess(ProfileItem item)
{
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 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 = 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 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 = 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 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", 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;
}
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));
}
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;
}
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 ShareWireguard(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.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;
}
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 : 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):
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;
}
#endregion GetShareUrl
#region ImportShareUrl
/// <summary>
/// 从剪贴板导入URL
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? profileItem;
try
{
string result = clipboardData.TrimEx();
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]))
{
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]))
{
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]))
{
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))
{
profileItem = ResolveHysteria2(result);
}
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Tuic]))
{
profileItem = ResolveTuic(result);
}
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Wireguard]))
{
profileItem = ResolveWireguard(result);
}
else
{
msg = ResUI.NonvmessOrssProtocol;
return null;
}
}
catch (Exception ex)
{
Logging.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 = JsonUtils.Deserialize<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 query = Utils.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 Global.StreamSecurity:
break;
default:
if (!Utils.IsNullOrEmpty(i.streamSecurity))
return null;
break;
}
i.network = m.Groups["network"].Value;
switch (i.network)
{
case nameof(ETransport.tcp):
string t1 = query["type"] ?? Global.None;
i.headerType = t1;
break;
case nameof(ETransport.kcp):
i.headerType = query["type"] ?? Global.None;
break;
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
string p1 = query["path"] ?? "/";
string h1 = query["host"] ?? "";
i.requestHost = Utils.UrlDecode(h1);
i.path = p1;
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
i.network = nameof(ETransport.h2);
string p2 = query["path"] ?? "/";
string h2 = query["host"] ?? "";
i.requestHost = Utils.UrlDecode(h2);
i.path = p2;
break;
case nameof(ETransport.quic):
string s = query["security"] ?? Global.None;
string k = query["key"] ?? "";
string t3 = query["type"] ?? Global.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];
}
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=", "");
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 = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
return item;
}
private static ProfileItem ResolveStdVLESS(string result)
{
ProfileItem item = new()
{
configType = EConfigType.VLESS,
security = Global.None
};
Uri url = new(result);
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;
}
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 = 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;
}
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 = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
item.headerType = query["congestion_control"] ?? "";
return item;
}
private static ProfileItem ResolveWireguard(string result)
{
ProfileItem item = new()
{
configType = EConfigType.Wireguard
};
Uri url = new(result);
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;
}
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"] ?? 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):
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;
}
#endregion ImportShareUrl
}
}

View File

@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
@@ -376,19 +377,18 @@ namespace v2rayN.Handler
ipAddress = ipHostInfo.AddressList[0];
}
Stopwatch timer = new();
timer.Start();
var timer = Stopwatch.StartNew();
IPEndPoint endPoint = new(ipAddress, port);
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)))
throw new TimeoutException("connect timeout (5s): " + url);
clientSocket.EndConnect(result);
timer.Stop();
responseTime = timer.Elapsed.Milliseconds;
responseTime = (int)timer.Elapsed.TotalMilliseconds;
}
catch (Exception ex)
{

View File

@@ -1,9 +1,12 @@
using v2rayN.Models;
namespace v2rayN.Handler
namespace v2rayN.Handler.Statistics
{
internal class StatisticsHandler
{
private static readonly Lazy<StatisticsHandler> instance = new(() => new());
public static StatisticsHandler Instance => instance.Value;
private Config _config;
private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat;
@@ -12,20 +15,17 @@ namespace v2rayN.Handler
private StatisticsSingbox? _statisticsSingbox;
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;
Enable = config.guiItem.enableStatistics;
if (!Enable)
_updateFunc = update;
if (!config.guiItem.enableStatistics)
{
return;
}
_updateFunc = update;
Init();
InitData();
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
@@ -55,7 +55,10 @@ namespace v2rayN.Handler
{
try
{
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
if (_lstServerStat != null)
{
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
}
}
catch (Exception ex)
{
@@ -63,7 +66,7 @@ namespace v2rayN.Handler
}
}
private void Init()
private void InitData()
{
SQLiteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");

View File

@@ -1,8 +1,9 @@
using System.Net.WebSockets;
using System.Text;
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler
namespace v2rayN.Handler.Statistics
{
internal class StatisticsSingbox
{
@@ -27,7 +28,7 @@ namespace v2rayN.Handler
try
{
url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort}/traffic";
url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort2}/traffic";
if (webSocket == null)
{
@@ -64,7 +65,7 @@ namespace v2rayN.Handler
await Task.Delay(1000);
try
{
if (!(_config.runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo))
if (!(_config.IsRunningCore(ECoreType.clash)))
{
continue;
}

View File

@@ -1,9 +1,10 @@
using Grpc.Core;
using Grpc.Net.Client;
using ProtosLib.Statistics;
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler
namespace v2rayN.Handler.Statistics
{
internal class StatisticsV2ray
{
@@ -52,7 +53,7 @@ namespace v2rayN.Handler
await Task.Delay(1000);
try
{
if (!(_config.runningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5 or ECoreType.SagerNet))
if (!(_config.IsRunningCore(ECoreType.Xray)))
{
continue;
}
@@ -86,6 +87,8 @@ namespace v2rayN.Handler
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
{
server = new();
long aggregateProxyUp = 0;
long aggregateProxyDown = 0;
try
{
foreach (Stat stat in source)
@@ -100,15 +103,15 @@ namespace v2rayN.Handler
name = nStr[1];
type = nStr[3];
if (name == Global.ProxyTag)
if (name.StartsWith(Global.ProxyTag))
{
if (type == "uplink")
{
server.proxyUp = value;
aggregateProxyUp += value;
}
else if (type == "downlink")
{
server.proxyDown = value;
aggregateProxyDown += value;
}
}
else if (name == Global.DirectTag)
@@ -123,6 +126,8 @@ namespace v2rayN.Handler
}
}
}
server.proxyUp = aggregateProxyUp;
server.proxyDown = aggregateProxyDown;
}
catch
{

View File

@@ -1,38 +1,17 @@
using PacLib;
using v2rayN.Common;
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler
{
public static class SysProxyHandle
{
//private const string _userWininetConfigFile = "user-wininet.json";
//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()
{
}
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
public static bool UpdateSysProxy(Config config, bool forceDisable)
{
var type = config.sysProxyType;
var type = config.systemProxyItem.sysProxyType;
if (forceDisable && type != ESysProxyType.Unchanged)
{
@@ -50,25 +29,29 @@ namespace v2rayN.Handler
}
if (type == ESysProxyType.ForcedChange)
{
var strExceptions = $"<local>;{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}";
var strExceptions = "";
if (config.systemProxyItem.notProxyLocalAddress)
{
strExceptions = $"<local>;{config.constItem.defIEProxyExceptions};{config.systemProxyItem.systemProxyExceptions}";
}
var strProxy = string.Empty;
if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol))
if (Utils.IsNullOrEmpty(config.systemProxyItem.systemProxyAdvancedProtocol))
{
strProxy = $"{Global.Loopback}:{port}";
}
else
{
strProxy = config.systemProxyAdvancedProtocol
strProxy = config.systemProxyItem.systemProxyAdvancedProtocol
.Replace("{ip}", Global.Loopback)
.Replace("{http_port}", port.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)
{
ProxySetting.UnsetProxy(); // set to no proxy
ProxySetting.UnsetProxy();
}
else if (type == ESysProxyType.Unchanged)
{
@@ -77,7 +60,7 @@ namespace v2rayN.Handler
{
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
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)
@@ -94,14 +77,7 @@ namespace v2rayN.Handler
public static void ResetIEProxy4WindowsShutDown()
{
try
{
//TODO To be verified
Utils.RegWriteValue(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", "ProxyEnable", 0);
}
catch
{
}
ProxySetting.UnsetProxy();
}
}
}

View File

@@ -6,6 +6,7 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
@@ -299,9 +300,6 @@ namespace v2rayN.Handler
{
await UpdateGeoFile("geosite", _config, update);
await UpdateGeoFile("geoip", _config, update);
//await UpdateGeoFile4Singbox("geosite", _config, false, update);
//await UpdateGeoFile4Singbox("geoip", _config, true, update);
});
}
@@ -327,7 +325,7 @@ namespace v2rayN.Handler
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
if (!Utils.IsNullOrEmpty(result))
{
responseHandler(type, result, preRelease);
ResponseHandler(type, result, preRelease);
}
else
{
@@ -345,7 +343,7 @@ namespace v2rayN.Handler
/// <summary>
/// 获取V2RayCore版本
/// </summary>
private SemanticVersion getCoreVersion(ECoreType type)
private SemanticVersion GetCoreVersion(ECoreType type)
{
try
{
@@ -410,7 +408,7 @@ namespace v2rayN.Handler
}
}
private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
private void ResponseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
{
try
{
@@ -431,7 +429,7 @@ namespace v2rayN.Handler
case ECoreType.Xray:
case ECoreType.v2fly_v5:
{
curVersion = getCoreVersion(type);
curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
string osBit = "64";
switch (RuntimeInformation.ProcessArchitecture)
@@ -456,7 +454,7 @@ namespace v2rayN.Handler
case ECoreType.clash_meta:
case ECoreType.mihomo:
{
curVersion = getCoreVersion(type);
curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion);
switch (RuntimeInformation.ProcessArchitecture)
{
@@ -477,7 +475,7 @@ namespace v2rayN.Handler
}
case ECoreType.sing_box:
{
curVersion = getCoreVersion(type);
curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
switch (RuntimeInformation.ProcessArchitecture)
{

View 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; }
}
}

View 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; }
}
}

View 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; }
}
}
}

View 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; }
}
}
}

View 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; }
}
}

View File

@@ -1,4 +1,6 @@
namespace v2rayN.Models
using v2rayN.Enums;
namespace v2rayN.Models
{
/// <summary>
/// 本软件配置文件实体类
@@ -10,12 +12,24 @@
public string indexId { get; set; }
public string subIndexId { get; set; }
public ESysProxyType sysProxyType { get; set; }
public string systemProxyExceptions { 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
#region other entities
@@ -31,6 +45,8 @@
public SpeedTestItem speedTestItem { get; set; }
public Mux4SboxItem mux4SboxItem { 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<KeyEventItem> globalHotkeys { get; set; }
public List<CoreTypeItem> coreTypeItem { get; set; }

View File

@@ -1,4 +1,5 @@
using System.Windows.Input;
using v2rayN.Enums;
namespace v2rayN.Models
{
@@ -31,6 +32,10 @@ namespace v2rayN.Models
/// 默认用户代理
/// </summary>
public string defUserAgent { get; set; }
public bool enableFragment { get; set; }
public bool enableCacheFile4Sbox { get; set; } = true;
}
[Serializable]
@@ -43,8 +48,8 @@ namespace v2rayN.Models
public bool udpEnabled { get; set; }
public bool sniffingEnabled { get; set; } = true;
public List<string>? destOverride { get; set; } = ["http", "tls"];
public bool routeOnly { get; set; }
public bool allowLANConn { get; set; }
public bool newPort4LAN { get; set; }
@@ -114,6 +119,7 @@ namespace v2rayN.Models
public double mainHeight { get; set; }
public double mainGirdHeight1 { get; set; }
public double mainGirdHeight2 { get; set; }
public EGirdOrientation mainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
public bool colorModeDark { get; set; }
public bool followSystemTheme { get; set; }
public string? colorPrimaryName { get; set; }
@@ -122,9 +128,10 @@ namespace v2rayN.Models
public int currentFontSize { get; set; }
public bool enableDragDropSort { get; set; }
public bool doubleClick2Activate { get; set; }
public bool autoHideStartup { get; set; } = true;
public bool autoHideStartup { get; set; }
public string mainMsgFilter { get; set; }
public List<ColumnItem> mainColumnItem { get; set; }
public bool showInTaskbar { get; set; }
}
[Serializable]
@@ -164,7 +171,7 @@ namespace v2rayN.Models
public string stack { get; set; }
public int mtu { get; set; }
public bool enableExInbound { get; set; }
public bool enableIPv6Address { get; set; } = true;
public bool enableIPv6Address { get; set; }
}
[Serializable]
@@ -178,13 +185,8 @@ namespace v2rayN.Models
[Serializable]
public class RoutingBasicItem
{
/// <summary>
/// 域名解析策略
/// </summary>
public string domainStrategy { get; set; }
public string domainStrategy4Singbox { get; set; }
public string domainMatcher { get; set; }
public string routingIndexId { get; set; }
public bool enableRoutingAdvanced { get; set; }
@@ -211,4 +213,27 @@ namespace v2rayN.Models
public int up_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; }
}
}

View File

@@ -1,440 +0,0 @@
namespace v2rayN.Models
{
[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;
}
}
}

View File

@@ -1,4 +1,6 @@
namespace v2rayN.Models
using v2rayN.Enums;
namespace v2rayN.Models
{
[Serializable]
public class CoreInfo

View File

@@ -1,4 +1,5 @@
using SQLite;
using v2rayN.Enums;
namespace v2rayN.Models
{
@@ -15,5 +16,6 @@ namespace v2rayN.Models
public string? normalDNS { get; set; }
public string? tunDNS { get; set; }
public string? domainStrategy4Freedom { get; set; }
public string? domainDNSAddress { get; set; }
}
}

View File

@@ -1,4 +1,5 @@
using SQLite;
using v2rayN.Enums;
namespace v2rayN.Models
{
@@ -48,7 +49,7 @@ namespace v2rayN.Models
switch (configType)
{
case EConfigType.Custom:
summary += string.Format("{0}", remarks);
summary += string.Format("[{1}]{0}", remarks, coreType.ToString());
break;
default:

View File

@@ -15,6 +15,7 @@ namespace v2rayN.Models
public bool enabled { get; set; } = true;
public bool locked { get; set; }
public string customIcon { get; set; }
public string customRulesetPath4Singbox { get; set; }
public string domainStrategy { get; set; }
public string domainStrategy4Singbox { get; set; }
public int sort { get; set; }

View File

@@ -4,21 +4,22 @@
public class RulesItem
{
public string id { get; set; }
public string type { get; set; }
public string? type { get; set; }
public string port { get; set; }
public string? port { get; set; }
public string? network { get; set; }
public List<string> inboundTag { get; set; }
public List<string>? inboundTag { get; set; }
public string outboundTag { get; set; }
public string? outboundTag { get; set; }
public List<string> ip { get; set; }
public List<string>? ip { get; set; }
public List<string> domain { get; set; }
public List<string>? domain { get; set; }
public List<string> protocol { get; set; }
public List<string>? protocol { get; set; }
public List<string> process { get; set; }
public List<string>? process { get; set; }
public bool enabled { get; set; } = true;
}

View File

@@ -1,7 +1,7 @@
namespace v2rayN.Models
{
[Serializable]
internal class ServerSpeedItem : ServerStatItem
public class ServerSpeedItem : ServerStatItem
{
public long proxyUp
{

View File

@@ -1,4 +1,6 @@
namespace v2rayN.Models
using v2rayN.Enums;
namespace v2rayN.Models
{
[Serializable]
internal class ServerTestItem

View File

@@ -7,7 +7,7 @@
public List<Inbound4Sbox> inbounds { get; set; }
public List<Outbound4Sbox> outbounds { get; set; }
public Route4Sbox route { get; set; }
public Experimental4Sbox experimental { get; set; }
public Experimental4Sbox? experimental { get; set; }
}
public class Log4Sbox
@@ -28,6 +28,7 @@
public bool? disable_expire { get; set; }
public bool? independent_cache { get; set; }
public bool? reverse_mapping { get; set; }
public string? client_subnet { get; set; }
public Fakeip4Sbox? fakeip { get; set; }
}
@@ -35,19 +36,24 @@
{
public bool? auto_detect_interface { get; set; }
public List<Rule4Sbox> rules { get; set; }
public List<Ruleset4Sbox>? rule_set { get; set; }
}
[Serializable]
public class Rule4Sbox
{
public string outbound { get; set; }
public string server { get; set; }
public string? outbound { get; set; }
public string? server { 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>? protocol { get; set; }
public string type { get; set; }
public string mode { get; set; }
public string network { get; set; }
public List<string>? network { get; set; }
public List<int>? port { get; set; }
public List<string>? port_range { get; set; }
public List<string>? geosite { get; set; }
@@ -58,8 +64,9 @@
public List<string>? geoip { get; set; }
public List<string>? ip_cidr { get; set; }
public List<string>? source_ip_cidr { get; set; }
public List<string>? process_name { get; set; }
public List<string>? rule_set { get; set; }
public List<Rule4Sbox>? rules { get; set; }
}
[Serializable]
@@ -93,7 +100,7 @@
{
public string type { get; set; }
public string tag { get; set; }
public string server { get; set; }
public string? server { get; set; }
public int? server_port { get; set; }
public string uuid { get; set; }
public string security { get; set; }
@@ -124,6 +131,8 @@
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
@@ -182,11 +191,13 @@
public class Server4Sbox
{
public string tag { get; set; }
public string address { get; set; }
public string address_resolver { get; set; }
public string strategy { get; set; }
public string? tag { get; set; }
public string? address { get; set; }
public string? address_resolver { get; set; }
public string? address_strategy { get; set; }
public string? strategy { get; set; }
public string? detour { get; set; }
public string? client_subnet { get; set; }
}
public class Experimental4Sbox
@@ -230,4 +241,15 @@
public string? cache_id { 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; }
}
}

View File

@@ -195,7 +195,7 @@ namespace v2rayN.Models
public class Sniffing4Ray
{
public bool enabled { get; set; }
public List<string> destOverride { get; set; }
public List<string>? destOverride { get; set; }
public bool routeOnly { get; set; }
}
@@ -232,7 +232,7 @@ namespace v2rayN.Models
/// <summary>
///
/// </summary>
public List<VnextItem4Ray> vnext { get; set; }
public List<VnextItem4Ray>? vnext { get; set; }
/// <summary>
///
@@ -253,6 +253,8 @@ namespace v2rayN.Models
///
/// </summary>
public int? userLevel { get; set; }
public FragmentItem4Ray? fragment { get; set; }
}
public class VnextItem4Ray
@@ -288,17 +290,17 @@ namespace v2rayN.Models
/// <summary>
///
/// </summary>
public string method { get; set; }
public string? method { get; set; }
/// <summary>
///
/// </summary>
public bool ota { get; set; }
public bool? ota { get; set; }
/// <summary>
///
/// </summary>
public string password { get; set; }
public string? password { get; set; }
/// <summary>
///
@@ -308,7 +310,7 @@ namespace v2rayN.Models
/// <summary>
///
/// </summary>
public int level { get; set; }
public int? level { get; set; }
/// <summary>
/// trojan
@@ -336,7 +338,7 @@ namespace v2rayN.Models
/// <summary>
///
/// </summary>
public int level { get; set; }
public int? level { get; set; }
}
public class Mux4Ray
@@ -368,6 +370,12 @@ namespace v2rayN.Models
public List<string> servers { get; set; }
}
public class DnsServer4Ray
{
public string? address { get; set; }
public List<string>? domains { get; set; }
}
public class Routing4Ray
{
/// <summary>
@@ -378,30 +386,47 @@ namespace v2rayN.Models
/// <summary>
///
/// </summary>
public string domainMatcher { get; set; }
public string? domainMatcher { get; set; }
/// <summary>
///
/// </summary>
public List<RulesItem4Ray> rules { get; set; }
public List<BalancersItem4Ray>? balancers { get; set; }
}
[Serializable]
public class RulesItem4Ray
{
public string type { get; set; }
public string? type { get; set; }
public string port { get; set; }
public string? port { get; set; }
public string? network { get; set; }
public List<string> inboundTag { get; set; }
public List<string>? inboundTag { get; set; }
public string outboundTag { get; set; }
public string? outboundTag { get; set; }
public List<string> ip { get; set; }
public string? balancerTag { get; set; }
public List<string> domain { get; set; }
public List<string>? ip { get; set; }
public List<string> protocol { get; set; }
public List<string>? domain { get; set; }
public List<string>? protocol { get; set; }
}
public class BalancersItem4Ray
{
public List<string>? selector { get; set; }
public BalancersStrategy4Ray? strategy { get; set; }
public string? tag { get; set; }
}
public class BalancersStrategy4Ray
{
public string? type { get; set; }
}
public class StreamSettings4Ray
@@ -419,47 +444,52 @@ namespace v2rayN.Models
/// <summary>
///
/// </summary>
public TlsSettings4Ray tlsSettings { get; set; }
public TlsSettings4Ray? tlsSettings { get; set; }
/// <summary>
/// Tcp传输额外设置
/// </summary>
public TcpSettings4Ray tcpSettings { get; set; }
public TcpSettings4Ray? tcpSettings { get; set; }
/// <summary>
/// Kcp传输额外设置
/// </summary>
public KcpSettings4Ray kcpSettings { get; set; }
public KcpSettings4Ray? kcpSettings { get; set; }
/// <summary>
/// ws传输额外设置
/// </summary>
public WsSettings4Ray wsSettings { get; set; }
public WsSettings4Ray? wsSettings { get; set; }
/// <summary>
///
/// </summary>
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
/// <summary>
///
/// </summary>
public SplithttpSettings4Ray? splithttpSettings { get; set; }
/// <summary>
/// h2传输额外设置
/// </summary>
public HttpSettings4Ray httpSettings { get; set; }
public HttpSettings4Ray? httpSettings { get; set; }
/// <summary>
/// QUIC
/// </summary>
public QuicSettings4Ray quicSettings { get; set; }
public QuicSettings4Ray? quicSettings { get; set; }
/// <summary>
/// VLESS only
/// </summary>
public TlsSettings4Ray realitySettings { get; set; }
public TlsSettings4Ray? realitySettings { get; set; }
/// <summary>
/// grpc
/// </summary>
public GrpcSettings4Ray grpcSettings { get; set; }
public GrpcSettings4Ray? grpcSettings { get; set; }
/// <summary>
/// sockopt
@@ -486,7 +516,7 @@ namespace v2rayN.Models
public string? fingerprint { get; set; }
public bool? show { get; set; } = false;
public bool? show { get; set; }
public string? publicKey { get; set; }
public string? shortId { get; set; }
public string? spiderX { get; set; }
@@ -606,6 +636,17 @@ namespace v2rayN.Models
public string? host { get; set; }
}
public class SplithttpSettings4Ray
{
public string? path { get; set; }
public string? host { get; set; }
public int? maxUploadSize { get; set; }
public int? maxConcurrentUploads { get; set; }
}
public class HttpSettings4Ray
{
/// <summary>
@@ -665,4 +706,11 @@ namespace v2rayN.Models
{
public string? dialerProxy { get; set; }
}
public class FragmentItem4Ray
{
public string? packets { get; set; }
public string? length { get; set; }
public string? interval { get; set; }
}
}

View File

@@ -78,15 +78,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Batch export subscription to clipboard successfully 的本地化字符串。
/// </summary>
public static string BatchExportSubscriptionSuccessfully {
get {
return ResourceManager.GetString("BatchExportSubscriptionSuccessfully", resourceCulture);
}
}
/// <summary>
/// 查找类似 Batch export share URL to clipboard successfully 的本地化字符串。
/// </summary>
@@ -222,15 +213,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Please fill in the KCP parameters correctly 的本地化字符串。
/// </summary>
public static string FillKcpParameters {
get {
return ResourceManager.GetString("FillKcpParameters", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please fill in the local listening port 的本地化字符串。
/// </summary>
@@ -285,15 +267,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Is not the correct client configuration file, please check 的本地化字符串。
/// </summary>
public static string IncorrectClientConfiguration {
get {
return ResourceManager.GetString("IncorrectClientConfiguration", resourceCulture);
}
}
/// <summary>
/// 查找类似 Is not the correct configuration, please check 的本地化字符串。
/// </summary>
@@ -303,15 +276,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Is not the correct server configuration file, please check 的本地化字符串。
/// </summary>
public static string IncorrectServerConfiguration {
get {
return ResourceManager.GetString("IncorrectServerConfiguration", resourceCulture);
}
}
/// <summary>
/// 查找类似 Initial Configuration 的本地化字符串。
/// </summary>
@@ -367,7 +331,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Automatic update interval(minutes) 的本地化字符串。
/// 查找类似 Automatic update interval (minutes) 的本地化字符串。
/// </summary>
public static string LvAutoUpdateInterval {
get {
@@ -412,7 +376,16 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Enabled Update 的本地化字符串。
/// 查找类似 Custom the rule-set of sing-box 的本地化字符串。
/// </summary>
public static string LvCustomRulesetPath4Singbox {
get {
return ResourceManager.GetString("LvCustomRulesetPath4Singbox", resourceCulture);
}
}
/// <summary>
/// 查找类似 Enable update 的本地化字符串。
/// </summary>
public static string LvEnabled {
get {
@@ -439,7 +412,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 More urls, separated by commas;Subscription conversion will be invalid 的本地化字符串。
/// 查找类似 More URLs, separated by commas; Subscription conversion will be invalid 的本地化字符串。
/// </summary>
public static string LvMoreUrl {
get {
@@ -618,6 +591,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Add [Http] server 的本地化字符串。
/// </summary>
public static string menuAddHttpServer {
get {
return ResourceManager.GetString("menuAddHttpServer", resourceCulture);
}
}
/// <summary>
/// 查找类似 Add [Hysteria2] server 的本地化字符串。
/// </summary>
@@ -735,6 +717,24 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Close Connection 的本地化字符串。
/// </summary>
public static string menuConnectionClose {
get {
return ResourceManager.GetString("menuConnectionClose", resourceCulture);
}
}
/// <summary>
/// 查找类似 Close All Connection 的本地化字符串。
/// </summary>
public static string menuConnectionCloseAll {
get {
return ResourceManager.GetString("menuConnectionCloseAll", resourceCulture);
}
}
/// <summary>
/// 查找类似 Clone selected server 的本地化字符串。
/// </summary>
@@ -789,15 +789,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Export subscription (base64) share to clipboard 的本地化字符串。
/// </summary>
public static string menuExport2SubContent {
get {
return ResourceManager.GetString("menuExport2SubContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Global Hotkey Setting 的本地化字符串。
/// </summary>
@@ -861,6 +852,42 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Direct 的本地化字符串。
/// </summary>
public static string menuModeDirect {
get {
return ResourceManager.GetString("menuModeDirect", resourceCulture);
}
}
/// <summary>
/// 查找类似 Global 的本地化字符串。
/// </summary>
public static string menuModeGlobal {
get {
return ResourceManager.GetString("menuModeGlobal", resourceCulture);
}
}
/// <summary>
/// 查找类似 Do not change 的本地化字符串。
/// </summary>
public static string menuModeNothing {
get {
return ResourceManager.GetString("menuModeNothing", resourceCulture);
}
}
/// <summary>
/// 查找类似 Rule 的本地化字符串。
/// </summary>
public static string menuModeRule {
get {
return ResourceManager.GetString("menuModeRule", resourceCulture);
}
}
/// <summary>
/// 查找类似 Move to bottom (B) 的本地化字符串。
/// </summary>
@@ -942,15 +969,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Set message filters 的本地化字符串。
/// </summary>
public static string menuMsgViewFilter {
get {
return ResourceManager.GetString("menuMsgViewFilter", resourceCulture);
}
}
/// <summary>
/// 查找类似 Select all (Ctrl+A) 的本地化字符串。
/// </summary>
@@ -960,6 +978,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Open the storage location 的本地化字符串。
/// </summary>
public static string menuOpenTheFileLocation {
get {
return ResourceManager.GetString("menuOpenTheFileLocation", resourceCulture);
}
}
/// <summary>
/// 查找类似 Option Setting 的本地化字符串。
/// </summary>
@@ -969,6 +996,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Auto column width adjustment 的本地化字符串。
/// </summary>
public static string menuProfileAutofitColumnWidth {
get {
return ResourceManager.GetString("menuProfileAutofitColumnWidth", resourceCulture);
}
}
/// <summary>
/// 查找类似 Promotion 的本地化字符串。
/// </summary>
@@ -978,6 +1014,42 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Latency Test 的本地化字符串。
/// </summary>
public static string menuProxiesDelaytest {
get {
return ResourceManager.GetString("menuProxiesDelaytest", resourceCulture);
}
}
/// <summary>
/// 查找类似 Part Node Latency Test 的本地化字符串。
/// </summary>
public static string menuProxiesDelaytestPart {
get {
return ResourceManager.GetString("menuProxiesDelaytestPart", resourceCulture);
}
}
/// <summary>
/// 查找类似 Refresh Proxies 的本地化字符串。
/// </summary>
public static string menuProxiesReload {
get {
return ResourceManager.GetString("menuProxiesReload", resourceCulture);
}
}
/// <summary>
/// 查找类似 Select active node (Enter) 的本地化字符串。
/// </summary>
public static string menuProxiesSelectActivity {
get {
return ResourceManager.GetString("menuProxiesSelectActivity", resourceCulture);
}
}
/// <summary>
/// 查找类似 Test servers real delay (Ctrl+R) 的本地化字符串。
/// </summary>
@@ -1149,6 +1221,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Rule mode 的本地化字符串。
/// </summary>
public static string menuRulemode {
get {
return ResourceManager.GetString("menuRulemode", resourceCulture);
}
}
/// <summary>
/// 查找类似 Remove Rule (Delete) 的本地化字符串。
/// </summary>
@@ -1176,6 +1257,24 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Multi-server load balancing 的本地化字符串。
/// </summary>
public static string menuSetDefaultLoadBalanceServer {
get {
return ResourceManager.GetString("menuSetDefaultLoadBalanceServer", resourceCulture);
}
}
/// <summary>
/// 查找类似 Multi-Server lowest latency 的本地化字符串。
/// </summary>
public static string menuSetDefaultMultipleServer {
get {
return ResourceManager.GetString("menuSetDefaultMultipleServer", resourceCulture);
}
}
/// <summary>
/// 查找类似 Set as active server (Enter) 的本地化字符串。
/// </summary>
@@ -1267,7 +1366,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Subscription group 的本地化字符串。
/// 查找类似 Subscription Group 的本地化字符串。
/// </summary>
public static string menuSubscription {
get {
@@ -1294,7 +1393,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Update subscription without proxy 的本地化字符串。
/// 查找类似 Update subscriptions without proxy 的本地化字符串。
/// </summary>
public static string menuSubUpdate {
get {
@@ -1303,7 +1402,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Update subscription with proxy 的本地化字符串。
/// 查找类似 Update subscriptions with proxy 的本地化字符串。
/// </summary>
public static string menuSubUpdateViaProxy {
get {
@@ -1365,15 +1464,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Test current service status 的本地化字符串。
/// </summary>
public static string menuTestMe {
get {
return ResourceManager.GetString("menuTestMe", resourceCulture);
}
}
/// <summary>
/// 查找类似 {0} Website 的本地化字符串。
/// </summary>
@@ -1528,7 +1618,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Update subscription end 的本地化字符串。
/// 查找类似 Update subscriptions end 的本地化字符串。
/// </summary>
public static string MsgUpdateSubscriptionEnd {
get {
@@ -1537,7 +1627,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Update subscription starts 的本地化字符串。
/// 查找类似 Update subscriptions start 的本地化字符串。
/// </summary>
public static string MsgUpdateSubscriptionStart {
get {
@@ -1563,6 +1653,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Successful operation. Click the settings menu to reboot the app. 的本地化字符串。
/// </summary>
public static string NeedRebootTips {
get {
return ResourceManager.GetString("NeedRebootTips", resourceCulture);
}
}
/// <summary>
/// 查找类似 Non-VMess or ss protocol 的本地化字符串。
/// </summary>
@@ -1572,15 +1671,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Non-standard service, this feature is invalid 的本地化字符串。
/// </summary>
public static string NonVmessService {
get {
return ResourceManager.GetString("NonVmessService", resourceCulture);
}
}
/// <summary>
/// 查找类似 The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2} 的本地化字符串。
/// </summary>
@@ -1807,7 +1897,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Group please leave blank here 的本地化字符串。
/// 查找类似 For group please leave blank here 的本地化字符串。
/// </summary>
public static string SubUrlTips {
get {
@@ -1852,15 +1942,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 System proxy 的本地化字符串。
/// </summary>
public static string SystemProxy {
get {
return ResourceManager.GetString("SystemProxy", resourceCulture);
}
}
/// <summary>
/// 查找类似 Address 的本地化字符串。
/// </summary>
@@ -1960,6 +2041,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Connections 的本地化字符串。
/// </summary>
public static string TbConnections {
get {
return ResourceManager.GetString("TbConnections", resourceCulture);
}
}
/// <summary>
/// 查找类似 Core Type 的本地化字符串。
/// </summary>
@@ -2230,6 +2320,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Proxies 的本地化字符串。
/// </summary>
public static string TbProxies {
get {
return ResourceManager.GetString("TbProxies", resourceCulture);
}
}
/// <summary>
/// 查找类似 PublicKey 的本地化字符串。
/// </summary>
@@ -2572,6 +2671,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Outbound DNS address 的本地化字符串。
/// </summary>
public static string TbSettingsDomainDNSAddress {
get {
return ResourceManager.GetString("TbSettingsDomainDNSAddress", resourceCulture);
}
}
/// <summary>
/// 查找类似 Outbound Freedom domainStrategy 的本地化字符串。
/// </summary>
@@ -2581,6 +2689,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Default domain strategy for outbound 的本地化字符串。
/// </summary>
public static string TbSettingsDomainStrategy4Out {
get {
return ResourceManager.GetString("TbSettingsDomainStrategy4Out", resourceCulture);
}
}
/// <summary>
/// 查找类似 Double-click server make active 的本地化字符串。
/// </summary>
@@ -2599,6 +2716,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Enable cache file for sing-box (ruleset files) 的本地化字符串。
/// </summary>
public static string TbSettingsEnableCacheFile4Sbox {
get {
return ResourceManager.GetString("TbSettingsEnableCacheFile4Sbox", resourceCulture);
}
}
/// <summary>
/// 查找类似 Check for pre-release updates 的本地化字符串。
/// </summary>
@@ -2626,6 +2752,24 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Enable fragment 的本地化字符串。
/// </summary>
public static string TbSettingsEnableFragment {
get {
return ResourceManager.GetString("TbSettingsEnableFragment", resourceCulture);
}
}
/// <summary>
/// 查找类似 Use Xray and enable non-Tun mode, which conflicts with the group previous proxy 的本地化字符串。
/// </summary>
public static string TbSettingsEnableFragmentTips {
get {
return ResourceManager.GetString("TbSettingsEnableFragmentTips", resourceCulture);
}
}
/// <summary>
/// 查找类似 Enable hardware acceleration(Require restart) 的本地化字符串。
/// </summary>
@@ -2761,6 +2905,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Main layout orientation(Require restart) 的本地化字符串。
/// </summary>
public static string TbSettingsMainGirdOrientation {
get {
return ResourceManager.GetString("TbSettingsMainGirdOrientation", resourceCulture);
}
}
/// <summary>
/// 查找类似 sing-box Mux Protocol 的本地化字符串。
/// </summary>
@@ -2797,6 +2950,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Do not use proxy servers for local (intranet) addresses 的本地化字符串。
/// </summary>
public static string TbSettingsNotProxyLocalAddress {
get {
return ResourceManager.GetString("TbSettingsNotProxyLocalAddress", resourceCulture);
}
}
/// <summary>
/// 查找类似 Auth pass 的本地化字符串。
/// </summary>
@@ -2852,7 +3014,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 HTTP port=SOCKS port+1;Pac port=SOCKS port+4;API port=SOCKS port+5; 的本地化字符串。
/// 查找类似 http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6; 的本地化字符串。
/// </summary>
public static string TbSettingsSocksPortTip {
get {
@@ -2959,78 +3121,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Bypass Mode 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeBypassMode {
get {
return ResourceManager.GetString("TbSettingsTunModeBypassMode", resourceCulture);
}
}
/// <summary>
/// 查找类似 Custom Template 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeCustomTemplate {
get {
return ResourceManager.GetString("TbSettingsTunModeCustomTemplate", resourceCulture);
}
}
/// <summary>
/// 查找类似 Direct IP CIDR, separated by commas (,) 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeDirectIP {
get {
return ResourceManager.GetString("TbSettingsTunModeDirectIP", resourceCulture);
}
}
/// <summary>
/// 查找类似 Direct Process name, separated by commas (,) 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeDirectProcess {
get {
return ResourceManager.GetString("TbSettingsTunModeDirectProcess", resourceCulture);
}
}
/// <summary>
/// 查找类似 DNS object, e.g. {&quot;servers&quot;:[]} 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeDNS {
get {
return ResourceManager.GetString("TbSettingsTunModeDNS", resourceCulture);
}
}
/// <summary>
/// 查找类似 Proxy IP CIDR, separated by commas (,) 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeProxyIP {
get {
return ResourceManager.GetString("TbSettingsTunModeProxyIP", resourceCulture);
}
}
/// <summary>
/// 查找类似 Proxy Process name, separated by commas (,) 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeProxyProcess {
get {
return ResourceManager.GetString("TbSettingsTunModeProxyProcess", resourceCulture);
}
}
/// <summary>
/// 查找类似 Show console 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeShowWindow {
get {
return ResourceManager.GetString("TbSettingsTunModeShowWindow", resourceCulture);
}
}
/// <summary>
/// 查找类似 Enable UDP 的本地化字符串。
/// </summary>
@@ -3076,6 +3166,123 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Sorting 的本地化字符串。
/// </summary>
public static string TbSorting {
get {
return ResourceManager.GetString("TbSorting", resourceCulture);
}
}
/// <summary>
/// 查找类似 Chain 的本地化字符串。
/// </summary>
public static string TbSortingChain {
get {
return ResourceManager.GetString("TbSortingChain", resourceCulture);
}
}
/// <summary>
/// 查找类似 Default 的本地化字符串。
/// </summary>
public static string TbSortingDefault {
get {
return ResourceManager.GetString("TbSortingDefault", resourceCulture);
}
}
/// <summary>
/// 查找类似 Delay 的本地化字符串。
/// </summary>
public static string TbSortingDelay {
get {
return ResourceManager.GetString("TbSortingDelay", resourceCulture);
}
}
/// <summary>
/// 查找类似 Download Speed 的本地化字符串。
/// </summary>
public static string TbSortingDownSpeed {
get {
return ResourceManager.GetString("TbSortingDownSpeed", resourceCulture);
}
}
/// <summary>
/// 查找类似 Download Traffic 的本地化字符串。
/// </summary>
public static string TbSortingDownTraffic {
get {
return ResourceManager.GetString("TbSortingDownTraffic", resourceCulture);
}
}
/// <summary>
/// 查找类似 Host 的本地化字符串。
/// </summary>
public static string TbSortingHost {
get {
return ResourceManager.GetString("TbSortingHost", resourceCulture);
}
}
/// <summary>
/// 查找类似 Name 的本地化字符串。
/// </summary>
public static string TbSortingName {
get {
return ResourceManager.GetString("TbSortingName", resourceCulture);
}
}
/// <summary>
/// 查找类似 Network 的本地化字符串。
/// </summary>
public static string TbSortingNetwork {
get {
return ResourceManager.GetString("TbSortingNetwork", resourceCulture);
}
}
/// <summary>
/// 查找类似 Time 的本地化字符串。
/// </summary>
public static string TbSortingTime {
get {
return ResourceManager.GetString("TbSortingTime", resourceCulture);
}
}
/// <summary>
/// 查找类似 Type 的本地化字符串。
/// </summary>
public static string TbSortingType {
get {
return ResourceManager.GetString("TbSortingType", resourceCulture);
}
}
/// <summary>
/// 查找类似 Upload Speed 的本地化字符串。
/// </summary>
public static string TbSortingUpSpeed {
get {
return ResourceManager.GetString("TbSortingUpSpeed", resourceCulture);
}
}
/// <summary>
/// 查找类似 Upload Traffic 的本地化字符串。
/// </summary>
public static string TbSortingUpTraffic {
get {
return ResourceManager.GetString("TbSortingUpTraffic", resourceCulture);
}
}
/// <summary>
/// 查找类似 SpiderX 的本地化字符串。
/// </summary>
@@ -3149,7 +3356,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 * After setting this value, an socks service will be started using sing-box to provide functions such as speed display 的本地化字符串。
/// 查找类似 * After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display 的本地化字符串。
/// </summary>
public static string TipPreSocksPort {
get {
@@ -3157,15 +3364,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Too many servers, please open the main interface 的本地化字符串。
/// </summary>
public static string TooManyServersTip {
get {
return ResourceManager.GetString("TooManyServersTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 *tcp camouflage type 的本地化字符串。
/// </summary>
@@ -3203,7 +3401,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 *ws/httpupgrade path 的本地化字符串。
/// 查找类似 *ws/httpupgrade/splithttp path 的本地化字符串。
/// </summary>
public static string TransportPathTip1 {
get {
@@ -3257,7 +3455,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 *ws/httpupgrade host 的本地化字符串。
/// 查找类似 *ws/httpupgrade/splithttp host 的本地化字符串。
/// </summary>
public static string TransportRequestHostTip2 {
get {

View File

@@ -117,9 +117,6 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
<value>صادرات دسته ای محتوای اشتراک به کلیپ بورد با موفقیت انجام شد</value>
</data>
<data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>Batch export share URL to clipboard successfully</value>
</data>
@@ -159,9 +156,6 @@
<data name="FillCorrectServerPort" xml:space="preserve">
<value>لطفا فرمت صحیح پورت سرور را پر کنید</value>
</data>
<data name="FillKcpParameters" xml:space="preserve">
<value>لطفاً پارامترهای KCP را به درستی پر کنید</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>لطفاً پورت گوش دادن محلی را پر کنید</value>
</data>
@@ -174,15 +168,9 @@
<data name="FillUUID" xml:space="preserve">
<value>لطفا شناسه کاربری را وارد کنید</value>
</data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value>فایل پیکربندی مشتری صحیح نیست، لطفا بررسی کنید</value>
</data>
<data name="Incorrectconfiguration" xml:space="preserve">
<value>پیکربندی درستی نیست، لطفا بررسی کنید</value>
</data>
<data name="IncorrectServerConfiguration" xml:space="preserve">
<value>فایل پیکربندی سرور صحیح نیست، لطفا بررسی کنید</value>
</data>
<data name="InitialConfiguration" xml:space="preserve">
<value>پیکربندی اولیه</value>
</data>
@@ -267,9 +255,6 @@
<data name="NonvmessOrssProtocol" xml:space="preserve">
<value>Non-VMess or ss protocol</value>
</data>
<data name="NonVmessService" xml:space="preserve">
<value> non-standard service, this feature is invalid</value>
</data>
<data name="NotFoundCore" xml:space="preserve">
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
</data>
@@ -415,15 +400,9 @@
<data name="FillServerAddressCustom" xml:space="preserve">
<value>Please browse to import server configuration</value>
</data>
<data name="SystemProxy" xml:space="preserve">
<value>پروکسی سیستم</value>
</data>
<data name="Speedtesting" xml:space="preserve">
<value>درحال تست کردن...</value>
</data>
<data name="TooManyServersTip" xml:space="preserve">
<value>تعداد سرورها خیلی زیاد است، لطفا رابط اصلی را باز کنید</value>
</data>
<data name="LabLAN" xml:space="preserve">
<value>LAN</value>
</data>
@@ -541,18 +520,12 @@
<data name="menuTcpingServer" xml:space="preserve">
<value>تست سرورها با tcping (Ctrl+O)</value>
</data>
<data name="menuTestMe" xml:space="preserve">
<value>وضعیت سرویس فعلی را تست کنید</value>
</data>
<data name="menuExport2ClientConfig" xml:space="preserve">
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
</data>
<data name="menuExport2ShareUrl" xml:space="preserve">
<value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value>
</data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>اشتراک (base64) را به کلیپ بورد صادر کنید</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>یک سرور پیکربندی سفارشی اضافه شود</value>
</data>
@@ -583,9 +556,6 @@
<data name="menuMsgViewCopyAll" xml:space="preserve">
<value>کپی همه</value>
</data>
<data name="menuMsgViewFilter" xml:space="preserve">
<value>فیلترهای پیام را تنظیم کنید</value>
</data>
<data name="menuMsgViewSelectAll" xml:space="preserve">
<value>انتخاب همه (Ctrl+A)</value>
</data>
@@ -698,7 +668,7 @@
<value>txtPreSocksPort</value>
</data>
<data name="TipPreSocksPort" xml:space="preserve">
<value>* After setting this value, an socks service will be started using sing-box to provide functions such as speed display</value>
<value>* After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display</value>
</data>
<data name="TbBrowse" xml:space="preserve">
<value>Browse</value>
@@ -955,6 +925,9 @@
<data name="TbSettingsRouteOnly" xml:space="preserve">
<value>فقط مسیر</value>
</data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>يەرلىك (Intranet) ئادرېسلارغا ۋاكالەتچى مۇلازىمېتىر ئىشلەتمەڭ</value>
</data>
<data name="menuMixedTestServer" xml:space="preserve">
<value>One-click test Latency and speed (Ctrl+E)</value>
</data>
@@ -985,15 +958,6 @@
<data name="TbSettingsTunMode" xml:space="preserve">
<value>تنظیمات TunMode</value>
</data>
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
<value>Direct IP CIDR, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
<value>Direct Process name, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>نمایش کنسول</value>
</data>
<data name="TbSettingsDefUserAgent" xml:space="preserve">
<value>User-Agent</value>
</data>
@@ -1003,4 +967,70 @@
<data name="TbSettingsEnableHWA" xml:space="preserve">
<value>فعال‌سازی شتاب‌دهنده سخت‌افزاری (نیاز به راه‌اندازی مجدد)</value>
</data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>مرتب سازی</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>تاخیر</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>سرعت دانلود</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>ترافیک دانلود</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>نام</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>زمان</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>سرعت اپلود</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>ترافیک آپلود</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>اتصالات</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>بستن اتصال</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>تمام اتصالات را ببندید</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>پروکسی</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>نوع قانون</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>Direct</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>Global</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>تغییر نده</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>قانون</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>Latency Test</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>Part Node Latency Test</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value>
</data>
</root>

View File

@@ -117,9 +117,6 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
<value>Batch export subscription to clipboard successfully</value>
</data>
<data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>Batch export share URL to clipboard successfully</value>
</data>
@@ -159,9 +156,6 @@
<data name="FillCorrectServerPort" xml:space="preserve">
<value>Please fill in the correct format server port</value>
</data>
<data name="FillKcpParameters" xml:space="preserve">
<value>Please fill in the KCP parameters correctly</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>Please fill in the local listening port</value>
</data>
@@ -174,15 +168,9 @@
<data name="FillUUID" xml:space="preserve">
<value>Please fill in the user ID</value>
</data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value>Is not the correct client configuration file, please check</value>
</data>
<data name="Incorrectconfiguration" xml:space="preserve">
<value>Is not the correct configuration, please check</value>
</data>
<data name="IncorrectServerConfiguration" xml:space="preserve">
<value>Is not the correct server configuration file, please check</value>
</data>
<data name="InitialConfiguration" xml:space="preserve">
<value>Initial Configuration</value>
</data>
@@ -253,10 +241,10 @@
<value>Is unpacking......</value>
</data>
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
<value>Update subscription end</value>
<value>Update subscriptions end</value>
</data>
<data name="MsgUpdateSubscriptionStart" xml:space="preserve">
<value>Update subscription starts</value>
<value>Update subscriptions start</value>
</data>
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
<value>Update Core successfully</value>
@@ -267,9 +255,6 @@
<data name="NonvmessOrssProtocol" xml:space="preserve">
<value>Non-VMess or ss protocol</value>
</data>
<data name="NonVmessService" xml:space="preserve">
<value>Non-standard service, this feature is invalid</value>
</data>
<data name="NotFoundCore" xml:space="preserve">
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
</data>
@@ -359,7 +344,7 @@
<value>Please fill in the correct custom DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade path</value>
<value>*ws/httpupgrade/splithttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -374,7 +359,7 @@
<value>*http host Separated by commas (,)</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade host</value>
<value>*ws/httpupgrade/splithttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host Separated by commas (,)</value>
@@ -415,15 +400,9 @@
<data name="FillServerAddressCustom" xml:space="preserve">
<value>Please browse to import server configuration</value>
</data>
<data name="SystemProxy" xml:space="preserve">
<value>System proxy</value>
</data>
<data name="Speedtesting" xml:space="preserve">
<value>Testing...</value>
</data>
<data name="TooManyServersTip" xml:space="preserve">
<value>Too many servers, please open the main interface</value>
</data>
<data name="LabLAN" xml:space="preserve">
<value>LAN</value>
</data>
@@ -473,16 +452,16 @@
<value>Update current subscription with proxy</value>
</data>
<data name="menuSubscription" xml:space="preserve">
<value>Subscription group</value>
<value>Subscription Group</value>
</data>
<data name="menuSubSetting" xml:space="preserve">
<value>Subscription group settings</value>
</data>
<data name="menuSubUpdate" xml:space="preserve">
<value>Update subscription without proxy</value>
<value>Update subscriptions without proxy</value>
</data>
<data name="menuSubUpdateViaProxy" xml:space="preserve">
<value>Update subscription with proxy</value>
<value>Update subscriptions with proxy</value>
</data>
<data name="menuSystemproxy" xml:space="preserve">
<value>System proxy</value>
@@ -544,18 +523,12 @@
<data name="menuTcpingServer" xml:space="preserve">
<value>Test servers with tcping (Ctrl+O)</value>
</data>
<data name="menuTestMe" xml:space="preserve">
<value>Test current service status</value>
</data>
<data name="menuExport2ClientConfig" xml:space="preserve">
<value>Export selected server for client configuration</value>
</data>
<data name="menuExport2ShareUrl" xml:space="preserve">
<value>Export share URLs to clipboard (Ctrl+C)</value>
</data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>Export subscription (base64) share to clipboard</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>Add a custom configuration server</value>
</data>
@@ -586,9 +559,6 @@
<data name="menuMsgViewCopyAll" xml:space="preserve">
<value>Copy all</value>
</data>
<data name="menuMsgViewFilter" xml:space="preserve">
<value>Set message filters</value>
</data>
<data name="menuMsgViewSelectAll" xml:space="preserve">
<value>Select all (Ctrl+A)</value>
</data>
@@ -605,7 +575,7 @@
<value>Share</value>
</data>
<data name="LvEnabled" xml:space="preserve">
<value>Enabled Update</value>
<value>Enable update</value>
</data>
<data name="LvSort" xml:space="preserve">
<value>Sort</value>
@@ -701,7 +671,7 @@
<value>txtPreSocksPort</value>
</data>
<data name="TipPreSocksPort" xml:space="preserve">
<value>* After setting this value, an socks service will be started using sing-box to provide functions such as speed display</value>
<value>* After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display</value>
</data>
<data name="TbBrowse" xml:space="preserve">
<value>Browse</value>
@@ -947,7 +917,7 @@
<value>Support DnsObject, Click to view the document</value>
</data>
<data name="SubUrlTips" xml:space="preserve">
<value>Group please leave blank here</value>
<value>For group please leave blank here</value>
</data>
<data name="TipChangeRouting" xml:space="preserve">
<value>Routing setting is changed</value>
@@ -958,6 +928,9 @@
<data name="TbSettingsRouteOnly" xml:space="preserve">
<value>RouteOnly</value>
</data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>Do not use proxy servers for local (intranet) addresses</value>
</data>
<data name="menuMixedTestServer" xml:space="preserve">
<value>One-click multi test Latency and speed (Ctrl+E)</value>
</data>
@@ -988,21 +961,9 @@
<data name="TbSettingsTunMode" xml:space="preserve">
<value>TunMode settings</value>
</data>
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
<value>Direct IP CIDR, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
<value>Direct Process name, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>Show console</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve">
<value>Move to group</value>
</data>
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
<value>Custom Template</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Enable Server Drag Drop Sort(Require restart)</value>
</data>
@@ -1037,7 +998,7 @@
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>HTTP port=SOCKS port+1;Pac port=SOCKS port+4;API port=SOCKS port+5;</value>
<value>http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>Set this with admin privileges, get admin privileges after startup</value>
@@ -1045,24 +1006,12 @@
<data name="TbSettingsFontSize" xml:space="preserve">
<value>Font Size</value>
</data>
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
<value>Proxy IP CIDR, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
<value>Proxy Process name, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
<value>Bypass Mode</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>SpeedTest Single Timeout Value</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>SpeedTest URL</value>
</data>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS object, e.g. {"servers":[]}</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</value>
</data>
@@ -1091,13 +1040,13 @@
<value>Restart as Administrator</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>More urls, separated by commas;Subscription conversion will be invalid</value>
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0} : {1}/s↑ | {2}/s↓</value>
</data>
<data name="LvAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval(minutes)</value>
<value>Automatic update interval (minutes)</value>
</data>
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
<value>Enable logging to file</value>
@@ -1198,4 +1147,121 @@
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Add [Http] server</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</value>
</data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>Enable cache file for sing-box (ruleset files)</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>Custom the rule-set of sing-box</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>Successful operation. Click the settings menu to reboot the app.</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>Open the storage location</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>Sorting</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>Chain</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>Delay</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>Download Speed</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>Download Traffic</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>Host</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>Name</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>Network</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>Time</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>Type</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>Upload Speed</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>Upload Traffic</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>Connections</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>Close Connection</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>Close All Connection</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>Proxies</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>Rule mode</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>Direct</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>Global</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>Do not change</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>Rule</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>Latency Test</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>Part Node Latency Test</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>Refresh Proxies</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Default domain strategy for outbound</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>Multi-Server lowest latency</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>Main layout orientation(Require restart)</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>Multi-server load balancing</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound DNS address</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>Auto column width adjustment</value>
</data>
</root>

View File

@@ -117,9 +117,6 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
<value>Экспортирование подписок в буфер обмена успешно завершено</value>
</data>
<data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>Экспортирование URL в буфер обмена успешно завершено</value>
</data>
@@ -159,9 +156,6 @@
<data name="FillCorrectServerPort" xml:space="preserve">
<value>Пожалуйста, укажите порт сервера в правильном формате</value>
</data>
<data name="FillKcpParameters" xml:space="preserve">
<value>Пожалуйста, заполните параметры KCP корректно</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>Пожалуйста, укажите локальный порт прослушивания</value>
</data>
@@ -174,15 +168,9 @@
<data name="FillUUID" xml:space="preserve">
<value>Пожалуйста, заполните идентификатор пользователя</value>
</data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value>Некорректный файл конфигурации клиента, пожалуйста, проверьте</value>
</data>
<data name="Incorrectconfiguration" xml:space="preserve">
<value>Некорректная конфигурация, пожалуйста, проверьте</value>
</data>
<data name="IncorrectServerConfiguration" xml:space="preserve">
<value>Некорректный файл конфигурации сервера, пожалуйста, проверьте</value>
</data>
<data name="InitialConfiguration" xml:space="preserve">
<value>Исходная конфигурация</value>
</data>
@@ -267,9 +255,6 @@
<data name="NonvmessOrssProtocol" xml:space="preserve">
<value>Не является протоколом Vmess или SS</value>
</data>
<data name="NonVmessService" xml:space="preserve">
<value> нестандартный сервис, эта функция недействительна</value>
</data>
<data name="NotFoundCore" xml:space="preserve">
<value>Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2}</value>
</data>
@@ -415,15 +400,9 @@
<data name="FillServerAddressCustom" xml:space="preserve">
<value>Пожалуйста, просмотрите, чтобы импортировать конфигурацию сервера</value>
</data>
<data name="SystemProxy" xml:space="preserve">
<value>Системный прокси</value>
</data>
<data name="Speedtesting" xml:space="preserve">
<value>Тестирование...</value>
</data>
<data name="TooManyServersTip" xml:space="preserve">
<value>Слишком много серверов, пожалуйста, откройте главный интерфейс</value>
</data>
<data name="LabLAN" xml:space="preserve">
<value>LAN</value>
</data>
@@ -544,18 +523,12 @@
<data name="menuTcpingServer" xml:space="preserve">
<value>Тест задержки с tcping (Ctrl+O)</value>
</data>
<data name="menuTestMe" xml:space="preserve">
<value>Проверить текущий статус службы</value>
</data>
<data name="menuExport2ClientConfig" xml:space="preserve">
<value>Экспортировать выбранный сервер для клиента</value>
</data>
<data name="menuExport2ShareUrl" xml:space="preserve">
<value>Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C)</value>
</data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>Экспортировать ссылку-подписку (base64) в буфер обмена</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>Добавить сервер пользовательской конфигурации</value>
</data>
@@ -586,9 +559,6 @@
<data name="menuMsgViewCopyAll" xml:space="preserve">
<value>Скопировать все</value>
</data>
<data name="menuMsgViewFilter" xml:space="preserve">
<value>Установить фильтры сообщений</value>
</data>
<data name="menuMsgViewSelectAll" xml:space="preserve">
<value>Выбрать все (Ctrl+A)</value>
</data>
@@ -701,7 +671,7 @@
<value>txtPreSocksPort</value>
</data>
<data name="TipPreSocksPort" xml:space="preserve">
<value>* После установки этого значения служба socks будет запущена с использованием sing-box для обеспечения таких функций, как отображение скорости</value>
<value>* После установки этого значения служба socks будет запущена с использованием Xray/sing-box(Tun) для обеспечения таких функций, как отображение скорости</value>
</data>
<data name="TbBrowse" xml:space="preserve">
<value>Просмотр</value>
@@ -964,6 +934,9 @@
<data name="TbSettingsRouteOnly" xml:space="preserve">
<value>Только маршрут</value>
</data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>Не используйте прокси-серверы для локальных (интранет) адресов</value>
</data>
<data name="menuMixedTestServer" xml:space="preserve">
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
</data>
@@ -994,21 +967,9 @@
<data name="TbSettingsTunMode" xml:space="preserve">
<value>Настройки TunMode</value>
</data>
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
<value>Прямой IP CIDR, разделенный запятыми (,)</value>
</data>
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
<value>Имя процесса, разделенное запятыми (,)</value>
</data>
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>Показать консоль</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve">
<value>Перейти в группу</value>
</data>
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
<value>Пользовательский шаблон</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Включить сортировку перетаскиванием сервера (требуется перезагрузка)</value>
</data>
@@ -1042,9 +1003,6 @@
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>Скопируйте файл шрифта TTF/TTC в каталог guiFonts, перезапустите настройки</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>HTTP port=socks port+1</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>Установите это с правами администратора</value>
</data>

View File

@@ -117,9 +117,6 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
<value>批量导出订阅内容至剪贴板成功</value>
</data>
<data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>批量导出分享URL至剪贴板成功</value>
</data>
@@ -159,9 +156,6 @@
<data name="FillCorrectServerPort" xml:space="preserve">
<value>请填写正确格式服务器端口</value>
</data>
<data name="FillKcpParameters" xml:space="preserve">
<value>请正确填写KCP参数</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>请填写本地监听端口</value>
</data>
@@ -174,15 +168,9 @@
<data name="FillUUID" xml:space="preserve">
<value>请填写用户ID</value>
</data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value>不是正确的客户端配置文件,请检查</value>
</data>
<data name="Incorrectconfiguration" xml:space="preserve">
<value>不是正确的配置,请检查</value>
</data>
<data name="IncorrectServerConfiguration" xml:space="preserve">
<value>不是正确的服务端配置文件,请检查</value>
</data>
<data name="InitialConfiguration" xml:space="preserve">
<value>初始化配置</value>
</data>
@@ -267,9 +255,6 @@
<data name="NonvmessOrssProtocol" xml:space="preserve">
<value>非VMess或ss协议</value>
</data>
<data name="NonVmessService" xml:space="preserve">
<value>非标准服务,此功能无效</value>
</data>
<data name="NotFoundCore" xml:space="preserve">
<value>在文件夹 ({0}) 下未找到Core文件 (文件名:{1}),请下载后放入文件夹,下载地址: {2}</value>
</data>
@@ -359,7 +344,7 @@
<value>请填写正确的自定义DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade path</value>
<value>*ws/httpupgrade/splithttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -374,7 +359,7 @@
<value>*http host中间逗号(,)分隔</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade host</value>
<value>*ws/httpupgrade/splithttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中间逗号(,)分隔</value>
@@ -415,15 +400,9 @@
<data name="FillServerAddressCustom" xml:space="preserve">
<value>请浏览导入服务器配置</value>
</data>
<data name="SystemProxy" xml:space="preserve">
<value>系统代理</value>
</data>
<data name="Speedtesting" xml:space="preserve">
<value>测试中...</value>
</data>
<data name="TooManyServersTip" xml:space="preserve">
<value>服务器太多,请打开主界面操作</value>
</data>
<data name="LabLAN" xml:space="preserve">
<value>局域网</value>
</data>
@@ -544,18 +523,12 @@
<data name="menuTcpingServer" xml:space="preserve">
<value>测试服务器延迟Tcping(多选) (Ctrl+O)</value>
</data>
<data name="menuTestMe" xml:space="preserve">
<value>测试当前服务状态</value>
</data>
<data name="menuExport2ClientConfig" xml:space="preserve">
<value>导出所选服务器为客户端配置</value>
</data>
<data name="menuExport2ShareUrl" xml:space="preserve">
<value>批量导出分享URL至剪贴板(多选) (Ctrl+C)</value>
</data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>批量导出订阅内容至剪贴板(多选)</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>添加自定义配置服务器</value>
</data>
@@ -586,9 +559,6 @@
<data name="menuMsgViewCopyAll" xml:space="preserve">
<value>复制所有</value>
</data>
<data name="menuMsgViewFilter" xml:space="preserve">
<value>设置信息过滤器</value>
</data>
<data name="menuMsgViewSelectAll" xml:space="preserve">
<value>全选 (Ctrl+A)</value>
</data>
@@ -701,7 +671,7 @@
<value>Socks端口</value>
</data>
<data name="TipPreSocksPort" xml:space="preserve">
<value>* 自定义配置的Socks端口值可不设置当设置此值后将使用sing-box额外启动一个前置Socks服务提供分流和速度显示等功能</value>
<value>* 自定义配置的Socks端口值可不设置当设置此值后将使用Xray/sing-box(Tun)额外启动一个前置Socks服务提供分流和速度显示等功能</value>
</data>
<data name="TbBrowse" xml:space="preserve">
<value>浏览</value>
@@ -958,6 +928,9 @@
<data name="TbSettingsRouteOnly" xml:space="preserve">
<value>RouteOnly</value>
</data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>请勿将代理服务器用于本地Intranet地址</value>
</data>
<data name="menuMixedTestServer" xml:space="preserve">
<value>一键多线程测试延迟和速度 (Ctrl+E)</value>
</data>
@@ -988,21 +961,9 @@
<data name="TbSettingsTunMode" xml:space="preserve">
<value>Tun模式设置</value>
</data>
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
<value>直连的IP CIDR用逗号(,)分隔</value>
</data>
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
<value>直连的进程名,用逗号(,)分隔</value>
</data>
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>显示控制台</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve">
<value>移至订阅分组</value>
</data>
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
<value>自定义配置模板</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>启用服务器拖放排序(需重启)</value>
</data>
@@ -1037,7 +998,7 @@
<value>拷贝字体TTF/TTC文件到目录guiFonts重启设置</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口=socks端口+1Pac端口=socks端口+4API端口=socks端口+5</value>
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
@@ -1045,24 +1006,12 @@
<data name="TbSettingsFontSize" xml:space="preserve">
<value>字体大小</value>
</data>
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
<value>代理的IP CIDR用逗号(,)分隔</value>
</data>
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
<value>代理的进程名,用逗号(,)分隔</value>
</data>
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
<value>绕行模式</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>测速单个超时值</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>测速文件地址</value>
</data>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS对象例如 {"servers":[]}</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>移至上下</value>
</data>
@@ -1195,4 +1144,121 @@
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>添加[Http]服务器</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>启用分片Fragment</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>使用Xray且非Tun模式启用和分组前置代理冲突</value>
</data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>启用sing-box规则集文件的缓存文件</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>自定义sing-box rule-set</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>操作成功。请点击设置菜单重启应用。</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>打开存储所在的位置</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>排序</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>路由链</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>默认</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>延迟</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>下载速度</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>下载流量</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>主机</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>名称</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>网络</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>时间</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>类型</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>上传速度</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>上传流量</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>当前连接</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>关闭连接</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>关闭所有连接</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>当前代理</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>规则模式</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>直连</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>全局</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>随原配置</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>规则</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>延迟测试</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>当前部分节点延迟测试</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>刷新</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>设为活动节点 (Enter)</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Outbound默认解析策略</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>多服务器最低延迟 (多选)</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>主界面布局方向(需重启)</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>多服务器负载均衡 (多选)</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound域名解析地址</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>自动调整列宽</value>
</data>
</root>

View File

@@ -117,9 +117,6 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
<value>批次匯出訂閱內容至剪貼簿成功</value>
</data>
<data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>批次匯出分享URL至剪貼簿成功</value>
</data>
@@ -159,9 +156,6 @@
<data name="FillCorrectServerPort" xml:space="preserve">
<value>請填寫正確格式伺服器埠</value>
</data>
<data name="FillKcpParameters" xml:space="preserve">
<value>請正確填寫KCP參數</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>請填寫本機監聽埠</value>
</data>
@@ -174,15 +168,9 @@
<data name="FillUUID" xml:space="preserve">
<value>請填寫使用者ID</value>
</data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value>不是正確的用戶端配置檔案,請檢查</value>
</data>
<data name="Incorrectconfiguration" xml:space="preserve">
<value>不是正確的配置,請檢查</value>
</data>
<data name="IncorrectServerConfiguration" xml:space="preserve">
<value>不是正確的服務端配置檔案,請檢查</value>
</data>
<data name="InitialConfiguration" xml:space="preserve">
<value>初始化配置</value>
</data>
@@ -267,9 +255,6 @@
<data name="NonvmessOrssProtocol" xml:space="preserve">
<value>非VMess或SS協定</value>
</data>
<data name="NonVmessService" xml:space="preserve">
<value>非標準服務,此功能無效</value>
</data>
<data name="NotFoundCore" xml:space="preserve">
<value>在資料夾 ({0}) 下未找到Core文件 (檔案名:{1}),請下載後放入資料夾、,下載網址: {2}</value>
</data>
@@ -358,7 +343,7 @@
<value>請填寫正確的自訂DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade path</value>
<value>*ws/httpupgrade/splithttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -373,7 +358,7 @@
<value>*http host中間逗號(,)分隔</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade host</value>
<value>*ws/httpupgrade/splithttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中間逗號(,)分隔</value>
@@ -414,15 +399,9 @@
<data name="FillServerAddressCustom" xml:space="preserve">
<value>請瀏覽匯入伺服器配置</value>
</data>
<data name="SystemProxy" xml:space="preserve">
<value>系統代理</value>
</data>
<data name="Speedtesting" xml:space="preserve">
<value>測試中...</value>
</data>
<data name="TooManyServersTip" xml:space="preserve">
<value>伺服器太多,請打開主介面操作</value>
</data>
<data name="LabLAN" xml:space="preserve">
<value>區域網路</value>
</data>
@@ -543,18 +522,12 @@
<data name="menuTcpingServer" xml:space="preserve">
<value>測試伺服器延遲Tcping(多選) (Ctrl+O)</value>
</data>
<data name="menuTestMe" xml:space="preserve">
<value>測試目前服務狀態</value>
</data>
<data name="menuExport2ClientConfig" xml:space="preserve">
<value>匯出所選伺服器為用戶端配置</value>
</data>
<data name="menuExport2ShareUrl" xml:space="preserve">
<value>批次匯出分享URL至剪貼簿(多選) (Ctrl+C)</value>
</data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>批次匯出訂閱內容至剪貼簿(多選)</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>新增自訂配置伺服器</value>
</data>
@@ -585,9 +558,6 @@
<data name="menuMsgViewCopyAll" xml:space="preserve">
<value>複製所有</value>
</data>
<data name="menuMsgViewFilter" xml:space="preserve">
<value>設定資訊過濾器</value>
</data>
<data name="menuMsgViewSelectAll" xml:space="preserve">
<value>全選 (Ctrl+A)</value>
</data>
@@ -700,7 +670,7 @@
<value>SOCKS埠</value>
</data>
<data name="TipPreSocksPort" xml:space="preserve">
<value>* 自訂配置的Socks埠值可不設定當設定此值後將使用sing-box額外啟動一個前置Socks服務提供分流和速度顯示等功能</value>
<value>* 自訂配置的Socks埠值可不設定當設定此值後將使用Xray/sing-box(Tun)額外啟動一個前置Socks服務提供分流和速度顯示等功能</value>
</data>
<!--********************************************-->
<data name="TbBrowse" xml:space="preserve">
@@ -958,6 +928,9 @@
<data name="TbSettingsRouteOnly" xml:space="preserve">
<value>RouteOnly</value>
</data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>請勿將代理伺服器用於本機Intranet位址</value>
</data>
<data name="menuMixedTestServer" xml:space="preserve">
<value>一鍵多執行緒測試延遲和速度 (Ctrl+E)</value>
</data>
@@ -988,21 +961,9 @@
<data name="TbSettingsTunMode" xml:space="preserve">
<value>TUN模式設定</value>
</data>
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
<value>直連的IP CIDR用逗號(,)分隔</value>
</data>
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
<value>直連的行程名,用逗號(,)分隔</value>
</data>
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>顯示控制台</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve">
<value>移至訂閱分組</value>
</data>
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
<value>自訂配置模板</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>啟動伺服器拖放排序(需重啟)</value>
</data>
@@ -1037,7 +998,7 @@
<value>複製字型TTF/TTC文件到目錄guiFonts重啟設定</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>HTTP埠=SOCKS埠+1</value>
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
@@ -1045,24 +1006,12 @@
<data name="TbSettingsFontSize" xml:space="preserve">
<value>字型大小</value>
</data>
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
<value>代理的IP CIDR用逗號(,)分隔</value>
</data>
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
<value>代理的行程名,用逗號(,)分隔</value>
</data>
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
<value>繞行模式</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>測速單個超時值</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>測速檔案位址</value>
</data>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS物件例如 {"servers":[]}</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>移至上下</value>
</data>
@@ -1168,4 +1117,28 @@
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>新增[Http]伺服器</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>啟用分片Fragment</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>使用Xray且非Tun模式啟用和分組前置代理衝突</value>
</data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>啟用sing-box規則集文件的緩存文件</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>自訂sing-box rule-set</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>操作成功。 請點選設定選單重啟應用程式。</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>打開儲存所在的位置</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>自動調整列寬</value>
</data>
</root>

View File

@@ -4,56 +4,7 @@
"error": "Verror.log",
"loglevel": "warning"
},
"inbounds": [{
"tag": "tag1",
"port": 10808,
"protocol": "socks",
"listen": "127.0.0.1",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"tag": "tag2",
"port": 10809,
"protocol": "http",
"listen": "127.0.0.1",
"settings": {
"allowTransparent": false
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"tag": "tag3",
"port": 10809,
"protocol": "http",
"listen": "127.0.0.1",
"settings": {
"allowTransparent": false
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"inbounds": [],
"outbounds": [{
"tag": "proxy",
"protocol": "vmess",

View File

@@ -3,14 +3,7 @@
"level": "debug",
"timestamp": true
},
"inbounds": [
{
"type": "socks",
"tag": "socks",
"listen": "127.0.0.1",
"listen_port": 10000
}
],
"inbounds": [],
"outbounds": [
{
"type": "vless",

View File

@@ -0,0 +1,39 @@
#
# 配置文件内容不会被修改,混合行为只会发生在内存中
#
# 注意下面缩进请用支持yaml显示的编辑器打开
#
# 使用clash配置文件关键字则覆盖原配置
#
# removed-rules 循环匹配rules数组每行,符合则移除当前行 (此规则请放最前面)
#
# append-rules 数组合并至原配置rules数组后
# prepend-rules 数组合并至原配置rules数组前
# append-proxies 数组合并至原配置proxies数组后
# prepend-proxies 数组合并至原配置proxies数组前
# append-proxy-groups 数组合并至原配置proxy-groups数组后
# prepend-proxy-groups 数组合并至原配置proxy-groups数组前
# append-rule-providers 数组合并至原配置rule-providers数组后
# prepend-rule-providers 数组合并至原配置rule-providers数组前
#
dns:
enable: true
enhanced-mode: fake-ip
nameserver:
- 114.114.114.114
- 223.5.5.5
- 8.8.8.8
fallback: []
fake-ip-filter:
- +.stun.*.*
- +.stun.*.*.*
- +.stun.*.*.*.*
- +.stun.*.*.*.*.*
- "*.n.n.srv.nintendo.net"
- +.stun.playstation.net
- xbox.*.*.microsoft.com
- "*.*.xboxlive.com"
- "*.msftncsi.com"
- "*.msftconnecttest.com"
- WORKGROUP

View File

@@ -0,0 +1,7 @@
tun:
enable: true
stack: gvisor
dns-hijack:
- 0.0.0.0:53
auto-route: true
auto-detect-interface: true

View File

@@ -5,28 +5,38 @@
"bittorrent"
]
},
{
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{
"outboundTag": "block",
"domain": [
"geosite:category-ads-all"
]
},
{
"outboundTag": "proxy",
"domain": [
"geosite:gfw",
"geosite:greatfire"
]
},
{
"outboundTag": "proxy",
"ip": [
"geoip:cloudflare",
"geoip:cloudfront",
"1.0.0.1",
"1.1.1.1",
"8.8.8.8",
"8.8.4.4",
"geoip:facebook",
"geoip:fastly",
"geoip:google",
"geoip:netflix",
"geoip:telegram",
"geoip:twitter"
],
"domain": [
"geosite:gfw",
"geosite:greatfire",
"geosite:tld-!cn"
]
},
{

View File

@@ -1,4 +1,9 @@
[
{
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{
"port": "0-65535",
"outboundTag": "proxy"

View File

@@ -6,6 +6,11 @@
"domain:example-example2.com"
]
},
{
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{
"outboundTag": "block",
"domain": [
@@ -15,12 +20,17 @@
{
"outboundTag": "direct",
"domain": [
"geosite:cn"
"geosite:cn",
"geosite:geolocation-cn"
]
},
{
"outboundTag": "direct",
"ip": [
"223.5.5.5/32",
"119.29.29.29/32",
"180.76.76.76/32",
"114.114.114.114/32",
"geoip:private",
"geoip:cn"
]

View File

@@ -3,11 +3,13 @@
{
"tag": "remote",
"address": "tcp://8.8.8.8",
"strategy": "ipv4_only",
"detour": "proxy"
},
{
"tag": "local",
"address": "223.5.5.5",
"strategy": "ipv4_only",
"detour": "direct"
},
{
@@ -17,16 +19,18 @@
],
"rules": [
{
"geosite": [
"cn"
"rule_set": [
"geosite-cn",
"geosite-geolocation-cn"
],
"server": "local"
},
{
"geosite": [
"category-ads-all"
"rule_set": [
"geosite-category-ads-all"
],
"server": "block"
}
]
],
"final": "remote"
}

View File

@@ -7,7 +7,8 @@
{
"address": "223.5.5.5",
"domains": [
"geosite:cn"
"geosite:cn",
"geosite:geolocation-cn"
],
"expectIPs": [
"geoip:cn"

View File

@@ -3,11 +3,13 @@
{
"tag": "remote",
"address": "tcp://8.8.8.8",
"strategy": "ipv4_only",
"detour": "proxy"
},
{
"tag": "local",
"address": "223.5.5.5",
"strategy": "ipv4_only",
"detour": "direct"
},
{
@@ -17,19 +19,18 @@
],
"rules": [
{
"geosite": [
"cn"
"rule_set": [
"geosite-cn",
"geosite-geolocation-cn"
],
"server": "local",
"disable_cache": true
"server": "local"
},
{
"geosite": [
"category-ads-all"
"rule_set": [
"geosite-category-ads-all"
],
"server": "block",
"disable_cache": true
"server": "block"
}
],
"strategy": "ipv4_only"
"final": "remote"
}

View File

@@ -56,7 +56,7 @@ namespace v2rayN.ViewModels
SaveServer();
});
Utils.SetDarkBorder(view, _config.uiItem.colorModeDark);
Utils.SetDarkBorder(view, _config.uiItem.followSystemTheme ? !Utils.IsLightTheme() : _config.uiItem.colorModeDark);
}
private void SaveServer()

View File

@@ -3,6 +3,7 @@ using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive;
using System.Windows;
using v2rayN.Enums;
using v2rayN.Handler;
using v2rayN.Models;
using v2rayN.Resx;
@@ -44,7 +45,7 @@ namespace v2rayN.ViewModels
SaveServer();
});
Utils.SetDarkBorder(view, _config.uiItem.colorModeDark);
Utils.SetDarkBorder(view, _config.uiItem.followSystemTheme ? !Utils.IsLightTheme() : _config.uiItem.colorModeDark);
}
private void SaveServer()
@@ -80,7 +81,8 @@ namespace v2rayN.ViewModels
return;
}
}
if (SelectedSource.configType != EConfigType.Socks)
if (SelectedSource.configType != EConfigType.Socks
&& SelectedSource.configType != EConfigType.Http)
{
if (Utils.IsNullOrEmpty(SelectedSource.id))
{
@@ -127,6 +129,7 @@ namespace v2rayN.ViewModels
EConfigType.VMess => ConfigHandler.AddServer(_config, item),
EConfigType.Shadowsocks => ConfigHandler.AddShadowsocksServer(_config, item),
EConfigType.Socks => ConfigHandler.AddSocksServer(_config, item),
EConfigType.Http => ConfigHandler.AddHttpServer(_config, item),
EConfigType.Trojan => ConfigHandler.AddTrojanServer(_config, item),
EConfigType.VLESS => ConfigHandler.AddVlessServer(_config, item),
EConfigType.Hysteria2 => ConfigHandler.AddHysteria2Server(_config, item),

View File

@@ -0,0 +1,199 @@
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Reactive;
using System.Reactive.Linq;
using System.Windows;
using v2rayN.Enums;
using v2rayN.Handler;
using v2rayN.Models;
namespace v2rayN.ViewModels
{
public class ClashConnectionsViewModel : ReactiveObject
{
private static Config _config;
private IObservableCollection<ClashConnectionModel> _connectionItems = new ObservableCollectionExtended<ClashConnectionModel>();
public IObservableCollection<ClashConnectionModel> ConnectionItems => _connectionItems;
[Reactive]
public ClashConnectionModel SelectedSource { get; set; }
public ReactiveCommand<Unit, Unit> ConnectionCloseCmd { get; }
public ReactiveCommand<Unit, Unit> ConnectionCloseAllCmd { get; }
[Reactive]
public int SortingSelected { get; set; }
[Reactive]
public bool AutoRefresh { get; set; }
public ClashConnectionsViewModel()
{
_config = LazyConfig.Instance.GetConfig();
SortingSelected = _config.clashUIItem.connectionsSorting;
AutoRefresh = _config.clashUIItem.connectionsAutoRefresh;
var canEditRemove = this.WhenAnyValue(
x => x.SelectedSource,
selectedSource => selectedSource != null && !string.IsNullOrEmpty(selectedSource.id));
this.WhenAnyValue(
x => x.SortingSelected,
y => y >= 0)
.Subscribe(c => DoSortingSelected(c));
this.WhenAnyValue(
x => x.AutoRefresh,
y => y == true)
.Subscribe(c => { _config.clashUIItem.connectionsAutoRefresh = AutoRefresh; });
ConnectionCloseCmd = ReactiveCommand.Create(() =>
{
ClashConnectionClose(false);
}, canEditRemove);
ConnectionCloseAllCmd = ReactiveCommand.Create(() =>
{
ClashConnectionClose(true);
});
Init();
}
private void DoSortingSelected(bool c)
{
if (!c)
{
return;
}
if (SortingSelected != _config.clashUIItem.connectionsSorting)
{
_config.clashUIItem.connectionsSorting = SortingSelected;
}
GetClashConnections();
}
private void Init()
{
var lastTime = DateTime.Now;
Observable.Interval(TimeSpan.FromSeconds(10))
.Subscribe(x =>
{
if (!(AutoRefresh && _config.uiItem.showInTaskbar && _config.IsRunningCore(ECoreType.clash)))
{
return;
}
var dtNow = DateTime.Now;
if (_config.clashUIItem.connectionsRefreshInterval > 0)
{
if ((dtNow - lastTime).Minutes % _config.clashUIItem.connectionsRefreshInterval == 0)
{
GetClashConnections();
lastTime = dtNow;
}
Thread.Sleep(1000);
}
});
}
private void GetClashConnections()
{
ClashApiHandler.Instance.GetClashConnections(_config, (it) =>
{
if (it == null)
{
return;
}
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
RefreshConnections(it?.connections);
}));
});
}
private void RefreshConnections(List<ConnectionItem>? connections)
{
_connectionItems.Clear();
var dtNow = DateTime.Now;
var lstModel = new List<ClashConnectionModel>();
foreach (var item in connections ?? [])
{
ClashConnectionModel model = new();
model.id = item.id;
model.network = item.metadata.network;
model.type = item.metadata.type;
model.host = $"{(string.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}";
var sp = (dtNow - item.start);
model.time = sp.TotalSeconds < 0 ? 1 : sp.TotalSeconds;
model.upload = item.upload;
model.download = item.download;
model.uploadTraffic = $"{Utils.HumanFy((long)item.upload)}";
model.downloadTraffic = $"{Utils.HumanFy((long)item.download)}";
model.elapsed = sp.ToString(@"hh\:mm\:ss");
model.chain = item.chains?.Count > 0 ? item.chains[0] : String.Empty;
lstModel.Add(model);
}
if (lstModel.Count <= 0) { return; }
//sort
switch (SortingSelected)
{
case 0:
lstModel = lstModel.OrderBy(t => t.upload / t.time).ToList();
break;
case 1:
lstModel = lstModel.OrderBy(t => t.download / t.time).ToList();
break;
case 2:
lstModel = lstModel.OrderBy(t => t.upload).ToList();
break;
case 3:
lstModel = lstModel.OrderBy(t => t.download).ToList();
break;
case 4:
lstModel = lstModel.OrderBy(t => t.time).ToList();
break;
case 5:
lstModel = lstModel.OrderBy(t => t.host).ToList();
break;
}
_connectionItems.AddRange(lstModel);
}
public void ClashConnectionClose(bool all)
{
var id = string.Empty;
if (!all)
{
var item = SelectedSource;
if (item is null)
{
return;
}
id = item.id;
}
else
{
_connectionItems.Clear();
}
ClashApiHandler.Instance.ClashConnectionClose(id);
GetClashConnections();
}
}
}

View File

@@ -0,0 +1,487 @@
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive;
using System.Reactive.Linq;
using System.Windows;
using v2rayN.Enums;
using v2rayN.Handler;
using v2rayN.Models;
using v2rayN.Resx;
using static v2rayN.Models.ClashProviders;
using static v2rayN.Models.ClashProxies;
namespace v2rayN.ViewModels
{
public class ClashProxiesViewModel : ReactiveObject
{
private static Config _config;
private NoticeHandler? _noticeHandler;
private Dictionary<String, ProxiesItem>? proxies;
private Dictionary<String, ProvidersItem>? providers;
private int delayTimeout = 99999999;
private IObservableCollection<ClashProxyModel> _proxyGroups = new ObservableCollectionExtended<ClashProxyModel>();
private IObservableCollection<ClashProxyModel> _proxyDetails = new ObservableCollectionExtended<ClashProxyModel>();
public IObservableCollection<ClashProxyModel> ProxyGroups => _proxyGroups;
public IObservableCollection<ClashProxyModel> ProxyDetails => _proxyDetails;
[Reactive]
public ClashProxyModel SelectedGroup { get; set; }
[Reactive]
public ClashProxyModel SelectedDetail { get; set; }
public ReactiveCommand<Unit, Unit> ProxiesReloadCmd { get; }
public ReactiveCommand<Unit, Unit> ProxiesDelaytestCmd { get; }
public ReactiveCommand<Unit, Unit> ProxiesDelaytestPartCmd { get; }
public ReactiveCommand<Unit, Unit> ProxiesSelectActivityCmd { get; }
[Reactive]
public int RuleModeSelected { get; set; }
[Reactive]
public int SortingSelected { get; set; }
[Reactive]
public bool AutoRefresh { get; set; }
public ClashProxiesViewModel()
{
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
_config = LazyConfig.Instance.GetConfig();
SelectedGroup = new();
SelectedDetail = new();
AutoRefresh = _config.clashUIItem.proxiesAutoRefresh;
SortingSelected = _config.clashUIItem.proxiesSorting;
RuleModeSelected = (int)_config.clashUIItem.ruleMode;
this.WhenAnyValue(
x => x.SelectedGroup,
y => y != null && !string.IsNullOrEmpty(y.name))
.Subscribe(c => RefreshProxyDetails(c));
this.WhenAnyValue(
x => x.RuleModeSelected,
y => y >= 0)
.Subscribe(c => DoRulemodeSelected(c));
this.WhenAnyValue(
x => x.SortingSelected,
y => y >= 0)
.Subscribe(c => DoSortingSelected(c));
this.WhenAnyValue(
x => x.AutoRefresh,
y => y == true)
.Subscribe(c => { _config.clashUIItem.proxiesAutoRefresh = AutoRefresh; });
ProxiesReloadCmd = ReactiveCommand.Create(() =>
{
ProxiesReload();
});
ProxiesDelaytestCmd = ReactiveCommand.Create(() =>
{
ProxiesDelayTest(true);
});
ProxiesDelaytestPartCmd = ReactiveCommand.Create(() =>
{
ProxiesDelayTest(false);
});
ProxiesSelectActivityCmd = ReactiveCommand.Create(() =>
{
SetActiveProxy();
});
ProxiesReload();
DelayTestTask();
}
private void DoRulemodeSelected(bool c)
{
if (!c)
{
return;
}
if (_config.clashUIItem.ruleMode == (ERuleMode)RuleModeSelected)
{
return;
}
SetRuleModeCheck((ERuleMode)RuleModeSelected);
}
public void SetRuleModeCheck(ERuleMode mode)
{
if (_config.clashUIItem.ruleMode == mode)
{
return;
}
SetRuleMode(mode);
}
private void DoSortingSelected(bool c)
{
if (!c)
{
return;
}
if (SortingSelected != _config.clashUIItem.proxiesSorting)
{
_config.clashUIItem.proxiesSorting = SortingSelected;
}
RefreshProxyDetails(c);
}
private void UpdateHandler(bool notify, string msg)
{
_noticeHandler?.SendMessage(msg, true);
}
public void ProxiesReload()
{
GetClashProxies(true);
ProxiesDelayTest();
}
public void ProxiesClear()
{
proxies = null;
providers = null;
ClashApiHandler.Instance.SetProxies(proxies);
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
_proxyGroups.Clear();
_proxyDetails.Clear();
}));
}
public void ProxiesDelayTest()
{
ProxiesDelayTest(true);
}
#region proxy function
private void SetRuleMode(ERuleMode mode)
{
_config.clashUIItem.ruleMode = mode;
if (mode != ERuleMode.Unchanged)
{
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("mode", mode.ToString().ToLower());
ClashApiHandler.Instance.ClashConfigUpdate(headers);
}
}
private void GetClashProxies(bool refreshUI)
{
ClashApiHandler.Instance.GetClashProxies(_config, (it, it2) =>
{
//UpdateHandler(false, "Refresh Clash Proxies");
proxies = it?.proxies;
providers = it2?.providers;
ClashApiHandler.Instance.SetProxies(proxies);
if (proxies == null)
{
return;
}
if (refreshUI)
{
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
RefreshProxyGroups();
}));
}
});
}
private void RefreshProxyGroups()
{
var selectedName = SelectedGroup?.name;
_proxyGroups.Clear();
var proxyGroups = ClashApiHandler.Instance.GetClashProxyGroups();
if (proxyGroups != null && proxyGroups.Count > 0)
{
foreach (var it in proxyGroups)
{
if (string.IsNullOrEmpty(it.name) || !proxies.ContainsKey(it.name))
{
continue;
}
var item = proxies[it.name];
if (!Global.allowSelectType.Contains(item.type.ToLower()))
{
continue;
}
_proxyGroups.Add(new ClashProxyModel()
{
now = item.now,
name = item.name,
type = item.type
});
}
}
//from api
foreach (KeyValuePair<string, ProxiesItem> kv in proxies)
{
if (!Global.allowSelectType.Contains(kv.Value.type.ToLower()))
{
continue;
}
var item = _proxyGroups.Where(t => t.name == kv.Key).FirstOrDefault();
if (item != null && !string.IsNullOrEmpty(item.name))
{
continue;
}
_proxyGroups.Add(new ClashProxyModel()
{
now = kv.Value.now,
name = kv.Key,
type = kv.Value.type
});
}
if (_proxyGroups != null && _proxyGroups.Count > 0)
{
if (selectedName != null && _proxyGroups.Any(t => t.name == selectedName))
{
SelectedGroup = _proxyGroups.FirstOrDefault(t => t.name == selectedName);
}
else
{
SelectedGroup = _proxyGroups[0];
}
}
else
{
SelectedGroup = new();
}
}
private void RefreshProxyDetails(bool c)
{
_proxyDetails.Clear();
if (!c)
{
return;
}
var name = SelectedGroup?.name;
if (string.IsNullOrEmpty(name))
{
return;
}
if (proxies == null)
{
return;
}
proxies.TryGetValue(name, out ProxiesItem proxy);
if (proxy == null || proxy.all == null)
{
return;
}
var lstDetails = new List<ClashProxyModel>();
foreach (var item in proxy.all)
{
var isActive = item == proxy.now;
var proxy2 = TryGetProxy(item);
if (proxy2 == null)
{
continue;
}
int delay = -1;
if (proxy2.history.Count > 0)
{
delay = proxy2.history[proxy2.history.Count - 1].delay;
}
lstDetails.Add(new ClashProxyModel()
{
isActive = isActive,
name = item,
type = proxy2.type,
delay = delay <= 0 ? delayTimeout : delay,
delayName = delay <= 0 ? string.Empty : $"{delay}ms",
});
}
//sort
switch (SortingSelected)
{
case 0:
lstDetails = lstDetails.OrderBy(t => t.delay).ToList();
break;
case 1:
lstDetails = lstDetails.OrderBy(t => t.name).ToList();
break;
default:
break;
}
_proxyDetails.AddRange(lstDetails);
}
private ProxiesItem? TryGetProxy(string name)
{
if (proxies is null)
return null;
proxies.TryGetValue(name, out ProxiesItem proxy2);
if (proxy2 != null)
{
return proxy2;
}
//from providers
if (providers != null)
{
foreach (KeyValuePair<string, ProvidersItem> kv in providers)
{
if (Global.proxyVehicleType.Contains(kv.Value.vehicleType.ToLower()))
{
var proxy3 = kv.Value.proxies.FirstOrDefault(t => t.name == name);
if (proxy3 != null)
{
return proxy3;
}
}
}
}
return null;
}
public void SetActiveProxy()
{
if (SelectedGroup == null || string.IsNullOrEmpty(SelectedGroup.name))
{
return;
}
if (SelectedDetail == null || string.IsNullOrEmpty(SelectedDetail.name))
{
return;
}
var name = SelectedGroup.name;
if (string.IsNullOrEmpty(name))
{
return;
}
var nameNode = SelectedDetail.name;
if (string.IsNullOrEmpty(nameNode))
{
return;
}
var selectedProxy = TryGetProxy(name);
if (selectedProxy == null || selectedProxy.type != "Selector")
{
_noticeHandler?.Enqueue(ResUI.OperationFailed);
return;
}
ClashApiHandler.Instance.ClashSetActiveProxy(name, nameNode);
selectedProxy.now = nameNode;
var group = _proxyGroups.Where(it => it.name == SelectedGroup.name).FirstOrDefault();
if (group != null)
{
group.now = nameNode;
var group2 = JsonUtils.DeepCopy(group);
_proxyGroups.Replace(group, group2);
SelectedGroup = group2;
//var index = _proxyGroups.IndexOf(group);
//_proxyGroups.Remove(group);
//_proxyGroups.Insert(index, group);
}
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
//RefreshProxyDetails(true);
//GetClashProxies(true);
}
private void ProxiesDelayTest(bool blAll)
{
//UpdateHandler(false, "Clash Proxies Latency Test");
ClashApiHandler.Instance.ClashProxiesDelayTest(blAll, _proxyDetails.ToList(), (item, result) =>
{
if (item == null)
{
GetClashProxies(true);
return;
}
if (string.IsNullOrEmpty(result))
{
return;
}
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
//UpdateHandler(false, $"{item.name}={result}");
var detail = _proxyDetails.Where(it => it.name == item.name).FirstOrDefault();
if (detail != null)
{
var dicResult = JsonUtils.Deserialize<Dictionary<string, object>>(result);
if (dicResult != null && dicResult.ContainsKey("delay"))
{
detail.delay = Convert.ToInt32(dicResult["delay"].ToString());
detail.delayName = $"{detail.delay}ms";
}
else if (dicResult != null && dicResult.ContainsKey("message"))
{
detail.delay = delayTimeout;
detail.delayName = $"{dicResult["message"]}";
}
else
{
detail.delay = delayTimeout;
detail.delayName = String.Empty;
}
_proxyDetails.Replace(detail, JsonUtils.DeepCopy(detail));
}
}));
});
}
#endregion proxy function
#region task
public void DelayTestTask()
{
var lastTime = DateTime.Now;
Observable.Interval(TimeSpan.FromSeconds(60))
.Subscribe(x =>
{
if (!(AutoRefresh && _config.uiItem.showInTaskbar && _config.IsRunningCore(ECoreType.clash)))
{
return;
}
var dtNow = DateTime.Now;
if (_config.clashUIItem.proxiesAutoDelayTestInterval > 0)
{
if ((dtNow - lastTime).Minutes % _config.clashUIItem.proxiesAutoDelayTestInterval == 0)
{
ProxiesDelayTest();
lastTime = dtNow;
}
Thread.Sleep(1000);
}
});
}
#endregion task
}
}

View File

@@ -3,6 +3,7 @@ using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive;
using System.Windows;
using v2rayN.Enums;
using v2rayN.Handler;
using v2rayN.Models;
using v2rayN.Resx;
@@ -17,7 +18,11 @@ namespace v2rayN.ViewModels
[Reactive] public bool useSystemHosts { get; set; }
[Reactive] public string domainStrategy4Freedom { get; set; }
[Reactive] public string domainDNSAddress { get; set; }
[Reactive] public string normalDNS { get; set; }
[Reactive] public string domainStrategy4Freedom2 { get; set; }
[Reactive] public string domainDNSAddress2 { get; set; }
[Reactive] public string normalDNS2 { get; set; }
[Reactive] public string tunDNS2 { get; set; }
@@ -33,12 +38,15 @@ namespace v2rayN.ViewModels
var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray);
useSystemHosts = item.useSystemHosts;
domainStrategy4Freedom = item?.domainStrategy4Freedom!;
normalDNS = item?.normalDNS!;
domainStrategy4Freedom = item?.domainStrategy4Freedom ?? string.Empty;
domainDNSAddress = item?.domainDNSAddress ?? string.Empty;
normalDNS = item?.normalDNS ?? string.Empty;
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
normalDNS2 = item2?.normalDNS!;
tunDNS2 = item2?.tunDNS!;
domainStrategy4Freedom2 = item2?.domainStrategy4Freedom ?? string.Empty;
domainDNSAddress2 = item2?.domainDNSAddress ?? string.Empty;
normalDNS2 = item2?.normalDNS ?? string.Empty;
tunDNS2 = item2?.tunDNS ?? string.Empty;
SaveCmd = ReactiveCommand.Create(() =>
{
@@ -56,7 +64,7 @@ namespace v2rayN.ViewModels
tunDNS2 = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
});
Utils.SetDarkBorder(view, _config.uiItem.colorModeDark);
Utils.SetDarkBorder(view, _config.uiItem.followSystemTheme ? !Utils.IsLightTheme() : _config.uiItem.colorModeDark);
}
private void SaveSetting()
@@ -97,13 +105,16 @@ namespace v2rayN.ViewModels
var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray);
item.domainStrategy4Freedom = domainStrategy4Freedom;
item.domainDNSAddress = domainDNSAddress;
item.useSystemHosts = useSystemHosts;
item.normalDNS = normalDNS;
ConfigHandler.SaveDNSItems(_config, item);
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
item2.domainStrategy4Freedom = domainStrategy4Freedom2;
item2.domainDNSAddress = domainDNSAddress2;
item2.normalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(normalDNS2));
item2.tunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2));
item2.tunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2));;
ConfigHandler.SaveDNSItems(_config, item2);
_noticeHandler?.Enqueue(ResUI.OperationSuccess);

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@ using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive;
using System.Windows;
using v2rayN.Enums;
using v2rayN.Handler;
using v2rayN.Models;
using v2rayN.Resx;
@@ -20,6 +21,7 @@ namespace v2rayN.ViewModels
[Reactive] public int localPort { get; set; }
[Reactive] public bool udpEnabled { get; set; }
[Reactive] public bool sniffingEnabled { get; set; }
public IList<string> destOverride { get; set; }
[Reactive] public bool routeOnly { get; set; }
[Reactive] public bool allowLANConn { get; set; }
[Reactive] public bool newPort4LAN { get; set; }
@@ -32,8 +34,10 @@ namespace v2rayN.ViewModels
[Reactive] public string defFingerprint { get; set; }
[Reactive] public string defUserAgent { get; set; }
[Reactive] public string mux4SboxProtocol { get; set; }
[Reactive] public bool enableCacheFile4Sbox { get; set; }
[Reactive] public int hyUpMbps { get; set; }
[Reactive] public int hyDownMbps { get; set; }
[Reactive] public bool enableFragment { get; set; }
#endregion Core
@@ -62,19 +66,21 @@ namespace v2rayN.ViewModels
[Reactive] public bool EnableCheckPreReleaseUpdate { get; set; }
[Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int autoUpdateInterval { get; set; }
[Reactive] public int trayMenuServersLimit { get; set; }
[Reactive] public string currentFontFamily { get; set; }
[Reactive] public int AutoUpdateInterval { get; set; }
[Reactive] public int TrayMenuServersLimit { get; set; }
[Reactive] public string CurrentFontFamily { get; set; }
[Reactive] public int SpeedTestTimeout { get; set; }
[Reactive] public string SpeedTestUrl { get; set; }
[Reactive] public string SpeedPingTestUrl { get; set; }
[Reactive] public bool EnableHWA { get; set; }
[Reactive] public string SubConvertUrl { get; set; }
[Reactive] public int MainGirdOrientation { get; set; }
#endregion UI
#region System proxy
[Reactive] public bool notProxyLocalAddress { get; set; }
[Reactive] public string systemProxyAdvancedProtocol { get; set; }
[Reactive] public string systemProxyExceptions { get; set; }
@@ -127,8 +133,10 @@ namespace v2rayN.ViewModels
defFingerprint = _config.coreBasicItem.defFingerprint;
defUserAgent = _config.coreBasicItem.defUserAgent;
mux4SboxProtocol = _config.mux4SboxItem.protocol;
enableCacheFile4Sbox = _config.coreBasicItem.enableCacheFile4Sbox;
hyUpMbps = _config.hysteriaItem.up_mbps;
hyDownMbps = _config.hysteriaItem.down_mbps;
enableFragment = _config.coreBasicItem.enableFragment;
#endregion Core
@@ -157,21 +165,23 @@ namespace v2rayN.ViewModels
EnableCheckPreReleaseUpdate = _config.guiItem.checkPreReleaseUpdate;
EnableDragDropSort = _config.uiItem.enableDragDropSort;
DoubleClick2Activate = _config.uiItem.doubleClick2Activate;
autoUpdateInterval = _config.guiItem.autoUpdateInterval;
trayMenuServersLimit = _config.guiItem.trayMenuServersLimit;
currentFontFamily = _config.uiItem.currentFontFamily;
AutoUpdateInterval = _config.guiItem.autoUpdateInterval;
TrayMenuServersLimit = _config.guiItem.trayMenuServersLimit;
CurrentFontFamily = _config.uiItem.currentFontFamily;
SpeedTestTimeout = _config.speedTestItem.speedTestTimeout;
SpeedTestUrl = _config.speedTestItem.speedTestUrl;
SpeedPingTestUrl = _config.speedTestItem.speedPingTestUrl;
EnableHWA = _config.guiItem.enableHWA;
SubConvertUrl = _config.constItem.subConvertUrl;
MainGirdOrientation = (int)_config.uiItem.mainGirdOrientation;
#endregion UI
#region System proxy
systemProxyAdvancedProtocol = _config.systemProxyAdvancedProtocol;
systemProxyExceptions = _config.systemProxyExceptions;
notProxyLocalAddress = _config.systemProxyItem.notProxyLocalAddress;
systemProxyAdvancedProtocol = _config.systemProxyItem.systemProxyAdvancedProtocol;
systemProxyExceptions = _config.systemProxyItem.systemProxyExceptions;
#endregion System proxy
@@ -192,7 +202,7 @@ namespace v2rayN.ViewModels
SaveSetting();
});
Utils.SetDarkBorder(view, _config.uiItem.colorModeDark);
Utils.SetDarkBorder(view, _config.uiItem.followSystemTheme ? !Utils.IsLightTheme() : _config.uiItem.colorModeDark);
}
private void InitCoreType()
@@ -255,6 +265,11 @@ namespace v2rayN.ViewModels
_noticeHandler?.Enqueue(ResUI.FillLocalListeningPort);
return;
}
var needReboot = (EnableStatistics != _config.guiItem.enableStatistics
|| EnableDragDropSort != _config.uiItem.enableDragDropSort
|| EnableHWA != _config.guiItem.enableHWA
|| CurrentFontFamily != _config.uiItem.currentFontFamily
|| MainGirdOrientation != (int)_config.uiItem.mainGirdOrientation);
//if (Utile.IsNullOrEmpty(Kcpmtu.ToString()) || !Utile.IsNumeric(Kcpmtu.ToString())
// || Utile.IsNullOrEmpty(Kcptti.ToString()) || !Utile.IsNumeric(Kcptti.ToString())
@@ -271,6 +286,7 @@ namespace v2rayN.ViewModels
_config.inbound[0].localPort = localPort;
_config.inbound[0].udpEnabled = udpEnabled;
_config.inbound[0].sniffingEnabled = sniffingEnabled;
_config.inbound[0].destOverride = destOverride?.ToList();
_config.inbound[0].routeOnly = routeOnly;
_config.inbound[0].allowLANConn = allowLANConn;
_config.inbound[0].newPort4LAN = newPort4LAN;
@@ -287,8 +303,10 @@ namespace v2rayN.ViewModels
_config.coreBasicItem.defFingerprint = defFingerprint;
_config.coreBasicItem.defUserAgent = defUserAgent;
_config.mux4SboxItem.protocol = mux4SboxProtocol;
_config.coreBasicItem.enableCacheFile4Sbox = enableCacheFile4Sbox;
_config.hysteriaItem.up_mbps = hyUpMbps;
_config.hysteriaItem.down_mbps = hyDownMbps;
_config.coreBasicItem.enableFragment = enableFragment;
//Kcp
//_config.kcpItem.mtu = Kcpmtu;
@@ -309,21 +327,23 @@ namespace v2rayN.ViewModels
_config.uiItem.enableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist;
_config.guiItem.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.uiItem.autoHideStartup = AutoHideStartup;
_config.guiItem.autoUpdateInterval = autoUpdateInterval;
_config.guiItem.autoUpdateInterval = AutoUpdateInterval;
_config.guiItem.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate;
_config.uiItem.enableDragDropSort = EnableDragDropSort;
_config.uiItem.doubleClick2Activate = DoubleClick2Activate;
_config.guiItem.trayMenuServersLimit = trayMenuServersLimit;
_config.uiItem.currentFontFamily = currentFontFamily;
_config.guiItem.trayMenuServersLimit = TrayMenuServersLimit;
_config.uiItem.currentFontFamily = CurrentFontFamily;
_config.speedTestItem.speedTestTimeout = SpeedTestTimeout;
_config.speedTestItem.speedTestUrl = SpeedTestUrl;
_config.speedTestItem.speedPingTestUrl = SpeedPingTestUrl;
_config.guiItem.enableHWA = EnableHWA;
_config.constItem.subConvertUrl = SubConvertUrl;
_config.uiItem.mainGirdOrientation = (EGirdOrientation)MainGirdOrientation;
//systemProxy
_config.systemProxyExceptions = systemProxyExceptions;
_config.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol;
_config.systemProxyItem.systemProxyExceptions = systemProxyExceptions;
_config.systemProxyItem.notProxyLocalAddress = notProxyLocalAddress;
_config.systemProxyItem.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol;
//tun mode
_config.tunModeItem.strictRoute = TunStrictRoute;
@@ -337,7 +357,14 @@ namespace v2rayN.ViewModels
if (ConfigHandler.SaveConfig(_config) == 0)
{
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
if (needReboot)
{
_noticeHandler?.Enqueue(ResUI.NeedRebootTips);
}
else
{
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
}
_view.DialogResult = true;
}
else

View File

@@ -0,0 +1,796 @@
using DynamicData;
using DynamicData.Binding;
using MaterialDesignThemes.Wpf;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Windows;
using v2rayN.Enums;
using v2rayN.Handler;
using v2rayN.Handler.Fmt;
using v2rayN.Handler.Statistics;
using v2rayN.Models;
using v2rayN.Resx;
using v2rayN.Views;
namespace v2rayN.ViewModels
{
public class ProfilesViewModel : ReactiveObject
{
#region private prop
private List<ProfileItem> _lstProfile;
private string _serverFilter = string.Empty;
private static Config _config;
private NoticeHandler? _noticeHandler;
private Dictionary<string, bool> _dicHeaderSort = new();
private Action<EViewAction> _updateView;
#endregion private prop
#region ObservableCollection
private IObservableCollection<ProfileItemModel> _profileItems = new ObservableCollectionExtended<ProfileItemModel>();
public IObservableCollection<ProfileItemModel> ProfileItems => _profileItems;
private IObservableCollection<SubItem> _subItems = new ObservableCollectionExtended<SubItem>();
public IObservableCollection<SubItem> SubItems => _subItems;
private IObservableCollection<ComboItem> _servers = new ObservableCollectionExtended<ComboItem>();
[Reactive]
public ProfileItemModel SelectedProfile { get; set; }
public IList<ProfileItemModel> SelectedProfiles { get; set; }
[Reactive]
public SubItem SelectedSub { get; set; }
[Reactive]
public SubItem SelectedMoveToGroup { get; set; }
[Reactive]
public ComboItem SelectedServer { get; set; }
[Reactive]
public string ServerFilter { get; set; }
[Reactive]
public bool BlServers { get; set; }
#endregion ObservableCollection
#region Menu
//servers delete
public ReactiveCommand<Unit, Unit> EditServerCmd { get; }
public ReactiveCommand<Unit, Unit> RemoveServerCmd { get; }
public ReactiveCommand<Unit, Unit> RemoveDuplicateServerCmd { get; }
public ReactiveCommand<Unit, Unit> CopyServerCmd { get; }
public ReactiveCommand<Unit, Unit> SetDefaultServerCmd { get; }
public ReactiveCommand<Unit, Unit> ShareServerCmd { get; }
public ReactiveCommand<Unit, Unit> SetDefaultMultipleServerCmd { get; }
public ReactiveCommand<Unit, Unit> SetDefaultLoadBalanceServerCmd { get; }
//servers move
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
public ReactiveCommand<Unit, Unit> MoveUpCmd { get; }
public ReactiveCommand<Unit, Unit> MoveDownCmd { get; }
public ReactiveCommand<Unit, Unit> MoveBottomCmd { get; }
//servers ping
public ReactiveCommand<Unit, Unit> MixedTestServerCmd { get; }
public ReactiveCommand<Unit, Unit> TcpingServerCmd { get; }
public ReactiveCommand<Unit, Unit> RealPingServerCmd { get; }
public ReactiveCommand<Unit, Unit> SpeedServerCmd { get; }
public ReactiveCommand<Unit, Unit> SortServerResultCmd { get; }
//servers export
public ReactiveCommand<Unit, Unit> Export2ClientConfigCmd { get; }
public ReactiveCommand<Unit, Unit> Export2ShareUrlCmd { get; }
public ReactiveCommand<Unit, Unit> AddSubCmd { get; }
public ReactiveCommand<Unit, Unit> EditSubCmd { get; }
#endregion Menu
#region Init
public ProfilesViewModel(Action<EViewAction> updateView)
{
_updateView = updateView;
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
_config = LazyConfig.Instance.GetConfig();
MessageBus.Current.Listen<string>(Global.CommandRefreshProfiles).Subscribe(x => RefreshServersBiz());
SelectedProfile = new();
SelectedSub = new();
SelectedMoveToGroup = new();
SelectedServer = new();
RefreshSubscriptions();
RefreshServers();
#region WhenAnyValue && ReactiveCommand
var canEditRemove = this.WhenAnyValue(
x => x.SelectedProfile,
selectedSource => selectedSource != null && !selectedSource.indexId.IsNullOrEmpty());
this.WhenAnyValue(
x => x.SelectedSub,
y => y != null && !y.remarks.IsNullOrEmpty() && _config.subIndexId != y.id)
.Subscribe(c => SubSelectedChanged(c));
this.WhenAnyValue(
x => x.SelectedMoveToGroup,
y => y != null && !y.remarks.IsNullOrEmpty())
.Subscribe(c => MoveToGroup(c));
this.WhenAnyValue(
x => x.SelectedServer,
y => y != null && !y.Text.IsNullOrEmpty())
.Subscribe(c => ServerSelectedChanged(c));
this.WhenAnyValue(
x => x.ServerFilter,
y => y != null && _serverFilter != y)
.Subscribe(c => ServerFilterChanged(c));
//servers delete
EditServerCmd = ReactiveCommand.Create(() =>
{
EditServer(false, EConfigType.Custom);
}, canEditRemove);
RemoveServerCmd = ReactiveCommand.Create(() =>
{
RemoveServer();
}, canEditRemove);
RemoveDuplicateServerCmd = ReactiveCommand.Create(() =>
{
RemoveDuplicateServer();
});
CopyServerCmd = ReactiveCommand.Create(() =>
{
CopyServer();
}, canEditRemove);
SetDefaultServerCmd = ReactiveCommand.Create(() =>
{
SetDefaultServer();
}, canEditRemove);
ShareServerCmd = ReactiveCommand.Create(() =>
{
ShareServer();
}, canEditRemove);
SetDefaultMultipleServerCmd = ReactiveCommand.Create(() =>
{
SetDefaultMultipleServer(ECoreType.sing_box);
}, canEditRemove);
SetDefaultLoadBalanceServerCmd = ReactiveCommand.Create(() =>
{
SetDefaultMultipleServer(ECoreType.Xray);
}, canEditRemove);
//servers move
MoveTopCmd = ReactiveCommand.Create(() =>
{
MoveServer(EMove.Top);
}, canEditRemove);
MoveUpCmd = ReactiveCommand.Create(() =>
{
MoveServer(EMove.Up);
}, canEditRemove);
MoveDownCmd = ReactiveCommand.Create(() =>
{
MoveServer(EMove.Down);
}, canEditRemove);
MoveBottomCmd = ReactiveCommand.Create(() =>
{
MoveServer(EMove.Bottom);
}, canEditRemove);
//servers ping
MixedTestServerCmd = ReactiveCommand.Create(() =>
{
ServerSpeedtest(ESpeedActionType.Mixedtest);
});
TcpingServerCmd = ReactiveCommand.Create(() =>
{
ServerSpeedtest(ESpeedActionType.Tcping);
}, canEditRemove);
RealPingServerCmd = ReactiveCommand.Create(() =>
{
ServerSpeedtest(ESpeedActionType.Realping);
}, canEditRemove);
SpeedServerCmd = ReactiveCommand.Create(() =>
{
ServerSpeedtest(ESpeedActionType.Speedtest);
}, canEditRemove);
SortServerResultCmd = ReactiveCommand.Create(() =>
{
SortServer(EServerColName.delayVal.ToString());
});
//servers export
Export2ClientConfigCmd = ReactiveCommand.Create(() =>
{
Export2ClientConfig();
}, canEditRemove);
Export2ShareUrlCmd = ReactiveCommand.Create(() =>
{
Export2ShareUrl();
}, canEditRemove);
//Subscription
AddSubCmd = ReactiveCommand.Create(() =>
{
EditSub(true);
});
EditSubCmd = ReactiveCommand.Create(() =>
{
EditSub(false);
});
#endregion WhenAnyValue && ReactiveCommand
}
#endregion Init
#region Actions
private void Reload()
{
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
}
private void UpdateSpeedtestHandler(string indexId, string delay, string speed)
{
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
SetTestResult(indexId, delay, speed);
}));
}
private void SetTestResult(string indexId, string delay, string speed)
{
if (Utils.IsNullOrEmpty(indexId))
{
_noticeHandler?.SendMessage(delay, true);
_noticeHandler?.Enqueue(delay);
return;
}
var item = _profileItems.Where(it => it.indexId == indexId).FirstOrDefault();
if (item != null)
{
if (!Utils.IsNullOrEmpty(delay))
{
int.TryParse(delay, out int temp);
item.delay = temp;
item.delayVal = $"{delay} {Global.DelayUnit}";
}
if (!Utils.IsNullOrEmpty(speed))
{
item.speedVal = $"{speed} {Global.SpeedUnit}";
}
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
}
}
public void UpdateStatistics(ServerSpeedItem update)
{
try
{
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
var item = _profileItems.Where(it => it.indexId == update.indexId).FirstOrDefault();
if (item != null)
{
item.todayDown = Utils.HumanFy(update.todayDown);
item.todayUp = Utils.HumanFy(update.todayUp);
item.totalDown = Utils.HumanFy(update.totalDown);
item.totalUp = Utils.HumanFy(update.totalUp);
if (SelectedProfile?.indexId == item.indexId)
{
var temp = JsonUtils.DeepCopy(item);
_profileItems.Replace(item, temp);
SelectedProfile = temp;
}
else
{
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
}
}
}));
}
catch
{
}
}
#endregion Actions
#region Servers && Groups
private void SubSelectedChanged(bool c)
{
if (!c)
{
return;
}
_config.subIndexId = SelectedSub?.id;
RefreshServers();
_updateView(EViewAction.ProfilesFocus);
}
private void ServerFilterChanged(bool c)
{
if (!c)
{
return;
}
_serverFilter = ServerFilter;
if (Utils.IsNullOrEmpty(_serverFilter))
{
RefreshServers();
}
}
public void RefreshServers()
{
MessageBus.Current.SendMessage("", Global.CommandRefreshProfiles);
}
private void RefreshServersBiz()
{
var lstModel = LazyConfig.Instance.ProfileItems(_config.subIndexId, _serverFilter);
ConfigHandler.SetDefaultServer(_config, lstModel);
var lstServerStat = (_config.guiItem.enableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
lstModel = (from t in lstModel
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
from t22 in t2b.DefaultIfEmpty()
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel
{
indexId = t.indexId,
configType = t.configType,
remarks = t.remarks,
address = t.address,
port = t.port,
security = t.security,
network = t.network,
streamSecurity = t.streamSecurity,
subid = t.subid,
subRemarks = t.subRemarks,
isActive = t.indexId == _config.indexId,
sort = t33 == null ? 0 : t33.sort,
delay = t33 == null ? 0 : t33.delay,
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
}).OrderBy(t => t.sort).ToList();
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel));
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
_profileItems.Clear();
_profileItems.AddRange(lstModel);
if (lstModel.Count > 0)
{
var selected = lstModel.FirstOrDefault(t => t.indexId == _config.indexId);
if (selected != null)
{
SelectedProfile = selected;
}
else
{
SelectedProfile = lstModel[0];
}
}
}));
}
public void RefreshSubscriptions()
{
_subItems.Clear();
_subItems.Add(new SubItem { remarks = ResUI.AllGroupServers });
foreach (var item in LazyConfig.Instance.SubItems().OrderBy(t => t.sort))
{
_subItems.Add(item);
}
if (_config.subIndexId != null && _subItems.FirstOrDefault(t => t.id == _config.subIndexId) != null)
{
SelectedSub = _subItems.FirstOrDefault(t => t.id == _config.subIndexId);
}
else
{
SelectedSub = _subItems[0];
}
}
#endregion Servers && Groups
#region Add Servers
private int GetProfileItems(out List<ProfileItem> lstSelecteds, bool latest)
{
lstSelecteds = new List<ProfileItem>();
if (SelectedProfiles == null || SelectedProfiles.Count <= 0)
{
return -1;
}
var orderProfiles = SelectedProfiles?.OrderBy(t => t.sort);
if (latest)
{
foreach (var profile in orderProfiles)
{
var item = LazyConfig.Instance.GetProfileItem(profile.indexId);
if (item is not null)
{
lstSelecteds.Add(item);
}
}
}
else
{
lstSelecteds = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(orderProfiles));
}
return 0;
}
public void EditServer(bool blNew, EConfigType eConfigType)
{
ProfileItem item;
if (blNew)
{
item = new()
{
subid = _config.subIndexId,
configType = eConfigType,
isSub = false,
};
}
else
{
if (Utils.IsNullOrEmpty(SelectedProfile?.indexId))
{
return;
}
item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId);
if (item is null)
{
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
return;
}
eConfigType = item.configType;
}
bool? ret = false;
if (eConfigType == EConfigType.Custom)
{
ret = (new AddServer2Window(item)).ShowDialog();
}
else
{
ret = (new AddServerWindow(item)).ShowDialog();
}
if (ret == true)
{
RefreshServers();
if (item.indexId == _config.indexId)
{
Reload();
}
}
}
public void RemoveServer()
{
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
{
return;
}
if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No)
{
return;
}
var exists = lstSelecteds.Exists(t => t.indexId == _config.indexId);
ConfigHandler.RemoveServer(_config, lstSelecteds);
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
RefreshServers();
if (exists)
{
Reload();
}
}
private void RemoveDuplicateServer()
{
var tuple = ConfigHandler.DedupServerList(_config, _config.subIndexId);
RefreshServers();
Reload();
_noticeHandler?.Enqueue(string.Format(ResUI.RemoveDuplicateServerResult, tuple.Item1, tuple.Item2));
}
private void CopyServer()
{
if (GetProfileItems(out List<ProfileItem> lstSelecteds, false) < 0)
{
return;
}
if (ConfigHandler.CopyServer(_config, lstSelecteds) == 0)
{
RefreshServers();
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
}
}
public void SetDefaultServer()
{
if (Utils.IsNullOrEmpty(SelectedProfile?.indexId))
{
return;
}
SetDefaultServer(SelectedProfile.indexId);
}
private void SetDefaultServer(string indexId)
{
if (Utils.IsNullOrEmpty(indexId))
{
return;
}
if (indexId == _config.indexId)
{
return;
}
var item = LazyConfig.Instance.GetProfileItem(indexId);
if (item is null)
{
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
return;
}
if (ConfigHandler.SetDefaultServerIndex(_config, indexId) == 0)
{
RefreshServers();
Reload();
}
}
private void ServerSelectedChanged(bool c)
{
if (!c)
{
return;
}
if (SelectedServer == null)
{
return;
}
if (Utils.IsNullOrEmpty(SelectedServer.ID))
{
return;
}
SetDefaultServer(SelectedServer.ID);
}
public async void ShareServer()
{
var item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId);
if (item is null)
{
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
return;
}
var url = FmtHandler.GetShareUri(item);
if (Utils.IsNullOrEmpty(url))
{
return;
}
var img = QRCodeHelper.GetQRCode(url);
var dialog = new QrcodeView()
{
imgQrcode = { Source = img },
txtContent = { Text = url },
};
await DialogHost.Show(dialog, "RootDialog");
}
private void SetDefaultMultipleServer(ECoreType coreType)
{
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
{
return;
}
if (ConfigHandler.AddCustomServer4Multiple(_config, lstSelecteds, coreType, out string indexId) != 0)
{
_noticeHandler?.Enqueue(ResUI.OperationFailed);
return;
}
if (indexId == _config.indexId)
{
Reload();
}
else
{
SetDefaultServer(indexId);
}
}
public void SortServer(string colName)
{
if (Utils.IsNullOrEmpty(colName))
{
return;
}
_dicHeaderSort.TryAdd(colName, true);
_dicHeaderSort.TryGetValue(colName, out bool asc);
if (ConfigHandler.SortServers(_config, _config.subIndexId, colName, asc) != 0)
{
return;
}
_dicHeaderSort[colName] = !asc;
RefreshServers();
}
//move server
private void MoveToGroup(bool c)
{
if (!c)
{
return;
}
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
{
return;
}
ConfigHandler.MoveToGroup(_config, lstSelecteds, SelectedMoveToGroup.id);
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
RefreshServers();
SelectedMoveToGroup = new();
//Reload();
}
public void MoveServer(EMove eMove)
{
var item = _lstProfile.FirstOrDefault(t => t.indexId == SelectedProfile.indexId);
if (item is null)
{
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
return;
}
int index = _lstProfile.IndexOf(item);
if (index < 0)
{
return;
}
if (ConfigHandler.MoveServer(_config, ref _lstProfile, index, eMove) == 0)
{
RefreshServers();
}
}
public void MoveServerTo(int startIndex, ProfileItemModel targetItem)
{
var targetIndex = _profileItems.IndexOf(targetItem);
if (startIndex >= 0 && targetIndex >= 0 && startIndex != targetIndex)
{
if (ConfigHandler.MoveServer(_config, ref _lstProfile, startIndex, EMove.Position, targetIndex) == 0)
{
RefreshServers();
}
}
}
public void ServerSpeedtest(ESpeedActionType actionType)
{
if (actionType == ESpeedActionType.Mixedtest)
{
SelectedProfiles = _profileItems;
}
if (GetProfileItems(out List<ProfileItem> lstSelecteds, false) < 0)
{
return;
}
//ClearTestResult();
var coreHandler = Locator.Current.GetService<CoreHandler>();
if (coreHandler != null)
{
new SpeedtestHandler(_config, coreHandler, lstSelecteds, actionType, UpdateSpeedtestHandler);
}
}
private void Export2ClientConfig()
{
var item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId);
if (item is null)
{
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
return;
}
MainFormHandler.Instance.Export2ClientConfig(item, _config);
}
public void Export2ShareUrl()
{
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
{
return;
}
StringBuilder sb = new();
foreach (var it in lstSelecteds)
{
var url = FmtHandler.GetShareUri(it);
if (Utils.IsNullOrEmpty(url))
{
continue;
}
sb.Append(url);
sb.AppendLine();
}
if (sb.Length > 0)
{
Utils.SetClipboardData(sb.ToString());
_noticeHandler?.SendMessage(ResUI.BatchExportURLSuccessfully);
}
}
#endregion Add Servers
#region Subscription
private void EditSub(bool blNew)
{
SubItem item;
if (blNew)
{
item = new();
}
else
{
item = LazyConfig.Instance.GetSubItem(_config.subIndexId);
if (item is null)
{
return;
}
}
var ret = (new SubEditWindow(item)).ShowDialog();
if (ret == true)
{
RefreshSubscriptions();
SubSelectedChanged(true);
}
}
#endregion Subscription
}
}

Some files were not shown because too many files have changed in this diff Show More