Compare commits

...

114 Commits
6.47 ... 6.57

Author SHA1 Message Date
2dust
c22b57927c up 6.57 2024-09-04 16:23:10 +08:00
2dust
81b84d235c Code clean 2024-09-04 16:15:31 +08:00
2dust
488e8aab00 Improvement check updates 2024-09-04 15:47:17 +08:00
Wydy
fc43a9a726 Update pac.txt (#5636) 2024-09-04 09:42:54 +08:00
2dust
31947fdcb3 Bug fix
https://github.com/2dust/v2rayN/issues/5635
2024-09-03 19:30:23 +08:00
2dust
34c7963d28 Bug fix
https://github.com/2dust/v2rayN/issues/5627
2024-09-03 16:14:49 +08:00
2dust
d91b0afb9a Improved log message display 2024-09-03 16:03:26 +08:00
2dust
82eb3fd6bd Unified processing version 2024-09-03 10:16:50 +08:00
2dust
3d3d3f83df Bug fix
https://github.com/2dust/v2rayN/issues/5619#issuecomment-2323968966
2024-09-02 15:10:34 +08:00
2dust
6879c75bc8 Using Queues to Improve Message Display 2024-09-02 14:20:09 +08:00
2dust
b02ad6cdab up 6.56 2024-09-01 19:56:11 +08:00
2dust
f7b16952ea PackageReference 2024-09-01 19:51:18 +08:00
2dust
f0d05a7d4e Refactor check updates 2024-09-01 16:39:45 +08:00
2dust
d6ca317b20 xray mux add more option
https://github.com/2dust/v2rayN/issues/5565
2024-08-31 10:12:21 +08:00
2dust
2879fddfd9 sinb-box mux add padding option
https://github.com/2dust/v2rayN/issues/5544
2024-08-31 09:38:15 +08:00
2dust
b6c09470fc Add global exception catching 2024-08-30 13:47:53 +08:00
2dust
9fdf6c6c32 Bug fix 2024-08-30 13:15:25 +08:00
2dust
79085af994 Bug fix 2024-08-30 12:59:43 +08:00
2dust
d189f4b443 Add custom config Socks port to the group
https://github.com/2dust/v2rayN/issues/5576
2024-08-30 10:12:40 +08:00
2dust
c9d65e5cd9 Fix
https://github.com/2dust/v2rayN/issues/5595
2024-08-30 09:31:44 +08:00
2dust
639d62588a Refactor click event 2024-08-29 20:32:00 +08:00
2dust
6c9db51fd5 Creating a new desktop app with avaloniaui 2024-08-29 15:48:51 +08:00
2dust
f0dbb6b22c Bug fix 2024-08-29 15:19:03 +08:00
2dust
f10f7b6268 Add Portable Mode for mihomo 2024-08-29 10:10:55 +08:00
2dust
48a5cbc552 Check for standalone windows .Net version 2024-08-29 10:09:45 +08:00
2dust
6721d150e0 Refactor QRCodeHelper 2024-08-28 10:20:37 +08:00
2dust
54c16cad7d Adding OSPlatform Processing 2024-08-27 19:44:50 +08:00
2dust
ae3ab15245 Add Socks Protocol string 2024-08-27 16:09:07 +08:00
2dust
d3c0f50fec Adjustment of server binding 2024-08-27 13:18:18 +08:00
2dust
43753b1b7a Add linux download url 2024-08-27 13:06:39 +08:00
2dust
6f3e4b3682 Adding OSPlatform Processing 2024-08-26 18:45:41 +08:00
2dust
b57cdd31bd Refactor_updateView to add task 2024-08-22 19:51:10 +08:00
2dust
b936c194e4 Refactor v2rayUpgrade 2024-08-22 15:23:29 +08:00
2dust
064431421a Bug fix 2024-08-21 21:12:01 +08:00
TTG
9d49c7aad0 Update custom_routing_white (#5566) 2024-08-21 11:18:15 +08:00
2dust
a6f27e5071 Code clean 2024-08-20 14:30:45 +08:00
2dust
8d1d10b783 Refactoring Project 2024-08-20 14:15:29 +08:00
2dust
61bea05f63 Refactoring Project 2024-08-19 18:15:54 +08:00
2dust
bbe7c7b884 Optimized code 2024-08-18 15:04:56 +08:00
Milinda Brantini
a432852b78 Update cidr for direct outboundTag (#5550)
Signed-off-by: Milinda Brantini <C_A_T_T_E_R_Y@outlook.com>
2024-08-18 09:59:33 +08:00
2dust
770e8b8cfa >Export Base64-encoded Share Links to Clipboard 2024-08-17 20:53:42 +08:00
2dust
7faabdc375 Refactor code to decouple view and viewmodel 2024-08-17 10:53:02 +08:00
2dust
a9860418ba Optimized code 2024-08-15 21:03:00 +08:00
2dust
30ff9d0ea9 Optimized code
CoreInfoHandler
2024-08-15 20:13:59 +08:00
2dust
bbc2298939 Bug fix
https://github.com/2dust/v2rayN/issues/5517
2024-08-15 13:58:07 +08:00
2dust
3286e8e24d Refactor code to decouple view and viewmodel 2024-08-15 13:51:30 +08:00
2dust
372f3991e1 Refactor code to decouple view and viewmodel 2024-08-12 20:25:31 +08:00
2dust
9aa5c0d135 Refactor code to decouple view and viewmodel 2024-08-11 20:44:29 +08:00
2dust
9e9808e489 Refactor code to decouple view and viewmodel 2024-08-11 15:45:55 +08:00
2dust
3dd75b17cf Clean code 2024-08-10 19:20:31 +08:00
2dust
2504b4737b Refactor code to decouple view and viewmodel 2024-08-10 14:44:25 +08:00
2dust
8ff04dca0d Refactor code to decouple view and viewmodel 2024-08-10 10:02:00 +08:00
2dust
d893ee4829 up 6.55 2024-08-05 14:41:54 +08:00
2dust
dfc5ec0705 Improve UI 2024-08-05 14:39:04 +08:00
2dust
8023eb74c9 Bug fix 2024-08-04 19:26:01 +08:00
2dust
bb4d3997ad Bug fix
https://github.com/2dust/v2rayN/issues/5467
2024-08-04 09:40:33 +08:00
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
263 changed files with 36887 additions and 7116 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,11 @@
using ReactiveUI;
namespace ServiceLib.Base
{
public class MyReactiveObject : ReactiveObject
{
protected static Config? _config;
protected Func<EViewAction, object?, Task<bool>>? _updateView;
protected NoticeHandler? _noticeHandler;
}
}

View File

@@ -1,10 +1,9 @@
using Downloader;
using System.IO;
using System.Net;
namespace v2rayN
namespace ServiceLib.Common
{
internal class DownloaderHelper
public class DownloaderHelper
{
private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
public static DownloaderHelper Instance => _instance.Value;
@@ -169,11 +168,15 @@ namespace v2rayN
{
progress.Report(101);
}
else if (value.Error != null)
{
throw value.Error;
}
}
};
using var cts = new CancellationTokenSource();
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token);
downloadOpt = null;
}

View File

@@ -1,8 +1,7 @@
using System.IO;
using System.IO.Compression;
using System.IO.Compression;
using System.Text;
namespace v2rayN
namespace ServiceLib.Common
{
public static class FileManager
{
@@ -34,6 +33,22 @@ namespace v2rayN
}
}
public static void UncompressedFile(string fileName, string toPath, string? toName)
{
try
{
FileInfo fileInfo = new(fileName);
using FileStream originalFileStream = fileInfo.OpenRead();
using FileStream decompressedFileStream = File.Create(toName != null ? Path.Combine(toPath, toName) : toPath);
using GZipStream decompressionStream = new(originalFileStream, CompressionMode.Decompress);
decompressionStream.CopyTo(decompressedFileStream);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
public static string NonExclusiveReadAllText(string path)
{
return NonExclusiveReadAllText(path, Encoding.Default);
@@ -86,5 +101,19 @@ namespace v2rayN
}
return true;
}
public static bool CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName)
{
try
{
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return false;
}
return true;
}
}
}

View File

@@ -1,9 +1,8 @@
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
namespace v2rayN
namespace ServiceLib.Common
{
/// <summary>
/// </summary>
@@ -21,6 +20,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 +56,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

@@ -1,7 +1,7 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace v2rayN
namespace ServiceLib.Common
{
/*
* See:

View File

@@ -1,11 +1,10 @@
using System.IO;
using System.Text.Json;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace v2rayN
namespace ServiceLib.Common
{
internal class JsonUtils
public class JsonUtils
{
/// <summary>
/// DeepCopy

View File

@@ -1,9 +1,8 @@
using NLog;
using NLog.Config;
using NLog.Targets;
using System.IO;
namespace v2rayN
namespace ServiceLib.Common
{
public class Logging
{

View File

@@ -0,0 +1,15 @@
using QRCoder;
namespace ServiceLib.Common
{
public class QRCodeHelper
{
public static byte[]? GenQRCode(string? url)
{
using QRCodeGenerator qrGenerator = new();
using QRCodeData qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q);
using PngByteQRCode qrCode = new(qrCodeData);
return qrCode.GetGraphic(20);
}
}
}

View File

@@ -1,7 +1,7 @@
using System.Linq.Expressions;
using System.Reflection;
namespace v2rayN
namespace ServiceLib.Common
{
public static class QueryableExtension
{

View File

@@ -1,4 +1,4 @@
namespace v2rayN
namespace ServiceLib.Common
{
public class SemanticVersion
{
@@ -27,7 +27,7 @@
this.minor = int.Parse(parts[1]);
this.patch = 0;
}
else if (parts.Length == 3)
else if (parts.Length == 3 || parts.Length == 4)
{
this.major = int.Parse(parts[0]);
this.minor = int.Parse(parts[1]);

View File

@@ -1,7 +1,7 @@
using SQLite;
using System.Collections;
namespace v2rayN
namespace ServiceLib.Common
{
public sealed class SQLiteHelper
{

View File

@@ -1,9 +1,8 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace v2rayN
namespace ServiceLib.Common
{
internal static class StringEx
public static class StringEx
{
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{

View File

@@ -1,9 +1,5 @@
using Microsoft.Win32;
using Microsoft.Win32.TaskScheduler;
using System.Collections.Specialized;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.NetworkInformation;
@@ -11,17 +7,12 @@ using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace v2rayN
namespace ServiceLib.Common
{
internal class Utils
public class Utils
{
#region Json操作
@@ -345,14 +336,6 @@ namespace v2rayN
return sb.ToString();
}
public static ImageSource IconToImageSource(Icon icon)
{
return Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
new System.Windows.Int32Rect(0, 0, icon.Width, icon.Height),
BitmapSizeOptions.FromEmptyOptions());
}
/// <summary>
/// idn to idc
/// </summary>
@@ -384,6 +367,7 @@ namespace v2rayN
public static bool IsBase64String(string plainText)
{
if (plainText.IsNullOrEmpty()) return false;
var buffer = new Span<byte>(new byte[plainText.Length]);
return Convert.TryFromBase64String(plainText, buffer, out int _);
}
@@ -420,11 +404,6 @@ namespace v2rayN
}
}
/// <summary>
/// 文本
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static bool IsNullOrEmpty(string? text)
{
if (string.IsNullOrWhiteSpace(text))
@@ -516,29 +495,6 @@ namespace v2rayN
#region
/// <summary>
/// 取得本机 IP Address
/// </summary>
/// <returns></returns>
//public static List<string> GetHostIPAddress()
//{
// List<string> lstIPAddress = new List<string>();
// try
// {
// IPHostEntry IpEntry = Dns.GetHostEntry(Dns.GetHostName());
// foreach (IPAddress ipa in IpEntry.AddressList)
// {
// if (ipa.AddressFamily == AddressFamily.InterNetwork)
// lstIPAddress.Add(ipa.ToString());
// }
// }
// catch (Exception ex)
// {
// SaveLog(ex.Message, ex);
// }
// return lstIPAddress;
//}
public static void SetSecurityProtocol(bool enableSecurityProtocolTls13)
{
if (enableSecurityProtocolTls13)
@@ -614,58 +570,35 @@ namespace v2rayN
string location = GetExePath();
if (blFull)
{
return string.Format("v2rayN - V{0} - {1}",
FileVersionInfo.GetVersionInfo(location).FileVersion?.ToString(),
return string.Format("{0} - V{1} - {2}",
Global.AppName,
GetVersionInfo(),
File.GetLastWriteTime(location).ToString("yyyy/MM/dd"));
}
else
{
return string.Format("v2rayN/{0}",
FileVersionInfo.GetVersionInfo(location).FileVersion?.ToString());
return string.Format("{0}/{1}",
Global.AppName,
GetVersionInfo());
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return string.Empty;
return Global.AppName;
}
}
/// <summary>
/// 获取剪贴板数
/// </summary>
/// <returns></returns>
public static string? GetClipboardData()
public static string GetVersionInfo()
{
string? strData = string.Empty;
try
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.UnicodeText))
{
strData = data.GetData(DataFormats.UnicodeText)?.ToString();
}
return strData;
return Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString() ?? "0.0";
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
return strData;
}
/// <summary>
/// 拷贝至剪贴板
/// </summary>
/// <returns></returns>
public static void SetClipboardData(string strData)
{
try
{
Clipboard.SetText(strData);
}
catch
{
return "0.0";
}
}
@@ -693,26 +626,6 @@ namespace v2rayN
return string.Empty;
}
/// <summary>
/// IsAdministrator
/// </summary>
/// <returns></returns>
public static bool IsAdministrator()
{
try
{
WindowsIdentity current = WindowsIdentity.GetCurrent();
WindowsPrincipal windowsPrincipal = new WindowsPrincipal(current);
//WindowsBuiltInRole可以枚举出很多权限例如系统用户、User、Guest等等
return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return false;
}
}
public static string GetDownloadFileName(string url)
{
var fileName = Path.GetFileName(url);
@@ -752,23 +665,6 @@ namespace v2rayN
}
}
public static void SetDarkBorder(System.Windows.Window window, bool dark)
{
// Make sure the handle is created before the window is shown
IntPtr hWnd = new System.Windows.Interop.WindowInteropHelper(window).EnsureHandle();
int attribute = dark ? 1 : 0;
uint attributeSize = (uint)Marshal.SizeOf(attribute);
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize);
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize);
}
public static bool IsLightTheme()
{
using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
var value = key?.GetValue("AppsUseLightTheme");
return value is int i && i > 0;
}
/// <summary>
/// 获取系统hosts
/// </summary>
@@ -800,6 +696,24 @@ namespace v2rayN
return systemHosts;
}
public static string GetExeName(string name)
{
if (IsWindows())
{
return $"{name}.exe";
}
else
{
return name;
}
}
public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
#endregion
#region TempPath
@@ -945,186 +859,5 @@ namespace v2rayN
}
#endregion TempPath
#region
/// <summary>
/// 开机自动启动
/// </summary>
/// <param name="run"></param>
/// <returns></returns>
public static void SetAutoRun(string AutoRunRegPath, string AutoRunName, bool run)
{
try
{
var autoRunName = $"{AutoRunName}_{GetMD5(StartupPath())}";
//delete first
RegWriteValue(AutoRunRegPath, autoRunName, "");
if (IsAdministrator())
{
AutoStart(autoRunName, "", "");
}
if (run)
{
string exePath = GetExePath();
if (IsAdministrator())
{
AutoStart(autoRunName, exePath, "");
}
else
{
RegWriteValue(AutoRunRegPath, autoRunName, exePath.AppendQuotes());
}
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
public static string? RegReadValue(string path, string name, string def)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.OpenSubKey(path, false);
string? value = regKey?.GetValue(name) as string;
if (IsNullOrEmpty(value))
{
return def;
}
else
{
return value;
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
return def;
}
public static void RegWriteValue(string path, string name, object value)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.CreateSubKey(path);
if (IsNullOrEmpty(value.ToString()))
{
regKey?.DeleteValue(name, false);
}
else
{
regKey?.SetValue(name, value);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
}
/// <summary>
/// Auto Start via TaskService
/// </summary>
/// <param name="taskName"></param>
/// <param name="fileName"></param>
/// <param name="description"></param>
/// <exception cref="ArgumentNullException"></exception>
public static void AutoStart(string taskName, string fileName, string description)
{
if (Utils.IsNullOrEmpty(taskName))
{
return;
}
string TaskName = taskName;
var logonUser = WindowsIdentity.GetCurrent().Name;
string taskDescription = description;
string deamonFileName = fileName;
using var taskService = new TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName));
foreach (var t in tasks)
{
taskService.RootFolder.DeleteTask(t.Name);
}
if (Utils.IsNullOrEmpty(fileName))
{
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = taskDescription;
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.StopIfGoingOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
task.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName.AppendQuotes(), null, Path.GetDirectoryName(deamonFileName)));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
}
public static void RemoveTunDevice()
{
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 "SWD\Wintun\{{{guid}}}" """;
// Try to remove the device
Process proc = new()
{
StartInfo = new()
{
FileName = pnputilPath,
Arguments = arg,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
proc.Start();
var output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
}
catch
{
}
}
#endregion
#region Windows API
[Flags]
public enum DWMWINDOWATTRIBUTE : uint
{
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19,
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
}
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize);
#endregion Windows API
}
}

View File

@@ -0,0 +1,58 @@
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace ServiceLib.Common
{
public 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

@@ -1,4 +1,4 @@
namespace v2rayN.Enums
namespace ServiceLib.Enums
{
public enum EConfigType
{

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Enums
namespace ServiceLib.Enums
{
public enum EInboundProtocol
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Enums
namespace ServiceLib.Enums
{
public enum ETransport
{

View File

@@ -0,0 +1,45 @@
namespace ServiceLib.Enums
{
public enum EViewAction
{
CloseWindow,
ShowYesNo,
SaveFileDialog,
AddBatchRoutingRulesYesNo,
AdjustMainLvColWidth,
UpdateSysProxy,
SetClipboardData,
AddServerViaClipboard,
ImportRulesFromClipboard,
ProfilesFocus,
ShareSub,
ShareServer,
ShowHideWindow,
ScanScreenTask,
Shutdown,
BrowseServer,
ImportRulesFromFile,
SubEditWindow,
RoutingRuleSettingWindow,
RoutingRuleDetailsWindow,
AddServerWindow,
AddServer2Window,
DNSSettingWindow,
RoutingSettingWindow,
OptionSettingWindow,
GlobalHotkeySettingWindow,
SubSettingWindow,
DispatcherSpeedTest,
DispatcherRefreshConnections,
DispatcherRefreshProxyGroups,
DispatcherProxiesDelayTest,
DispatcherStatistics,
DispatcherServerAvailability,
DispatcherReload,
DispatcherRefreshServersBiz,
DispatcherRefreshIcon,
DispatcherCheckUpdate,
DispatcherCheckUpdateFinished,
DispatcherShowMsg,
}
}

View File

@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ReactiveUI />
</Weavers>

View File

@@ -1,11 +1,10 @@
using v2rayN.Enums;
namespace v2rayN
namespace ServiceLib
{
internal class Global
public class Global
{
#region const
public const string AppName = "v2rayN";
public const string GithubUrl = "https://github.com";
public const string GithubApiUrl = "https://api.github.com/repos";
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
@@ -23,27 +22,30 @@ 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 SingboxRulesetUrlGeosite = @"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-{0}.srs";
public const string SingboxRulesetUrlGeoip = @"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/srs/{0}.srs";
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 V2raySampleClient = "v2rayN.Sample.SampleClientConfig";
public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
public const string V2raySampleHttpRequestFileName = "v2rayN.Sample.SampleHttpRequest";
public const string V2raySampleHttpResponseFileName = "v2rayN.Sample.SampleHttpResponse";
public const string V2raySampleInbound = "v2rayN.Sample.SampleInbound";
public const string V2raySampleOutbound = "v2rayN.Sample.SampleOutbound";
public const string SingboxSampleOutbound = "v2rayN.Sample.SingboxSampleOutbound";
public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns";
public const string TunSingboxInboundFileName = "v2rayN.Sample.tun_singbox_inbound";
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 CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
public const string ClashMixinConfigFileName = "Mixin.yaml";
public const string V2raySampleClient = "ServiceLib.Sample.SampleClientConfig";
public const string SingboxSampleClient = "ServiceLib.Sample.SingboxSampleClientConfig";
public const string V2raySampleHttpRequestFileName = "ServiceLib.Sample.SampleHttpRequest";
public const string V2raySampleHttpResponseFileName = "ServiceLib.Sample.SampleHttpResponse";
public const string V2raySampleInbound = "ServiceLib.Sample.SampleInbound";
public const string V2raySampleOutbound = "ServiceLib.Sample.SampleOutbound";
public const string SingboxSampleOutbound = "ServiceLib.Sample.SingboxSampleOutbound";
public const string CustomRoutingFileName = "ServiceLib.Sample.custom_routing_";
public const string TunSingboxDNSFileName = "ServiceLib.Sample.tun_singbox_dns";
public const string TunSingboxInboundFileName = "ServiceLib.Sample.tun_singbox_inbound";
public const string TunSingboxRulesFileName = "ServiceLib.Sample.tun_singbox_rules";
public const string DNSV2rayNormalFileName = "ServiceLib.Sample.dns_v2ray_normal";
public const string DNSSingboxNormalFileName = "ServiceLib.Sample.dns_singbox_normal";
public const string ClashMixinYaml = "ServiceLib.Sample.clash_mixin_yaml";
public const string ClashTunYaml = "ServiceLib.Sample.clash_tun_yaml";
public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp";
@@ -58,6 +60,7 @@ namespace v2rayN
public const string InboundAPIProtocol = "dokodemo-door";
public const string HttpProtocol = "http://";
public const string HttpsProtocol = "https://";
public const string SocksProtocol = "socks://";
public const string UserEMail = "t@t.tt";
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
@@ -70,7 +73,9 @@ namespace v2rayN
public const int MaxPort = 65536;
public const string CommandClearMsg = "CommandClearMsg";
public const string CommandSendMsgView = "CommandSendMsgView";
public const string CommandSendSnackMsg = "CommandSendSnackMsg";
public const string CommandStopSpeedTest = "CommandStopSpeedTest";
public const string CommandRefreshProfiles = "CommandRefreshProfiles";
public const string DelayUnit = "";
public const string SpeedUnit = "";
public const int MinFontSize = 10;
@@ -112,6 +117,7 @@ namespace v2rayN
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",
};
@@ -170,8 +176,11 @@ 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" };
@@ -183,6 +192,10 @@ namespace v2rayN
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,9 @@
global using ServiceLib.Base;
global using ServiceLib.Common;
global using ServiceLib.Enums;
global using ServiceLib.Handler;
global using ServiceLib.Handler.CoreConfig;
global using ServiceLib.Handler.Fmt;
global using ServiceLib.Handler.Statistics;
global using ServiceLib.Models;
global using ServiceLib.Resx;

View File

@@ -0,0 +1,206 @@
using static ServiceLib.Models.ClashProxies;
namespace ServiceLib.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 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)
{
_proxies = clashProxies?.proxies;
update(clashProxies, clashProviders);
return;
}
Task.Delay(5000).Wait();
}
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 (_proxies != null)
{
break;
}
Task.Delay(5000).Wait();
}
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.Config.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());
Task.Delay(1000).Wait();
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 () =>
{
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,17 +1,13 @@
using System.Data;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using v2rayN.Enums;
using v2rayN.Handler.Fmt;
using v2rayN.Models;
namespace v2rayN.Handler
namespace ServiceLib.Handler
{
/// <summary>
/// 本软件配置文件处理类
/// </summary>
internal class ConfigHandler
public class ConfigHandler
{
private static string configRes = Global.ConfigFileName;
private static readonly object objLock = new();
@@ -128,20 +124,16 @@ namespace v2rayN.Handler
mtu = 9000,
};
}
if (config.guiItem == null)
{
config.guiItem = new()
config.guiItem ??= new()
{
enableStatistics = false,
};
}
if (config.uiItem == null)
{
config.uiItem = new UIItem()
config.msgUIItem ??= new();
config.uiItem ??= new UIItem()
{
enableAutoAdjustMainLvColWidth = true
};
}
if (config.uiItem.mainColumnItem == null)
{
config.uiItem.mainColumnItem = new();
@@ -177,6 +169,13 @@ namespace v2rayN.Handler
config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrl;
}
config.mux4RayItem ??= new()
{
concurrency = 8,
xudpConcurrency = 16,
xudpProxyUDP443 = "reject"
};
if (config.mux4SboxItem == null)
{
config.mux4SboxItem = new()
@@ -194,8 +193,17 @@ 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;
}
@@ -345,13 +353,64 @@ namespace v2rayN.Handler
#region Server
public static int AddServer(Config config, ProfileItem profileItem)
{
var item = LazyConfig.Instance.GetProfileItem(profileItem.indexId);
if (item is null)
{
item = profileItem;
}
else
{
item.coreType = profileItem.coreType;
item.remarks = profileItem.remarks;
item.address = profileItem.address;
item.port = profileItem.port;
item.id = profileItem.id;
item.alterId = profileItem.alterId;
item.security = profileItem.security;
item.flow = profileItem.flow;
item.network = profileItem.network;
item.headerType = profileItem.headerType;
item.requestHost = profileItem.requestHost;
item.path = profileItem.path;
item.streamSecurity = profileItem.streamSecurity;
item.sni = profileItem.sni;
item.allowInsecure = profileItem.allowInsecure;
item.fingerprint = profileItem.fingerprint;
item.alpn = profileItem.alpn;
item.publicKey = profileItem.publicKey;
item.shortId = profileItem.shortId;
item.spiderX = profileItem.spiderX;
}
var ret = item.configType switch
{
EConfigType.VMess => AddVMessServer(config, item),
EConfigType.Shadowsocks => AddShadowsocksServer(config, item),
EConfigType.Socks => AddSocksServer(config, item),
EConfigType.Http => AddHttpServer(config, item),
EConfigType.Trojan => AddTrojanServer(config, item),
EConfigType.VLESS => AddVlessServer(config, item),
EConfigType.Hysteria2 => AddHysteria2Server(config, item),
EConfigType.Tuic => AddTuicServer(config, item),
EConfigType.Wireguard => AddWireguardServer(config, item),
_ => -1,
};
return ret;
}
/// <summary>
/// Add or edit server
/// </summary>
/// <param name="config"></param>
/// <param name="profileItem"></param>
/// <returns></returns>
public static int AddServer(Config config, ProfileItem profileItem, bool toFile = true)
public static int AddVMessServer(Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configType = EConfigType.VMess;
@@ -609,7 +668,21 @@ namespace v2rayN.Handler
/// <returns></returns>
public static int EditCustomServer(Config config, ProfileItem profileItem)
{
if (SQLiteHelper.Instance.Update(profileItem) > 0)
var item = LazyConfig.Instance.GetProfileItem(profileItem.indexId);
if (item is null)
{
item = profileItem;
}
else
{
item.remarks = profileItem.remarks;
item.address = profileItem.address;
item.coreType = profileItem.coreType;
item.displayLog = profileItem.displayLog;
item.preSocksPort = profileItem.preSocksPort;
}
if (SQLiteHelper.Instance.Update(item) > 0)
{
return 0;
}
@@ -1064,6 +1137,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 ? ResUI.menuSetDefaultMultipleServer : 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
@@ -1152,7 +1252,7 @@ namespace v2rayN.Handler
var addStatus = profileItem.configType switch
{
EConfigType.VMess => AddServer(config, profileItem, false),
EConfigType.VMess => AddVMessServer(config, profileItem, false),
EConfigType.Shadowsocks => AddShadowsocksServer(config, profileItem, false),
EConfigType.Socks => AddSocksServer(config, profileItem, false),
EConfigType.Trojan => AddTrojanServer(config, profileItem, false),
@@ -1185,7 +1285,10 @@ namespace v2rayN.Handler
{
return -1;
}
var subRemarks = LazyConfig.Instance.GetSubItem(subid)?.remarks;
var subItem = LazyConfig.Instance.GetSubItem(subid);
var subRemarks = subItem?.remarks;
var preSocksPort = subItem?.preSocksPort;
List<ProfileItem>? lstProfiles = null;
//Is sing-box array configuration
@@ -1209,6 +1312,7 @@ namespace v2rayN.Handler
{
it.subid = subid;
it.isSub = isSub;
it.preSocksPort = preSocksPort;
if (AddCustomServer(config, it, true) == 0)
{
count++;
@@ -1265,6 +1369,7 @@ namespace v2rayN.Handler
}
profileItem.subid = subid;
profileItem.isSub = isSub;
profileItem.preSocksPort = preSocksPort;
if (AddCustomServer(config, profileItem, true) == 0)
{
return 1;
@@ -1309,6 +1414,10 @@ namespace v2rayN.Handler
public static int AddBatchServers(Config config, string strData, string subid, bool isSub)
{
if (Utils.IsNullOrEmpty(strData))
{
return -1;
}
List<ProfileItem>? lstOriSub = null;
if (isSub && !Utils.IsNullOrEmpty(subid))
{
@@ -1382,21 +1491,43 @@ namespace v2rayN.Handler
public static int AddSubItem(Config config, SubItem subItem)
{
if (Utils.IsNullOrEmpty(subItem.id))
var item = LazyConfig.Instance.GetSubItem(subItem.id);
if (item is null)
{
subItem.id = Utils.GetGUID(false);
item = subItem;
}
else
{
item.remarks = subItem.remarks;
item.url = subItem.url;
item.moreUrl = subItem.moreUrl;
item.enabled = subItem.enabled;
item.autoUpdateInterval = subItem.autoUpdateInterval;
item.userAgent = subItem.userAgent;
item.sort = subItem.sort;
item.filter = subItem.filter;
item.updateTime = subItem.updateTime;
item.convertTarget = subItem.convertTarget;
item.prevProfile = subItem.prevProfile;
item.nextProfile = subItem.nextProfile;
item.preSocksPort = subItem.preSocksPort;
}
if (subItem.sort <= 0)
if (Utils.IsNullOrEmpty(item.id))
{
item.id = Utils.GetGUID(false);
if (item.sort <= 0)
{
var maxSort = 0;
if (SQLiteHelper.Instance.Table<SubItem>().Count() > 0)
{
maxSort = SQLiteHelper.Instance.Table<SubItem>().Max(t => t == null ? 0 : t.sort);
}
subItem.sort = maxSort + 1;
item.sort = maxSort + 1;
}
}
if (SQLiteHelper.Instance.Replace(subItem) > 0)
if (SQLiteHelper.Instance.Replace(item) > 0)
{
return 0;
}

View File

@@ -0,0 +1,265 @@
namespace ServiceLib.Handler.CoreConfig
{
/// <summary>
/// Core configuration file processing class
/// </summary>
public 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,14 +1,9 @@
using System.IO;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.CoreConfig
namespace ServiceLib.Handler.CoreConfig
{
/// <summary>
/// Core configuration file processing class
/// </summary>
internal class CoreConfigHandler
public class CoreConfigHandler
{
public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
{
@@ -20,13 +15,26 @@ namespace v2rayN.Handler.CoreConfig
msg = ResUI.CheckServerSettings;
return -1;
}
var config = LazyConfig.Instance.GetConfig();
var config = LazyConfig.Instance.Config;
msg = ResUI.InitialConfiguration;
if (node.configType == EConfigType.Custom)
{
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 (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
{
var configGenSingbox = new CoreConfigSingbox(config);
@@ -105,41 +113,6 @@ namespace v2rayN.Handler.CoreConfig
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)
@@ -171,5 +144,28 @@ namespace v2rayN.Handler.CoreConfig
}
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,12 +1,10 @@
using System.Net;
using System.Data;
using System.Net;
using System.Net.NetworkInformation;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.CoreConfig
namespace ServiceLib.Handler.CoreConfig
{
internal class CoreConfigSingbox
public class CoreConfigSingbox
{
private Config _config;
@@ -15,6 +13,8 @@ namespace v2rayN.Handler.CoreConfig
_config = config;
}
#region public gen function
public int GenerateClientConfigContent(ProfileItem node, out SingboxConfig? singboxConfig, out string msg)
{
singboxConfig = null;
@@ -75,6 +75,356 @@ namespace v2rayN.Handler.CoreConfig
return 0;
}
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out SingboxConfig? singboxConfig, out string msg)
{
singboxConfig = null;
try
{
if (_config == null)
{
msg = ResUI.CheckServerSettings;
return -1;
}
msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
}
singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
if (singboxConfig == null)
{
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new();
try
{
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
GenLog(singboxConfig);
//GenDns(new(), singboxConfig);
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
singboxConfig.outbounds.RemoveAt(0);
int httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds)
{
if (it.configType == EConfigType.Custom)
{
continue;
}
if (it.port <= 0)
{
continue;
}
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
{
continue;
}
}
//find unused port
var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++)
{
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{
continue;
}
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
{
continue;
}
//found
port = k;
httpPort = port + 1;
break;
}
//Port In Used
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
{
continue;
}
it.port = port;
it.allowTest = true;
//inbound
Inbound4Sbox inbound = new()
{
listen = Global.Loopback,
listen_port = port,
type = EInboundProtocol.http.ToString(),
};
inbound.tag = inbound.type + inbound.listen_port.ToString();
singboxConfig.inbounds.Add(inbound);
//outbound
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
continue;
}
if (item.configType == EConfigType.Shadowsocks
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
{
continue;
}
if (item.configType == EConfigType.VLESS
&& !Global.Flows.Contains(item.flow))
{
continue;
}
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.listen_port.ToString();
singboxConfig.outbounds.Add(outbound);
//rule
Rule4Sbox rule = new()
{
inbound = new List<string> { inbound.tag },
outbound = outbound.tag
};
singboxConfig.route.rules.Add(rule);
}
GenDnsDomains(null, singboxConfig, null);
//var dnsServer = singboxConfig.dns?.servers.FirstOrDefault();
//if (dnsServer != null)
//{
// dnsServer.detour = singboxConfig.route.rules.LastOrDefault()?.outbound;
//}
//var dnsRule = singboxConfig.dns?.rules.Where(t => t.outbound != null).FirstOrDefault();
//if (dnsRule != null)
//{
// singboxConfig.dns.rules = [];
// singboxConfig.dns.rules.Add(dnsRule);
//}
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
}
public int GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds, out SingboxConfig? singboxConfig, out string msg)
{
singboxConfig = null;
try
{
if (_config == null)
{
msg = ResUI.CheckServerSettings;
return -1;
}
msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
}
singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
if (singboxConfig == null)
{
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
GenLog(singboxConfig);
GenInbounds(singboxConfig);
GenRouting(singboxConfig);
GenExperimental(singboxConfig);
singboxConfig.outbounds.RemoveAt(0);
var tagProxy = new List<string>();
foreach (var it in selecteds)
{
if (it.configType == EConfigType.Custom)
{
continue;
}
if (it.port <= 0)
{
continue;
}
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
continue;
}
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{
if (Utils.IsNullOrEmpty(item.id) || !Utils.IsGuidByParse(item.id))
{
continue;
}
}
if (item.configType == EConfigType.Shadowsocks
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
{
continue;
}
if (item.configType == EConfigType.VLESS && !Global.Flows.Contains(item.flow))
{
continue;
}
//outbound
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
GenOutbound(item, outbound);
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
singboxConfig.outbounds.Add(outbound);
tagProxy.Add(outbound.tag);
}
if (tagProxy.Count <= 0)
{
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
GenDns(null, singboxConfig);
ConvertGeo2Ruleset(singboxConfig);
//add urltest outbound
var outUrltest = new Outbound4Sbox
{
type = "urltest",
tag = $"{Global.ProxyTag}-auto",
outbounds = tagProxy,
interrupt_exist_connections = false,
};
singboxConfig.outbounds.Add(outUrltest);
//add selector outbound
var outSelector = new Outbound4Sbox
{
type = "selector",
tag = Global.ProxyTag,
outbounds = JsonUtils.DeepCopy(tagProxy),
interrupt_exist_connections = false,
};
outSelector.outbounds.Insert(0, outUrltest.tag);
singboxConfig.outbounds.Add(outSelector);
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
}
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;
}
if (node.address == Global.CoreMultipleLoadConfigFileName)
{
var txtFile = File.ReadAllText(addressFileName);
var singboxConfig = JsonUtils.Deserialize<SingboxConfig>(txtFile);
if (singboxConfig == null)
{
File.Copy(addressFileName, fileName);
}
else
{
GenInbounds(singboxConfig);
GenExperimental(singboxConfig);
JsonUtils.ToFile(singboxConfig, fileName, false);
}
}
else
{
File.Copy(addressFileName, fileName);
}
//check again
if (!File.Exists(fileName))
{
msg = ResUI.FailedReadConfiguration + "2";
return -1;
}
msg = string.Format(ResUI.SuccessfulConfiguration, $"{node.GetSummary()}");
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
return 0;
}
#endregion public gen function
#region private gen function
private int GenLog(SingboxConfig singboxConfig)
@@ -352,6 +702,7 @@ namespace v2rayN.Handler.CoreConfig
enabled = true,
protocol = _config.mux4SboxItem.protocol,
max_connections = _config.mux4SboxItem.max_connections,
padding = _config.mux4SboxItem.padding,
};
outbound.multiplex = mux;
}
@@ -558,6 +909,17 @@ namespace v2rayN.Handler.CoreConfig
});
}
singboxConfig.route.rules.Insert(0, new()
{
outbound = Global.DirectTag,
clash_mode = ERuleMode.Direct.ToString()
});
singboxConfig.route.rules.Insert(0, new()
{
outbound = Global.ProxyTag,
clash_mode = ERuleMode.Global.ToString()
});
if (_config.tunModeItem.enableTun)
{
singboxConfig.route.auto_detect_interface = true;
@@ -622,7 +984,7 @@ namespace v2rayN.Handler.CoreConfig
{
lstDnsExe = new();
lstDirectExe = new();
var coreInfo = LazyConfig.Instance.GetCoreInfo();
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfo)
{
if (it.coreType == ECoreType.v2rayN)
@@ -802,7 +1164,7 @@ namespace v2rayN.Handler.CoreConfig
return true;
}
private int GenDns(ProfileItem node, SingboxConfig singboxConfig)
private int GenDns(ProfileItem? node, SingboxConfig singboxConfig)
{
try
{
@@ -824,7 +1186,7 @@ namespace v2rayN.Handler.CoreConfig
}
singboxConfig.dns = dns4Sbox;
GenDnsDomains(singboxConfig);
GenDnsDomains(node, singboxConfig, item);
}
catch (Exception ex)
{
@@ -833,33 +1195,55 @@ namespace v2rayN.Handler.CoreConfig
return 0;
}
private int GenDnsDomains(SingboxConfig singboxConfig)
private int GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem)
{
var dns4Sbox = singboxConfig.dns ?? new();
dns4Sbox.servers ??= [];
dns4Sbox.rules ??= [];
var lstDomain = singboxConfig.outbounds
.Where(t => !Utils.IsNullOrEmpty(t.server) && Utils.IsDomain(t.server))
.Select(t => t.server)
.ToList();
if (lstDomain != null && lstDomain.Count > 0)
{
//var strategy = dns4Sbox.servers.Where(t => !Utils.IsNullOrEmpty(t.strategy)).Select(t => t.strategy).FirstOrDefault();
var tag = "local_local";
dns4Sbox.servers.Add(new()
{
tag = tag,
address = "223.5.5.5",
address = Utils.IsNullOrEmpty(dNSItem?.domainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.domainDNSAddress,
detour = Global.DirectTag,
//strategy = strategy
strategy = Utils.IsNullOrEmpty(dNSItem?.domainStrategy4Freedom) ? null : dNSItem?.domainStrategy4Freedom,
});
dns4Sbox.rules.Add(new()
dns4Sbox.rules.Insert(0, new()
{
server = tag,
clash_mode = ERuleMode.Direct.ToString()
});
dns4Sbox.rules.Insert(0, new()
{
server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote",
clash_mode = ERuleMode.Global.ToString()
});
var lstDomain = singboxConfig.outbounds
.Where(t => !Utils.IsNullOrEmpty(t.server) && Utils.IsDomain(t.server))
.Select(t => t.server)
.Distinct()
.ToList();
if (lstDomain != null && lstDomain.Count > 0)
{
dns4Sbox.rules.Insert(0, new()
{
server = tag,
domain = lstDomain
});
}
//Tun2SocksAddress
if (_config.tunModeItem.enableTun && node?.configType == EConfigType.Socks && Utils.IsDomain(node?.sni))
{
dns4Sbox.rules.Insert(0, new()
{
server = tag,
domain = [node?.sni]
});
}
singboxConfig.dns = dns4Sbox;
return 0;
}
@@ -889,6 +1273,10 @@ namespace v2rayN.Handler.CoreConfig
private int ConvertGeo2Ruleset(SingboxConfig singboxConfig)
{
static void AddRuleSets(List<string> ruleSets, List<string>? rule_set)
{
if (rule_set != null) ruleSets.AddRange(rule_set);
}
var geosite = "geosite";
var geoip = "geoip";
var ruleSets = new List<string>();
@@ -898,13 +1286,13 @@ namespace v2rayN.Handler.CoreConfig
{
rule.rule_set = rule?.geosite?.Select(t => $"{geosite}-{t}").ToList();
rule.geosite = null;
ruleSets.AddRange(rule.rule_set);
AddRuleSets(ruleSets, rule.rule_set);
}
foreach (var rule in singboxConfig.route.rules.Where(t => t.geoip?.Count > 0).ToList() ?? [])
{
rule.rule_set = rule?.geoip?.Select(t => $"{geoip}-{t}").ToList();
rule.geoip = null;
ruleSets.AddRange(rule.rule_set);
AddRuleSets(ruleSets, rule.rule_set);
}
//convert dns geosite & geoip to ruleset
@@ -920,7 +1308,15 @@ namespace v2rayN.Handler.CoreConfig
}
foreach (var dnsRule in singboxConfig.dns?.rules.Where(t => t.rule_set?.Count > 0).ToList() ?? [])
{
ruleSets.AddRange(dnsRule.rule_set);
AddRuleSets(ruleSets, dnsRule.rule_set);
}
//rules in rules
foreach (var item in singboxConfig.dns?.rules.Where(t => t.rules?.Count > 0).Select(t => t.rules).ToList() ?? [])
{
foreach (var item2 in item ?? [])
{
AddRuleSets(ruleSets, item2.rule_set);
}
}
//load custom ruleset file
@@ -942,194 +1338,46 @@ namespace v2rayN.Handler.CoreConfig
}
}
//Local srs files address
var localSrss = Utils.GetBinPath("srss");
//Add ruleset srs
singboxConfig.route.rule_set = [];
foreach (var item in new HashSet<string>(ruleSets))
{
if (Utils.IsNullOrEmpty(item)) { continue; }
var customRuleset = customRulesets.FirstOrDefault(t => t.tag != null && t.tag.Equals(item));
if (customRuleset != null)
if (customRuleset is null)
{
singboxConfig.route.rule_set.Add(customRuleset);
var pathSrs = Path.Combine(localSrss, $"{item}.srs");
if (File.Exists(pathSrs))
{
customRuleset = new()
{
type = "local",
format = "binary",
tag = item,
path = pathSrs
};
}
else
{
var geo = item.Split('-').FirstOrDefault() ?? geosite;
var value = item.Split('-').LastOrDefault();
singboxConfig.route.rule_set.Add(new()
customRuleset = new()
{
type = "remote",
format = "binary",
tag = item,
url = string.Format(geo.Equals(geosite) ? Global.SingboxRulesetUrlGeosite : Global.SingboxRulesetUrlGeoip, value),
url = string.Format(Global.SingboxRulesetUrl, item.StartsWith(geosite) ? geosite : geoip, item),
download_detour = Global.ProxyTag
});
};
}
}
singboxConfig.route.rule_set.Add(customRuleset);
}
return 0;
}
#endregion private gen function
#region Gen speedtest config
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out SingboxConfig? singboxConfig, out string msg)
{
singboxConfig = null;
try
{
if (_config == null)
{
msg = ResUI.CheckServerSettings;
return -1;
}
msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
}
singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
if (singboxConfig == null)
{
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new();
try
{
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
GenLog(singboxConfig);
//GenDns(new(), singboxConfig);
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
singboxConfig.outbounds.RemoveAt(0);
int httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds)
{
if (it.configType == EConfigType.Custom)
{
continue;
}
if (it.port <= 0)
{
continue;
}
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
{
continue;
}
}
//find unused port
var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++)
{
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{
continue;
}
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
{
continue;
}
//found
port = k;
httpPort = port + 1;
break;
}
//Port In Used
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
{
continue;
}
it.port = port;
it.allowTest = true;
//inbound
Inbound4Sbox inbound = new()
{
listen = Global.Loopback,
listen_port = port,
type = EInboundProtocol.http.ToString(),
};
inbound.tag = inbound.type + inbound.listen_port.ToString();
singboxConfig.inbounds.Add(inbound);
//outbound
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
continue;
}
if (item.configType == EConfigType.Shadowsocks
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
{
continue;
}
if (item.configType == EConfigType.VLESS
&& !Global.Flows.Contains(item.flow))
{
continue;
}
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.listen_port.ToString();
singboxConfig.outbounds.Add(outbound);
//rule
Rule4Sbox rule = new()
{
inbound = new List<string> { inbound.tag },
outbound = outbound.tag
};
singboxConfig.route.rules.Add(rule);
}
GenDnsDomains(singboxConfig);
//var dnsServer = singboxConfig.dns?.servers.FirstOrDefault();
//if (dnsServer != null)
//{
// dnsServer.detour = singboxConfig.route.rules.LastOrDefault()?.outbound;
//}
//var dnsRule = singboxConfig.dns?.rules.Where(t => t.outbound != null).FirstOrDefault();
//if (dnsRule != null)
//{
// singboxConfig.dns.rules = [];
// singboxConfig.dns.rules.Add(dnsRule);
//}
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
}
#endregion Gen speedtest config
}
}

View File

@@ -1,12 +1,10 @@
using System.Net;
using System.Net.NetworkInformation;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
using System.Text.Json.Nodes;
namespace v2rayN.Handler.CoreConfig
namespace ServiceLib.Handler.CoreConfig
{
internal class CoreConfigV2ray
public class CoreConfigV2ray
{
private Config _config;
@@ -15,6 +13,8 @@ namespace v2rayN.Handler.CoreConfig
_config = config;
}
#region public gen function
public int GenerateClientConfigContent(ProfileItem node, out V2rayConfig? v2rayConfig, out string msg)
{
v2rayConfig = null;
@@ -53,7 +53,7 @@ namespace v2rayN.Handler.CoreConfig
GenMoreOutbounds(node, v2rayConfig);
GenDns(v2rayConfig);
GenDns(node, v2rayConfig);
GenStatistic(v2rayConfig);
@@ -68,6 +68,276 @@ namespace v2rayN.Handler.CoreConfig
return 0;
}
public int GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds, out V2rayConfig? v2rayConfig, out string msg)
{
v2rayConfig = null;
try
{
if (_config == null)
{
msg = ResUI.CheckServerSettings;
return -1;
}
msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.V2raySampleClient);
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
}
v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
if (v2rayConfig == null)
{
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
GenLog(v2rayConfig);
GenInbounds(v2rayConfig);
GenRouting(v2rayConfig);
GenDns(null, v2rayConfig);
GenStatistic(v2rayConfig);
v2rayConfig.outbounds.RemoveAt(0);
var tagProxy = new List<string>();
foreach (var it in selecteds)
{
if (it.configType == EConfigType.Custom)
{
continue;
}
if (it.configType is EConfigType.Hysteria2 or EConfigType.Tuic or EConfigType.Wireguard)
{
continue;
}
if (it.port <= 0)
{
continue;
}
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
continue;
}
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{
if (Utils.IsNullOrEmpty(item.id) || !Utils.IsGuidByParse(item.id))
{
continue;
}
}
if (item.configType == EConfigType.Shadowsocks
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
{
continue;
}
if (item.configType == EConfigType.VLESS && !Global.Flows.Contains(item.flow))
{
continue;
}
//outbound
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
GenOutbound(item, outbound);
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
v2rayConfig.outbounds.Add(outbound);
tagProxy.Add(outbound.tag);
}
if (tagProxy.Count <= 0)
{
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
//add balancers
var balancer = new BalancersItem4Ray
{
selector = [Global.ProxyTag],
strategy = new() { type = "roundRobin" },
tag = $"{Global.ProxyTag}-round",
};
v2rayConfig.routing.balancers = [balancer];
//add rule
var rules = v2rayConfig.routing.rules.Where(t => t.outboundTag == Global.ProxyTag).ToList();
if (rules?.Count > 0)
{
foreach (var rule in rules)
{
rule.outboundTag = null;
rule.balancerTag = balancer.tag;
}
}
else
{
v2rayConfig.routing.rules.Add(new()
{
network = "tcp,udp",
balancerTag = balancer.tag,
type = "field"
});
}
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
}
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out V2rayConfig? v2rayConfig, out string msg)
{
v2rayConfig = null;
try
{
if (_config == null)
{
msg = ResUI.CheckServerSettings;
return -1;
}
msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.V2raySampleClient);
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
}
v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
if (v2rayConfig == null)
{
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new();
try
{
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
GenLog(v2rayConfig);
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
v2rayConfig.outbounds.RemoveAt(0);
int httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds)
{
if (it.configType == EConfigType.Custom)
{
continue;
}
if (it.port <= 0)
{
continue;
}
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
{
continue;
}
}
//find unused port
var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++)
{
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{
continue;
}
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
{
continue;
}
//found
port = k;
httpPort = port + 1;
break;
}
//Port In Used
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
{
continue;
}
it.port = port;
it.allowTest = true;
//inbound
Inbounds4Ray inbound = new()
{
listen = Global.Loopback,
port = port,
protocol = EInboundProtocol.http.ToString(),
};
inbound.tag = inbound.protocol + inbound.port.ToString();
v2rayConfig.inbounds.Add(inbound);
//outbound
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
continue;
}
if (item.configType == EConfigType.Shadowsocks
&& !Global.SsSecuritiesInXray.Contains(item.security))
{
continue;
}
if (item.configType == EConfigType.VLESS
&& !Global.Flows.Contains(item.flow))
{
continue;
}
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.port.ToString();
v2rayConfig.outbounds.Add(outbound);
//rule
RulesItem4Ray rule = new()
{
inboundTag = new List<string> { inbound.tag },
outboundTag = outbound.tag,
type = "field"
};
v2rayConfig.routing.rules.Add(rule);
}
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
}
#endregion public gen function
#region private gen function
private int GenLog(V2rayConfig v2rayConfig)
@@ -500,7 +770,9 @@ namespace v2rayN.Handler.CoreConfig
if (enabled)
{
outbound.mux.enabled = true;
outbound.mux.concurrency = 8;
outbound.mux.concurrency = _config.mux4RayItem.concurrency;
outbound.mux.xudpConcurrency = _config.mux4RayItem.xudpConcurrency;
outbound.mux.xudpProxyUDP443 = _config.mux4RayItem.xudpProxyUDP443;
}
else
{
@@ -748,7 +1020,7 @@ namespace v2rayN.Handler.CoreConfig
return 0;
}
private int GenDns(V2rayConfig v2rayConfig)
private int GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
{
try
{
@@ -800,6 +1072,8 @@ namespace v2rayN.Handler.CoreConfig
}
}
GenDnsDomains(node, obj, item);
v2rayConfig.dns = obj;
}
catch (Exception ex)
@@ -809,6 +1083,26 @@ namespace v2rayN.Handler.CoreConfig
return 0;
}
private int GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
{
if (node == null)
{ return 0; }
var servers = dns["servers"];
if (servers != null)
{
if (Utils.IsDomain(node.address))
{
var dnsServer = new DnsServer4Ray()
{
address = Utils.IsNullOrEmpty(dNSItem?.domainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.domainDNSAddress,
domains = [node.address]
};
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
}
}
return 0;
}
private int GenStatistic(V2rayConfig v2rayConfig)
{
if (_config.guiItem.enableStatistics)
@@ -952,153 +1246,5 @@ namespace v2rayN.Handler.CoreConfig
}
#endregion private gen function
#region Gen speedtest config
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out V2rayConfig? v2rayConfig, out string msg)
{
v2rayConfig = null;
try
{
if (_config == null)
{
msg = ResUI.CheckServerSettings;
return -1;
}
msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.V2raySampleClient);
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
}
v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
if (v2rayConfig == null)
{
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new();
try
{
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
GenLog(v2rayConfig);
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
v2rayConfig.outbounds.RemoveAt(0);
int httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds)
{
if (it.configType == EConfigType.Custom)
{
continue;
}
if (it.port <= 0)
{
continue;
}
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
{
continue;
}
}
//find unused port
var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++)
{
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{
continue;
}
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
{
continue;
}
//found
port = k;
httpPort = port + 1;
break;
}
//Port In Used
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
{
continue;
}
it.port = port;
it.allowTest = true;
//inbound
Inbounds4Ray inbound = new()
{
listen = Global.Loopback,
port = port,
protocol = EInboundProtocol.http.ToString(),
};
inbound.tag = inbound.protocol + inbound.port.ToString();
v2rayConfig.inbounds.Add(inbound);
//outbound
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
continue;
}
if (item.configType == EConfigType.Shadowsocks
&& !Global.SsSecuritiesInXray.Contains(item.security))
{
continue;
}
if (item.configType == EConfigType.VLESS
&& !Global.Flows.Contains(item.flow))
{
continue;
}
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.port.ToString();
v2rayConfig.outbounds.Add(outbound);
//rule
RulesItem4Ray rule = new()
{
inboundTag = new List<string> { inbound.tag },
outboundTag = outbound.tag,
type = "field"
};
v2rayConfig.routing.rules.Add(rule);
}
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
}
#endregion Gen speedtest config
}
}

View File

@@ -1,18 +1,12 @@
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;
namespace v2rayN.Handler
namespace ServiceLib.Handler
{
/// <summary>
/// Core process processing class
/// </summary>
internal class CoreHandler
public class CoreHandler
{
private Config _config;
private Process? _process;
@@ -28,9 +22,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);
@@ -48,12 +41,6 @@ namespace v2rayN.Handler
ShowMsg(false, msg);
ShowMsg(true, $"{node.GetSummary()}");
CoreStop();
if (_config.tunModeItem.enableTun)
{
Thread.Sleep(1000);
Utils.RemoveTunDevice();
}
CoreStart(node);
//In tun mode, do a delay check and restart the core
@@ -116,7 +103,7 @@ namespace v2rayN.Handler
if (!hasProc)
{
var coreInfo = LazyConfig.Instance.GetCoreInfo();
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfo)
{
if (it.coreType == ECoreType.v2rayN)
@@ -129,7 +116,7 @@ namespace v2rayN.Handler
foreach (Process p in existing)
{
string? path = p.MainModule?.FileName;
if (path == $"{Utils.GetBinPath(vName, it.coreType.ToString())}.exe")
if (path == Utils.GetExeName(Utils.GetBinPath(vName, it.coreType.ToString())))
{
KillProcess(p);
}
@@ -164,7 +151,7 @@ namespace v2rayN.Handler
string fileName = string.Empty;
foreach (string name in coreInfo.coreExes)
{
string vName = $"{name}.exe";
string vName = Utils.GetExeName(name);
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
if (File.Exists(vName))
{
@@ -197,7 +184,7 @@ namespace v2rayN.Handler
//}
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
_config.runningCoreType = coreType;
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
var proc = RunProcess(node, coreInfo, "", displayLog);
@@ -219,6 +206,7 @@ namespace v2rayN.Handler
coreType = preCoreType,
configType = EConfigType.Socks,
address = Global.Loopback,
sni = node.address, //Tun2SocksAddress
port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)
};
}
@@ -230,7 +218,7 @@ namespace v2rayN.Handler
coreType = preCoreType,
configType = EConfigType.Socks,
address = Global.Loopback,
port = node.preSocksPort
port = node.preSocksPort.Value,
};
_config.runningCoreType = preCoreType;
}
@@ -239,7 +227,7 @@ namespace v2rayN.Handler
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
{
var coreInfo2 = LazyConfig.Instance.GetCoreInfo(preCoreType);
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc2 = RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
if (proc2 is not null)
{
@@ -257,7 +245,7 @@ namespace v2rayN.Handler
ShowMsg(false, configPath);
try
{
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
if (proc is null)
{

View File

@@ -0,0 +1,217 @@
using System.Runtime.Intrinsics.X86;
namespace ServiceLib.Handler
{
public sealed class CoreInfoHandler
{
private static readonly Lazy<CoreInfoHandler> _instance = new(() => new());
private List<CoreInfo>? _coreInfo;
public static CoreInfoHandler Instance => _instance.Value;
public CoreInfoHandler()
{
InitCoreInfo();
}
public CoreInfo? GetCoreInfo(ECoreType coreType)
{
if (_coreInfo == null)
{
InitCoreInfo();
}
return _coreInfo?.FirstOrDefault(t => t.coreType == coreType);
}
public List<CoreInfo> GetCoreInfo()
{
if (_coreInfo == null)
{
InitCoreInfo();
}
return _coreInfo ?? [];
}
private void InitCoreInfo()
{
_coreInfo = [];
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.v2rayN,
coreUrl = Global.NUrl,
coreReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip",
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip",
coreDownloadUrlLinux32 = Global.NUrl + "/download/{0}/v2rayN-linux-32.zip",
coreDownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
coreDownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.v2fly,
coreExes = new List<string> { "wv2ray", "v2ray" },
arguments = "",
coreUrl = Global.V2flyCoreUrl,
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "V2Ray",
versionArg = "-version",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.SagerNet,
coreExes = new List<string> { "SagerNet", "v2ray" },
arguments = "run",
coreUrl = Global.SagerNetCoreUrl,
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "V2Ray",
versionArg = "version",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.v2fly_v5,
coreExes = new List<string> { "v2ray" },
arguments = "run -c config.json -format jsonv5",
coreUrl = Global.V2flyCoreUrl,
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "V2Ray",
versionArg = "version",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.Xray,
coreExes = new List<string> { "xray", "wxray" },
arguments = "run {0}",
coreUrl = Global.XrayCoreUrl,
coreReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
coreDownloadUrl32 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-32.zip",
coreDownloadUrl64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
coreDownloadUrlArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
coreDownloadUrlLinux32 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-32.zip",
coreDownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
coreDownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
match = "Xray",
versionArg = "-version",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.clash,
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
arguments = "-f config.json" + PortableMode(),
coreUrl = Global.ClashCoreUrl,
coreReleaseApiUrl = Global.ClashCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "v",
versionArg = "-v",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.clash_meta,
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
arguments = "-f config.json" + PortableMode(),
coreUrl = Global.ClashMetaCoreUrl,
coreReleaseApiUrl = Global.ClashMetaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "v",
versionArg = "-v",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.mihomo,
coreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
arguments = "-f config.json" + PortableMode(),
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",
coreDownloadUrlLinux32 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-386-{0}.gz",
coreDownloadUrlLinux64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
coreDownloadUrlLinuxArm64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
match = "Mihomo",
versionArg = "-v",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.hysteria,
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
arguments = "",
coreUrl = Global.HysteriaCoreUrl,
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.naiveproxy,
coreExes = new List<string> { "naiveproxy", "naive" },
arguments = "config.json",
coreUrl = Global.NaiveproxyCoreUrl,
redirectInfo = false,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.tuic,
coreExes = new List<string> { "tuic-client", "tuic" },
arguments = "-c config.json",
coreUrl = Global.TuicCoreUrl,
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.sing_box,
coreExes = new List<string> { "sing-box-client", "sing-box" },
arguments = "run {0} --disable-color",
coreUrl = Global.SingboxCoreUrl,
redirectInfo = true,
coreReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
coreDownloadUrl32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-386.zip",
coreDownloadUrl64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
coreDownloadUrlArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
coreDownloadUrlLinux32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-386.tar.gz",
coreDownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
coreDownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
match = "sing-box",
versionArg = "version",
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.juicity,
coreExes = new List<string> { "juicity-client", "juicity" },
arguments = "run -c config.json",
coreUrl = Global.JuicityCoreUrl
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.hysteria2,
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
arguments = "",
coreUrl = Global.HysteriaCoreUrl,
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
redirectInfo = true,
});
}
private string PortableMode()
{
return $" -d \"{Utils.GetBinPath("")}\"";
}
}
}

View File

@@ -1,18 +1,14 @@
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Sockets;
using v2rayN.Enums;
using v2rayN.Resx;
namespace v2rayN.Handler
namespace ServiceLib.Handler
{
/// <summary>
///Download
/// </summary>
internal class DownloadHandle
public class DownloadHandler
{
public event EventHandler<ResultEventArgs>? UpdateCompleted;
@@ -34,7 +30,7 @@ namespace v2rayN.Handler
{
try
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
var progress = new Progress<string>();
progress.ProgressChanged += (sender, value) =>
@@ -62,11 +58,11 @@ namespace v2rayN.Handler
return 0;
}
public async Task DownloadFileAsync(string url, bool blProxy, int downloadTimeout)
public async Task DownloadFileAsync(string url, string fileName, bool blProxy, int downloadTimeout)
{
try
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, $"{ResUI.Downloading} {url}"));
var progress = new Progress<double>();
@@ -78,7 +74,7 @@ namespace v2rayN.Handler
var webProxy = GetWebProxy(blProxy);
await DownloaderHelper.Instance.DownloadFileAsync(webProxy,
url,
Utils.GetTempPath(Utils.GetDownloadFileName(url)),
fileName,
progress,
downloadTimeout);
}
@@ -96,7 +92,7 @@ namespace v2rayN.Handler
public async Task<string?> UrlRedirectAsync(string url, bool blProxy)
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
var webRequestHandler = new SocketsHttpHandler
{
AllowAutoRedirect = false,
@@ -185,7 +181,7 @@ namespace v2rayN.Handler
{
try
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy);
var client = new HttpClient(new SocketsHttpHandler()
{
@@ -230,7 +226,7 @@ namespace v2rayN.Handler
{
try
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy);
@@ -264,7 +260,7 @@ namespace v2rayN.Handler
try
{
var config = LazyConfig.Instance.GetConfig();
var config = LazyConfig.Instance.Config;
int responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10);
return responseTime;
}
@@ -286,8 +282,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 +289,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

@@ -1,11 +1,8 @@
using System.Collections.Specialized;
using System.IO;
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class BaseFmt
public class BaseFmt
{
protected static string GetIpv6(string address)
{
@@ -59,6 +56,10 @@ namespace v2rayN.Handler.Fmt
{
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));
@@ -137,6 +138,7 @@ namespace v2rayN.Handler.Fmt
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)

View File

@@ -1,9 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class ClashFmt : BaseFmt
public class ClashFmt : BaseFmt
{
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{

View File

@@ -1,10 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class FmtHandler
public class FmtHandler
{
public static string? GetShareUri(ProfileItem item)
{

View File

@@ -1,10 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class Hysteria2Fmt : BaseFmt
public class Hysteria2Fmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{

View File

@@ -1,9 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class NaiveproxyFmt : BaseFmt
public class NaiveproxyFmt : BaseFmt
{
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{

View File

@@ -1,11 +1,8 @@
using System.Text.RegularExpressions;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class ShadowsocksFmt : BaseFmt
public class ShadowsocksFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{

View File

@@ -1,9 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class SingboxFmt : BaseFmt
public class SingboxFmt : BaseFmt
{
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
{

View File

@@ -1,10 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class SocksFmt : BaseFmt
public class SocksFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{

View File

@@ -1,10 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class TrojanFmt : BaseFmt
public class TrojanFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{

View File

@@ -1,10 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class TuicFmt : BaseFmt
public class TuicFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{

View File

@@ -1,9 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class V2rayFmt : BaseFmt
public class V2rayFmt : BaseFmt
{
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
{

View File

@@ -1,10 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class VLESSFmt : BaseFmt
public class VLESSFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{

View File

@@ -0,0 +1,122 @@
namespace ServiceLib.Handler.Fmt
{
public 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

@@ -1,10 +1,6 @@
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
internal class WireguardFmt : BaseFmt
public class WireguardFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{

View File

@@ -0,0 +1,242 @@
namespace ServiceLib.Handler
{
public sealed class LazyConfig
{
private static readonly Lazy<LazyConfig> _instance = new(() => new());
private Config _config;
private int? _statePort;
private int? _statePort2;
public static LazyConfig Instance => _instance.Value;
public Config Config => _config;
public int StatePort
{
get
{
_statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
return _statePort.Value;
}
}
public int StatePort2
{
get
{
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
return _statePort2.Value;
}
}
private Job? _processJob;
public LazyConfig()
{
SQLiteHelper.Instance.CreateTable<SubItem>();
SQLiteHelper.Instance.CreateTable<ProfileItem>();
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
SQLiteHelper.Instance.CreateTable<RoutingItem>();
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
SQLiteHelper.Instance.CreateTable<DNSItem>();
}
#region Config
public void SetConfig(Config config) => _config = config;
public int GetLocalPort(EInboundProtocol protocol)
{
var localPort = _config.inbound.FirstOrDefault(t => t.protocol == nameof(EInboundProtocol.socks))?.localPort ?? 10808;
return localPort + (int)protocol;
}
public void AddProcess(IntPtr processHandle)
{
if (Utils.IsWindows())
{
_processJob ??= new();
_processJob?.AddProcess(processHandle);
}
}
#endregion Config
#region SqliteHelper
public List<SubItem> SubItems()
{
return SQLiteHelper.Instance.Table<SubItem>().ToList();
}
public SubItem GetSubItem(string subid)
{
return SQLiteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
}
public List<ProfileItem> ProfileItems(string subid)
{
if (Utils.IsNullOrEmpty(subid))
{
return SQLiteHelper.Instance.Table<ProfileItem>().ToList();
}
else
{
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
}
}
public List<string> ProfileItemIndexes(string subid)
{
if (Utils.IsNullOrEmpty(subid))
{
return SQLiteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
}
else
{
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
}
}
public List<ProfileItemModel> ProfileItems(string subid, string filter)
{
var sql = @$"select a.*
,b.remarks subRemarks
from ProfileItem a
left join SubItem b on a.subid = b.id
where 1=1 ";
if (!Utils.IsNullOrEmpty(subid))
{
sql += $" and a.subid = '{subid}'";
}
if (!Utils.IsNullOrEmpty(filter))
{
if (filter.Contains('\''))
{
filter = filter.Replace("'", "");
}
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
}
return SQLiteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
}
public List<ProfileItemModel> ProfileItemsEx(string subid, string filter)
{
var lstModel = ProfileItems(_config.subIndexId, filter);
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();
return lstModel;
}
public ProfileItem? GetProfileItem(string indexId)
{
if (Utils.IsNullOrEmpty(indexId))
{
return null;
}
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
}
public ProfileItem? GetProfileItemViaRemarks(string remarks)
{
if (Utils.IsNullOrEmpty(remarks))
{
return null;
}
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.remarks == remarks);
}
public List<RoutingItem> RoutingItems()
{
return SQLiteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
}
public RoutingItem GetRoutingItem(string id)
{
return SQLiteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
}
public List<DNSItem> DNSItems()
{
return SQLiteHelper.Instance.Table<DNSItem>().ToList();
}
public DNSItem GetDNSItem(ECoreType eCoreType)
{
return SQLiteHelper.Instance.Table<DNSItem>().FirstOrDefault(it => it.coreType == eCoreType);
}
#endregion SqliteHelper
#region Core Type
public List<string> GetShadowsocksSecurities(ProfileItem profileItem)
{
var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks);
switch (coreType)
{
case ECoreType.v2fly:
return Global.SsSecurities;
case ECoreType.Xray:
return Global.SsSecuritiesInXray;
case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox;
}
return Global.SsSecuritiesInSagerNet;
}
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
{
if (profileItem?.coreType != null)
{
return (ECoreType)profileItem.coreType;
}
if (_config.coreTypeItem == null)
{
return ECoreType.Xray;
}
var item = _config.coreTypeItem.FirstOrDefault(it => it.configType == eConfigType);
if (item == null)
{
return ECoreType.Xray;
}
return item.coreType;
}
#endregion Core Type
}
}

View File

@@ -0,0 +1,41 @@
using ReactiveUI;
namespace ServiceLib.Handler
{
public class NoticeHandler
{
public void Enqueue(string? content)
{
if (content.IsNullOrEmpty())
{
return;
}
MessageBus.Current.SendMessage(content, Global.CommandSendSnackMsg);
}
public void SendMessage(string? content)
{
if (content.IsNullOrEmpty())
{
return;
}
MessageBus.Current.SendMessage(content, Global.CommandSendMsgView);
}
public void SendMessage(string? content, bool time)
{
if (content.IsNullOrEmpty())
{
return;
}
content = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {content}";
SendMessage(content);
}
public void SendMessageAndEnqueue(string? msg)
{
Enqueue(msg);
SendMessage(msg);
}
}
}

View File

@@ -1,10 +1,10 @@
using System.Collections.Concurrent;
using System.Reactive.Linq;
using v2rayN.Models;
namespace v2rayN.Handler
//using System.Reactive.Linq;
namespace ServiceLib.Handler
{
internal class ProfileExHandler
public class ProfileExHandler
{
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];

View File

@@ -1,27 +1,19 @@
using ReactiveUI;
using System.Diagnostics;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler
namespace ServiceLib.Handler
{
internal class SpeedtestHandler
public class SpeedtestHandler
{
private Config? _config;
private CoreHandler _coreHandler;
private List<ServerTestItem> _selecteds;
private ESpeedActionType _actionType;
private Action<string, string, string> _updateFunc;
private Action<SpeedTestResult> _updateFunc;
private bool _exitLoop = false;
public SpeedtestHandler(Config config)
{
_config = config;
}
public SpeedtestHandler(Config config, CoreHandler coreHandler, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<string, string, string> update)
public SpeedtestHandler(Config config, CoreHandler coreHandler, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> update)
{
_config = config;
_coreHandler = coreHandler;
@@ -91,6 +83,12 @@ namespace v2rayN.Handler
}
}
public void ExitLoop()
{
_exitLoop = true;
UpdateFunc("", ResUI.SpeedtestingStop);
}
private Task RunTcping()
{
try
@@ -146,7 +144,7 @@ namespace v2rayN.Handler
return Task.CompletedTask;
}
DownloadHandle downloadHandle = new DownloadHandle();
DownloadHandler downloadHandle = new DownloadHandler();
List<Task> tasks = new();
foreach (var it in _selecteds)
@@ -213,22 +211,11 @@ namespace v2rayN.Handler
string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new();
var exitLoop = false;
MessageBus.Current.Listen<string>(Global.CommandStopSpeedTest)
.Subscribe(x =>
{
if (!exitLoop)
{
UpdateFunc("", ResUI.SpeedtestingStop);
}
exitLoop = true;
});
DownloadHandler downloadHandle = new();
foreach (var it in _selecteds)
{
if (exitLoop)
if (_exitLoop)
{
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
continue;
@@ -286,22 +273,11 @@ namespace v2rayN.Handler
string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new();
var exitLoop = false;
MessageBus.Current.Listen<string>(Global.CommandStopSpeedTest)
.Subscribe(x =>
{
if (!exitLoop)
{
UpdateFunc("", ResUI.SpeedtestingStop);
}
exitLoop = true;
});
DownloadHandler downloadHandle = new();
foreach (var it in _selecteds)
{
if (exitLoop)
if (_exitLoop)
{
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
continue;
@@ -358,7 +334,7 @@ namespace v2rayN.Handler
await RunSpeedTestMulti();
}
private async Task<string> GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy)
private async Task<string> GetRealPingTime(DownloadHandler downloadHandle, IWebProxy webProxy)
{
int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10);
//string output = Utile.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
@@ -377,19 +353,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)
{
@@ -409,7 +384,7 @@ namespace v2rayN.Handler
private void UpdateFunc(string indexId, string delay, string speed = "")
{
_updateFunc(indexId, delay, speed);
_updateFunc(new() { IndexId = indexId, Delay = delay, Speed = speed });
}
}
}

View File

@@ -1,9 +1,10 @@
using v2rayN.Models;
namespace ServiceLib.Handler.Statistics
{
public class StatisticsHandler
{
private static readonly Lazy<StatisticsHandler> instance = new(() => new());
public static StatisticsHandler Instance => instance.Value;
namespace v2rayN.Handler
{
internal class StatisticsHandler
{
private Config _config;
private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat;
@@ -12,20 +13,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);
@@ -54,16 +52,19 @@ namespace v2rayN.Handler
public void SaveTo()
{
try
{
if (_lstServerStat != null)
{
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
private void Init()
private void InitData()
{
SQLiteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");

View File

@@ -1,11 +1,9 @@
using System.Net.WebSockets;
using System.Text;
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler
namespace ServiceLib.Handler.Statistics
{
internal class StatisticsSingbox
public class StatisticsSingbox
{
private Config _config;
private bool _exitFlag;
@@ -65,7 +63,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,12 +1,10 @@
using Grpc.Core;
using Grpc.Net.Client;
using ProtosLib.Statistics;
using v2rayN.Enums;
using v2rayN.Models;
namespace v2rayN.Handler
namespace ServiceLib.Handler.Statistics
{
internal class StatisticsV2ray
public class StatisticsV2ray
{
private Models.Config _config;
private GrpcChannel? _channel;
@@ -53,7 +51,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;
}

View File

@@ -0,0 +1,76 @@
namespace ServiceLib.Handler
{
public class TaskHandler
{
private static readonly Lazy<TaskHandler> _instance = new(() => new());
public static TaskHandler Instance => _instance.Value;
public TaskHandler()
{
}
public void RegUpdateTask(Config config, Action<bool, string> update)
{
Task.Run(() => UpdateTaskRunSubscription(config, update));
Task.Run(() => UpdateTaskRunGeo(config, update));
}
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
{
await Task.Delay(60000);
Logging.SaveLog("UpdateTaskRunSubscription");
var updateHandle = new UpdateHandler();
while (true)
{
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
var lstSubs = LazyConfig.Instance.SubItems()
.Where(t => t.autoUpdateInterval > 0)
.Where(t => updateTime - t.updateTime >= t.autoUpdateInterval * 60)
.ToList();
foreach (var item in lstSubs)
{
updateHandle.UpdateSubscriptionProcess(config, item.id, true, (bool success, string msg) =>
{
update(success, msg);
if (success)
Logging.SaveLog("subscription" + msg);
});
item.updateTime = updateTime;
ConfigHandler.AddSubItem(config, item);
await Task.Delay(5000);
}
await Task.Delay(60000);
}
}
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> update)
{
var autoUpdateGeoTime = DateTime.Now;
await Task.Delay(1000 * 120);
Logging.SaveLog("UpdateTaskRunGeo");
var updateHandle = new UpdateHandler();
while (true)
{
var dtNow = DateTime.Now;
if (config.guiItem.autoUpdateInterval > 0)
{
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
{
updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
update(false, msg);
});
autoUpdateGeoTime = dtNow;
}
}
await Task.Delay(1000 * 3600);
}
}
}
}

View File

@@ -1,25 +1,17 @@
using DynamicData;
using Splat;
using System.Diagnostics;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler
namespace ServiceLib.Handler
{
internal class UpdateHandle
public class UpdateHandler
{
private Action<bool, string> _updateFunc;
private Config _config;
private int _timeout = 30;
public event EventHandler<ResultEventArgs> AbsoluteCompleted;
public class ResultEventArgs : EventArgs
private class ResultEventArgs
{
public bool Success;
public string Msg;
@@ -33,37 +25,66 @@ namespace v2rayN.Handler
}
}
public void CheckUpdateGuiN(Config config, Action<bool, string> update, bool preRelease)
public async Task CheckUpdateGuiN(Config config, Action<bool, string> update, bool preRelease)
{
_config = config;
_updateFunc = update;
var url = string.Empty;
var fileName = string.Empty;
DownloadHandle downloadHandle = new();
DownloadHandler downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{
if (args.Success)
{
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(true, Utils.UrlEncode(fileName));
}
else
{
_updateFunc(false, args.Msg);
}
};
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(false, args.GetException().Message);
};
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, ECoreType.v2rayN));
var args = await CheckUpdateAsync(downloadHandle, ECoreType.v2rayN, preRelease);
if (args.Success)
{
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, ECoreType.v2rayN));
_updateFunc(false, args.Msg);
url = args.Url;
fileName = Utils.GetTempPath(Utils.GetGUID());
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
}
else
{
_updateFunc(false, args.Msg);
}
}
public async Task CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease)
{
_config = config;
_updateFunc = update;
var url = string.Empty;
var fileName = string.Empty;
DownloadHandler downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{
if (args.Success)
{
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(false, ResUI.MsgUnpacking);
try
{
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
fileName = Utils.UrlEncode(fileName);
Process process = new()
{
StartInfo = new ProcessStartInfo
{
FileName = "v2rayUpgrade.exe",
Arguments = fileName.AppendQuotes(),
WorkingDirectory = Utils.StartupPath()
}
};
process.Start();
if (process.Id > 0)
{
_updateFunc(true, "");
}
_updateFunc(true, fileName);
}
catch (Exception ex)
{
@@ -79,83 +100,25 @@ namespace v2rayN.Handler
{
_updateFunc(false, args.GetException().Message);
};
AbsoluteCompleted += (sender2, args) =>
{
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, type));
var args = await CheckUpdateAsync(downloadHandle, type, preRelease);
if (args.Success)
{
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "v2rayN"));
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, type));
_updateFunc(false, args.Msg);
url = args.Url;
AskToDownload(downloadHandle, url, true).ContinueWith(task =>
{
_updateFunc(false, url);
});
fileName = Utils.GetTempPath(Utils.GetGUID());
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
}
else
{
Locator.Current.GetService<NoticeHandler>()?.Enqueue(args.Msg);
_updateFunc(false, args.Msg);
}
};
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, "v2rayN"));
CheckUpdateAsync(ECoreType.v2rayN, preRelease);
}
public void CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease)
{
_config = config;
_updateFunc = update;
var url = string.Empty;
DownloadHandle downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{
if (args.Success)
{
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(false, ResUI.MsgUnpacking);
try
{
_updateFunc(true, url);
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
}
}
else
if (!args.Msg.IsNullOrEmpty())
{
_updateFunc(false, args.Msg);
}
};
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(true, args.GetException().Message);
};
AbsoluteCompleted += (sender2, args) =>
{
if (args.Success)
{
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "Core"));
_updateFunc(false, args.Msg);
url = args.Url;
AskToDownload(downloadHandle, url, true).ContinueWith(task =>
{
_updateFunc(false, url);
});
}
else
{
Locator.Current.GetService<NoticeHandler>()?.Enqueue(args.Msg);
_updateFunc(false, args.Msg);
}
};
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, "Core"));
CheckUpdateAsync(type, preRelease);
}
public void UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> update)
@@ -195,7 +158,7 @@ namespace v2rayN.Handler
continue;
}
var downloadHandle = new DownloadHandle();
var downloadHandle = new DownloadHandler();
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(false, $"{hashCode}{args.GetException().Message}");
@@ -233,10 +196,7 @@ namespace v2rayN.Handler
result = Utils.Base64Decode(result);
}
var lstUrl = new List<string>
{
item.moreUrl.TrimEx().Split(",")
};
var lstUrl = item.moreUrl.TrimEx().Split(",") ?? [];
foreach (var it in lstUrl)
{
var url2 = Utils.GetPunycode(it);
@@ -294,20 +254,18 @@ namespace v2rayN.Handler
});
}
public void UpdateGeoFileAll(Config config, Action<bool, string> update)
{
Task.Run(async () =>
public async Task UpdateGeoFileAll(Config config, Action<bool, string> update)
{
await UpdateGeoFile("geosite", _config, update);
await UpdateGeoFile("geoip", _config, update);
});
_updateFunc(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
}
public void RunAvailabilityCheck(Action<bool, string> update)
{
Task.Run(async () =>
{
var time = await (new DownloadHandle()).RunAvailabilityCheck(null);
var time = await (new DownloadHandler()).RunAvailabilityCheck(null);
update(false, string.Format(ResUI.TestMeOutput, time));
});
@@ -315,43 +273,43 @@ namespace v2rayN.Handler
#region private
private async void CheckUpdateAsync(ECoreType type, bool preRelease)
private async Task<ResultEventArgs> CheckUpdateAsync(DownloadHandler downloadHandle, ECoreType type, bool preRelease)
{
try
{
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
string url = coreInfo.coreReleaseApiUrl;
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
var url = coreInfo?.coreReleaseApiUrl;
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
var result = await downloadHandle.DownloadStringAsync(url, true, Global.AppName);
if (!Utils.IsNullOrEmpty(result))
{
ResponseHandler(type, result, preRelease);
return await ParseDownloadUrl(type, result, preRelease);
}
else
{
Logging.SaveLog("StatusCode error: " + url);
return;
return new ResultEventArgs(false, "");
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
_updateFunc(false, ex.Message);
return new ResultEventArgs(false, ex.Message);
}
}
/// <summary>
/// 获取V2RayCore版本
/// 获取Core版本
/// </summary>
private SemanticVersion GetCoreVersion(ECoreType type)
{
try
{
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
string filePath = string.Empty;
foreach (string name in coreInfo.coreExes)
{
string vName = $"{name}.exe";
string vName = Utils.GetExeName(name);
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
if (File.Exists(vName))
{
@@ -408,7 +366,7 @@ namespace v2rayN.Handler
}
}
private void ResponseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
private async Task<ResultEventArgs> ParseDownloadUrl(ECoreType type, string gitHubReleaseApi, bool preRelease)
{
try
{
@@ -417,11 +375,10 @@ namespace v2rayN.Handler
var version = new SemanticVersion(gitHubRelease?.TagName!);
var body = gitHubRelease?.Body;
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
SemanticVersion curVersion;
string message;
string url;
string? url;
switch (type)
{
case ECoreType.v2fly:
@@ -431,23 +388,7 @@ namespace v2rayN.Handler
{
curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
string osBit = "64";
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm64:
osBit = "arm64-v8a";
break;
case Architecture.X86:
osBit = "32";
break;
default:
osBit = "64";
break;
}
url = string.Format(coreInfo.coreDownloadUrl64, version.ToVersionString("v"), osBit);
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"));
break;
}
case ECoreType.clash:
@@ -456,62 +397,21 @@ namespace v2rayN.Handler
{
curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion);
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm64:
url = coreInfo.coreDownloadUrlArm64;
break;
case Architecture.X86:
url = coreInfo.coreDownloadUrl32;
break;
default:
url = coreInfo.coreDownloadUrl64;
break;
}
url = string.Format(url, version.ToVersionString("v"));
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"));
break;
}
case ECoreType.sing_box:
{
curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm64:
url = coreInfo.coreDownloadUrlArm64;
break;
case Architecture.X86:
url = coreInfo.coreDownloadUrl32;
break;
default:
url = coreInfo.coreDownloadUrl64;
break;
}
url = string.Format(url, version.ToVersionString("v"), version);
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"), version);
break;
}
case ECoreType.v2rayN:
{
curVersion = new SemanticVersion(FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString());
curVersion = new SemanticVersion(Utils.GetVersionInfo());
message = string.Format(ResUI.IsLatestN, type, curVersion);
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm64:
url = string.Format(coreInfo.coreDownloadUrlArm64, version);
break;
case Architecture.X86:
url = string.Format(coreInfo.coreDownloadUrl32, version);
break;
default:
url = string.Format(coreInfo.coreDownloadUrl64, version);
break;
}
url = string.Format(GetUrlFromCore(coreInfo), version);
break;
}
default:
@@ -520,37 +420,42 @@ namespace v2rayN.Handler
if (curVersion >= version && version != new SemanticVersion(0, 0, 0))
{
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
return;
return new ResultEventArgs(false, message);
}
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(true, body, url));
return new ResultEventArgs(true, body, url);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
_updateFunc(false, ex.Message);
return new ResultEventArgs(false, ex.Message);
}
}
private async Task AskToDownload(DownloadHandle downloadHandle, string url, bool blAsk)
private string? GetUrlFromCore(CoreInfo? coreInfo)
{
bool blDownload = false;
if (blAsk)
if (Utils.IsWindows())
{
if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes)
return RuntimeInformation.ProcessArchitecture switch
{
blDownload = true;
Architecture.Arm64 => coreInfo?.coreDownloadUrlArm64,
Architecture.X86 => coreInfo?.coreDownloadUrl32,
Architecture.X64 => coreInfo?.coreDownloadUrl64,
_ => null,
};
}
}
else
else if (Utils.IsLinux())
{
blDownload = true;
}
if (blDownload)
return RuntimeInformation.ProcessArchitecture switch
{
await downloadHandle.DownloadFileAsync(url, true, 600);
Architecture.Arm64 => coreInfo?.coreDownloadUrlLinuxArm64,
Architecture.X86 => coreInfo?.coreDownloadUrlLinux32,
Architecture.X64 => coreInfo?.coreDownloadUrlLinux64,
_ => null,
};
}
return null;
}
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> update)
@@ -558,8 +463,9 @@ namespace v2rayN.Handler
_config = config;
_updateFunc = update;
var url = string.Format(Global.GeoUrl, geoName);
var fileName = Utils.GetTempPath(Utils.GetGUID());
DownloadHandle downloadHandle = new();
DownloadHandler downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{
if (args.Success)
@@ -568,14 +474,8 @@ namespace v2rayN.Handler
try
{
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
if (File.Exists(fileName))
{
//Global.coreTypes.ForEach(it =>
//{
// string targetPath = Utile.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
// File.Copy(fileName, targetPath, true);
//});
string targetPath = Utils.GetBinPath($"{geoName}.dat");
File.Copy(fileName, targetPath, true);
@@ -597,7 +497,8 @@ namespace v2rayN.Handler
{
_updateFunc(false, args.GetException().Message);
};
await AskToDownload(downloadHandle, url, false);
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
}
#endregion private

View File

@@ -0,0 +1,11 @@
namespace ServiceLib.Models
{
public class CheckUpdateItem
{
public bool? isSelected { get; set; }
public string coreType { get; set; }
public string? remarks { get; set; }
public string? fileName { get; set; }
public bool? isFinished { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
namespace ServiceLib.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 ServiceLib.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 ServiceLib.Models.ClashProxies;
namespace ServiceLib.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 ServiceLib.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,18 @@
namespace ServiceLib.Models
{
[Serializable]
public class ClashProxyModel
{
public string name { get; set; }
public string type { get; set; }
public string now { get; set; }
public int delay { get; set; }
public string delayName { get; set; }
public bool isActive { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
public class ComboItem
{

View File

@@ -1,6 +1,4 @@
using v2rayN.Enums;
namespace v2rayN.Models
namespace ServiceLib.Models
{
/// <summary>
/// 本软件配置文件实体类
@@ -12,12 +10,24 @@ namespace v2rayN.Models
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
@@ -28,11 +38,15 @@ namespace v2rayN.Models
public GrpcItem grpcItem { get; set; }
public RoutingBasicItem routingBasicItem { get; set; }
public GUIItem guiItem { get; set; }
public MsgUIItem msgUIItem { get; set; }
public UIItem uiItem { get; set; }
public ConstItem constItem { get; set; }
public SpeedTestItem speedTestItem { get; set; }
public Mux4RayItem mux4RayItem { 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,7 +1,4 @@
using System.Windows.Input;
using v2rayN.Enums;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class CoreBasicItem
@@ -110,6 +107,13 @@ namespace v2rayN.Models
public bool enableLog { get; set; } = true;
}
[Serializable]
public class MsgUIItem
{
public string? mainMsgFilter { get; set; }
public bool? autoRefresh { get; set; }
}
[Serializable]
public class UIItem
{
@@ -119,6 +123,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; }
@@ -128,8 +133,8 @@ namespace v2rayN.Models
public bool enableDragDropSort { get; set; }
public bool doubleClick2Activate { get; set; }
public bool autoHideStartup { get; set; }
public string mainMsgFilter { get; set; }
public List<ColumnItem> mainColumnItem { get; set; }
public bool showInTaskbar { get; set; }
}
[Serializable]
@@ -150,7 +155,7 @@ namespace v2rayN.Models
public bool Shift { get; set; }
public Key? KeyCode { get; set; }
public int? KeyCode { get; set; }
}
[Serializable]
@@ -169,7 +174,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]
@@ -198,11 +203,20 @@ namespace v2rayN.Models
public int Index { get; set; }
}
[Serializable]
public class Mux4RayItem
{
public int? concurrency { get; set; }
public int? xudpConcurrency { get; set; }
public string? xudpProxyUDP443 { get; set; }
}
[Serializable]
public class Mux4SboxItem
{
public string protocol { get; set; }
public int max_connections { get; set; }
public bool? padding { get; set; }
}
[Serializable]
@@ -211,4 +225,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,6 +1,4 @@
using v2rayN.Enums;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class CoreInfo
@@ -20,6 +18,9 @@ namespace v2rayN.Models
public string coreDownloadUrl64 { get; set; }
public string coreDownloadUrlArm64 { get; set; }
public string? coreDownloadUrlLinux32 { get; set; }
public string? coreDownloadUrlLinux64 { get; set; }
public string? coreDownloadUrlLinuxArm64 { get; set; }
public string match { get; set; }
public string versionArg { get; set; }

View File

@@ -1,7 +1,6 @@
using SQLite;
using v2rayN.Enums;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class DNSItem
@@ -16,5 +15,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,6 +1,6 @@
using System.Text.Json.Serialization;
namespace v2rayN.Models
namespace ServiceLib.Models
{
public class GitHubReleaseAsset
{

View File

@@ -1,6 +1,6 @@
using SQLite;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class ProfileExItem

View File

@@ -1,7 +1,6 @@
using SQLite;
using v2rayN.Enums;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class ProfileItem
@@ -49,7 +48,7 @@ namespace v2rayN.Models
switch (configType)
{
case EConfigType.Custom:
summary += string.Format("{0}", remarks);
summary += string.Format("[{1}]{0}", remarks, coreType.ToString());
break;
default:
@@ -179,7 +178,7 @@ namespace v2rayN.Models
public ECoreType? coreType { get; set; }
public int preSocksPort { get; set; }
public int? preSocksPort { get; set; }
public string fingerprint { get; set; }

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class ProfileItemModel : ProfileItem

View File

@@ -1,6 +1,6 @@
using SQLite;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class RoutingItem

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class RoutingItemModel : RoutingItem

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class RulesItem

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class RulesItemModel : RulesItem

View File

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

View File

@@ -1,6 +1,6 @@
using SQLite;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class ServerStatItem

View File

@@ -1,9 +1,7 @@
using v2rayN.Enums;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
internal class ServerTestItem
public class ServerTestItem
{
public string indexId { get; set; }
public string address { get; set; }

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
public class SingboxConfig
{
@@ -49,6 +49,8 @@
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 List<string>? network { get; set; }
@@ -129,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
@@ -146,6 +150,7 @@
public bool enabled { get; set; }
public string protocol { get; set; }
public int max_connections { get; set; }
public bool? padding { get; set; }
}
public class Utls4Sbox

View File

@@ -0,0 +1,12 @@
namespace ServiceLib.Models
{
[Serializable]
public class SpeedTestResult
{
public string? IndexId { get; set; }
public string? Delay { get; set; }
public string? Speed { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
public class SsSIP008
{

View File

@@ -1,6 +1,6 @@
using SQLite;
namespace v2rayN.Models
namespace ServiceLib.Models
{
[Serializable]
public class SubItem
@@ -31,5 +31,7 @@ namespace v2rayN.Models
public string? prevProfile { get; set; }
public string? nextProfile { get; set; }
public int? preSocksPort { get; set; }
}
}

View File

@@ -1,6 +1,6 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
internal class SysProxyConfig
public class SysProxyConfig
{
public bool UserSettingsRecorded;
public string Flags;

View File

@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
namespace v2rayN.Models
namespace ServiceLib.Models
{
/// <summary>
/// v2ray配置文件实体类 例子SampleConfig.txt
@@ -343,15 +343,10 @@ namespace v2rayN.Models
public class Mux4Ray
{
/// <summary>
///
/// </summary>
public bool enabled { get; set; }
/// <summary>
///
/// </summary>
public int concurrency { get; set; }
public int? concurrency { get; set; }
public int? xudpConcurrency { get; set; }
public string? xudpProxyUDP443 { get; set; }
}
public class Response4Ray
@@ -370,6 +365,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>
@@ -380,12 +381,14 @@ 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]
@@ -400,6 +403,8 @@ namespace v2rayN.Models
public string? outboundTag { get; set; }
public string? balancerTag { get; set; }
public List<string>? ip { get; set; }
public List<string>? domain { get; set; }
@@ -407,6 +412,18 @@ namespace v2rayN.Models
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
{
/// <summary>

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Models
namespace ServiceLib.Models
{
/// <summary>
/// Tcp伪装http的Request只要Host

View File

@@ -1,12 +1,12 @@
using System.Text.Json.Serialization;
namespace v2rayN.Models
namespace ServiceLib.Models
{
/// <summary>
/// https://github.com/2dust/v2rayN/wiki/
/// </summary>
[Serializable]
internal class VmessQRCode
public class VmessQRCode
{
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public int v { get; set; } = 2;

View File

@@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace v2rayN.Resx {
namespace ServiceLib.Resx {
using System;
@@ -39,7 +39,7 @@ namespace v2rayN.Resx {
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("v2rayN.Resx.ResUI", typeof(ResUI).Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ServiceLib.Resx.ResUI", typeof(ResUI).Assembly);
resourceMan = temp;
}
return resourceMan;
@@ -79,16 +79,7 @@ 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 的本地化字符串。
/// 查找类似 Export Share Link to Clipboard Successfully 的本地化字符串。
/// </summary>
public static string BatchExportURLSuccessfully {
get {
@@ -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>
@@ -421,7 +385,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Enabled Update 的本地化字符串。
/// 查找类似 Enable update 的本地化字符串。
/// </summary>
public static string LvEnabled {
get {
@@ -448,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 {
@@ -646,7 +610,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Import bulk URL from clipboard (Ctrl+V) 的本地化字符串。
/// 查找类似 Importing Share Links from clipboard (Ctrl+V) 的本地化字符串。
/// </summary>
public static string menuAddServerViaClipboard {
get {
@@ -753,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>
@@ -790,7 +772,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Export selected server for client configuration 的本地化字符串。
/// 查找类似 Export selected server for complete configuration 的本地化字符串。
/// </summary>
public static string menuExport2ClientConfig {
get {
@@ -799,7 +781,16 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Export share URLs to clipboard (Ctrl+C) 的本地化字符串。
/// 查找类似 Export selected server for complete configuration to clipboard 的本地化字符串。
/// </summary>
public static string menuExport2ClientConfigClipboard {
get {
return ResourceManager.GetString("menuExport2ClientConfigClipboard", resourceCulture);
}
}
/// <summary>
/// 查找类似 Export Share Link to Clipboard (Ctrl+C) 的本地化字符串。
/// </summary>
public static string menuExport2ShareUrl {
get {
@@ -808,11 +799,11 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Export subscription (base64) share to clipboard 的本地化字符串。
/// 查找类似 Export Base64-encoded Share Links to Clipboard 的本地化字符串。
/// </summary>
public static string menuExport2SubContent {
public static string menuExport2ShareUrlBase64 {
get {
return ResourceManager.GetString("menuExport2SubContent", resourceCulture);
return ResourceManager.GetString("menuExport2ShareUrlBase64", resourceCulture);
}
}
@@ -879,6 +870,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>
@@ -960,15 +987,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>
@@ -996,6 +1014,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Auto column width adjustment 的本地化字符串。
/// </summary>
public static string menuProfileAutofitColumnWidth {
get {
return ResourceManager.GetString("menuProfileAutofitColumnWidth", resourceCulture);
}
}
/// <summary>
/// 查找类似 Promotion 的本地化字符串。
/// </summary>
@@ -1005,6 +1032,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>
@@ -1176,6 +1239,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Rule mode 的本地化字符串。
/// </summary>
public static string menuRulemode {
get {
return ResourceManager.GetString("menuRulemode", resourceCulture);
}
}
/// <summary>
/// 查找类似 Remove Rule (Delete) 的本地化字符串。
/// </summary>
@@ -1203,6 +1275,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>
@@ -1230,6 +1320,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Show or hide the main window 的本地化字符串。
/// </summary>
public static string menuShowOrHideMainWindow {
get {
return ResourceManager.GetString("menuShowOrHideMainWindow", resourceCulture);
}
}
/// <summary>
/// 查找类似 Sort by test result 的本地化字符串。
/// </summary>
@@ -1294,7 +1393,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Subscription group 的本地化字符串。
/// 查找类似 Subscription Group 的本地化字符串。
/// </summary>
public static string menuSubscription {
get {
@@ -1321,7 +1420,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Update subscription without proxy 的本地化字符串。
/// 查找类似 Update subscriptions without proxy 的本地化字符串。
/// </summary>
public static string menuSubUpdate {
get {
@@ -1330,7 +1429,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Update subscription with proxy 的本地化字符串。
/// 查找类似 Update subscriptions with proxy 的本地化字符串。
/// </summary>
public static string menuSubUpdateViaProxy {
get {
@@ -1392,15 +1491,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Test current service status 的本地化字符串。
/// </summary>
public static string menuTestMe {
get {
return ResourceManager.GetString("menuTestMe", resourceCulture);
}
}
/// <summary>
/// 查找类似 {0} Website 的本地化字符串。
/// </summary>
@@ -1555,7 +1645,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Update subscription end 的本地化字符串。
/// 查找类似 Update subscriptions end 的本地化字符串。
/// </summary>
public static string MsgUpdateSubscriptionEnd {
get {
@@ -1564,7 +1654,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Update subscription starts 的本地化字符串。
/// 查找类似 Update subscriptions start 的本地化字符串。
/// </summary>
public static string MsgUpdateSubscriptionStart {
get {
@@ -1608,15 +1698,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>
@@ -1843,7 +1924,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Group please leave blank here 的本地化字符串。
/// 查找类似 For group please leave blank here 的本地化字符串。
/// </summary>
public static string SubUrlTips {
get {
@@ -1880,7 +1961,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Scan import URL successfully 的本地化字符串。
/// 查找类似 Scan import the shared link successfully 的本地化字符串。
/// </summary>
public static string SuccessfullyImportedServerViaScan {
get {
@@ -1888,15 +1969,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 System proxy 的本地化字符串。
/// </summary>
public static string SystemProxy {
get {
return ResourceManager.GetString("SystemProxy", resourceCulture);
}
}
/// <summary>
/// 查找类似 Address 的本地化字符串。
/// </summary>
@@ -1996,6 +2068,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Connections 的本地化字符串。
/// </summary>
public static string TbConnections {
get {
return ResourceManager.GetString("TbConnections", resourceCulture);
}
}
/// <summary>
/// 查找类似 Core Type 的本地化字符串。
/// </summary>
@@ -2249,7 +2330,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 txtPreSocksPort 的本地化字符串。
/// 查找类似 Socks port 的本地化字符串。
/// </summary>
public static string TbPreSocksPort {
get {
@@ -2257,6 +2338,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Custom config socks port 的本地化字符串。
/// </summary>
public static string TbPreSocksPort4Sub {
get {
return ResourceManager.GetString("TbPreSocksPort4Sub", resourceCulture);
}
}
/// <summary>
/// 查找类似 PrivateKey 的本地化字符串。
/// </summary>
@@ -2266,6 +2356,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Proxies 的本地化字符串。
/// </summary>
public static string TbProxies {
get {
return ResourceManager.GetString("TbProxies", resourceCulture);
}
}
/// <summary>
/// 查找类似 PublicKey 的本地化字符串。
/// </summary>
@@ -2608,6 +2707,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Outbound DNS address 的本地化字符串。
/// </summary>
public static string TbSettingsDomainDNSAddress {
get {
return ResourceManager.GetString("TbSettingsDomainDNSAddress", resourceCulture);
}
}
/// <summary>
/// 查找类似 Outbound Freedom domainStrategy 的本地化字符串。
/// </summary>
@@ -2617,6 +2725,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>
@@ -2824,6 +2941,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>
@@ -2860,6 +2986,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>
@@ -2915,7 +3050,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 {
@@ -3022,78 +3157,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>
@@ -3139,6 +3202,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>
@@ -3220,15 +3400,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>
@@ -3363,5 +3534,14 @@ namespace v2rayN.Resx {
return ResourceManager.GetString("UngroupedServers", resourceCulture);
}
}
/// <summary>
/// 查找类似 You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it! 的本地化字符串。
/// </summary>
public static string UpdateStandalonePackageTip {
get {
return ResourceManager.GetString("UpdateStandalonePackageTip", resourceCulture);
}
}
}
}

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>
@@ -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>
@@ -1006,4 +970,67 @@
<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,11 +117,8 @@
<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>
<value>Export Share Link to Clipboard Successfully</value>
</data>
<data name="CheckServerSettings" xml:space="preserve">
<value>Please check the server settings first</value>
@@ -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>
@@ -314,7 +299,7 @@
<value>{0} servers have been imported from clipboard</value>
</data>
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
<value>Scan import URL successfully</value>
<value>Scan import the shared link successfully</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>The ping of current service: {0} ms</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>
@@ -512,7 +491,7 @@
<value>Language (Restart)</value>
</data>
<data name="menuAddServerViaClipboard" xml:space="preserve">
<value>Import bulk URL from clipboard (Ctrl+V)</value>
<value>Importing Share Links from clipboard (Ctrl+V)</value>
</data>
<data name="menuAddServerViaScan" xml:space="preserve">
<value>Scan QR code on the screen (Ctrl+S)</value>
@@ -544,17 +523,11 @@
<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>
<value>Export selected server for complete 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>
<value>Export Share Link to Clipboard (Ctrl+C)</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>Add a custom configuration server</value>
@@ -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>
@@ -698,7 +668,7 @@
<value>Encryption</value>
</data>
<data name="TbPreSocksPort" xml:space="preserve">
<value>txtPreSocksPort</value>
<value>Socks port</value>
</data>
<data name="TipPreSocksPort" xml:space="preserve">
<value>* After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display</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,7 +1040,7 @@
<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>
@@ -1219,4 +1168,115 @@
<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>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>Export Base64-encoded Share Links to Clipboard</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>Export selected server for complete configuration to clipboard</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Custom config socks port</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>
@@ -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,11 +117,8 @@
<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>
<value>导出分享链接至剪贴板成功</value>
</data>
<data name="CheckServerSettings" xml:space="preserve">
<value>请先检查服务器设置</value>
@@ -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>
@@ -314,7 +299,7 @@
<value>成功从剪贴板导入 {0} 个服务器</value>
</data>
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
<value>扫描导入URL成功</value>
<value>扫描导入分享链接成功</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>当前服务的真连接延迟: {0} ms</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>
@@ -512,7 +491,7 @@
<value>语言(重启)</value>
</data>
<data name="menuAddServerViaClipboard" xml:space="preserve">
<value>从剪贴板导入批量URL (Ctrl+V)</value>
<value>从剪贴板导入分享链接 (Ctrl+V)</value>
</data>
<data name="menuAddServerViaScan" xml:space="preserve">
<value>扫描屏幕上的二维码 (Ctrl+S)</value>
@@ -544,17 +523,11 @@
<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>
<value>导出所选服务器完整配置</value>
</data>
<data name="menuExport2ShareUrl" xml:space="preserve">
<value>批量导出分享URL至剪贴板(多选) (Ctrl+C)</value>
</data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>批量导出订阅内容至剪贴板(多选)</value>
<value>导出分享链接至剪贴板(多选) (Ctrl+C)</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>添加自定义配置服务器</value>
@@ -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>
@@ -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>
@@ -1216,4 +1165,115 @@
<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>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>导出分享链接至剪贴板(多选) Base64编码</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>导出所选服务器完整配置至剪贴板</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>显示或隐藏主界面</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自定义配置的Socks端口</value>
</data>
</root>

View File

@@ -117,11 +117,8 @@
<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>
<value>匯出分享链接至剪貼簿成功</value>
</data>
<data name="CheckServerSettings" xml:space="preserve">
<value>請先檢查伺服器設定</value>
@@ -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>
@@ -313,7 +298,7 @@
<value>成功從剪貼簿匯入 {0} 個伺服器</value>
</data>
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
<value>掃描匯入URL成功</value>
<value>掃描匯入分享链接成功</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>目前服務的真連接延遲: {0} ms</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>
@@ -511,7 +490,7 @@
<value>語言(重啟)</value>
</data>
<data name="menuAddServerViaClipboard" xml:space="preserve">
<value>從剪貼簿匯入批次URL (Ctrl+V)</value>
<value>從剪貼簿導入分享鏈接 (Ctrl+V)</value>
</data>
<data name="menuAddServerViaScan" xml:space="preserve">
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
@@ -543,17 +522,11 @@
<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>
<value>匯出所選伺服器完整配置</value>
</data>
<data name="menuExport2ShareUrl" xml:space="preserve">
<value>批次匯出分享URL至剪貼簿(多選) (Ctrl+C)</value>
</data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>批次匯出訂閱內容至剪貼簿(多選)</value>
<value>匯出分享链接至剪貼簿(多選) (Ctrl+C)</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>新增自訂配置伺服器</value>
@@ -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>
@@ -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>
@@ -1189,4 +1138,22 @@
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>打開儲存所在的位置</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>自動調整列寬</value>
</data>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>匯出分享链接至剪貼簿(多選) Base64编码</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>匯出所選伺服器完整配置至剪貼簿</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>顯示或隱藏主介面</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自訂配置的Socks端口</value>
</data>
</root>

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