Compare commits

...

73 Commits
7.0.3 ... 7.1.3

Author SHA1 Message Date
2dust
22eb993ebf up 7.1.3 2024-11-18 16:51:51 +08:00
2dust
b5e1a297ae Optimize Linux start tun mode
You can choose not to store the password and enter it manually each time
2024-11-18 16:44:12 +08:00
2dust
499a16feae Fix LocalizationHelper for AmazTool 2024-11-18 10:13:49 +08:00
Slnanx
1866a59d12 更新程序内嵌资源文件 (#6101)
* fix

* fix

* 移除自述

* 改用单例模式,避免多次初始化。

* 小修正

* 修正

* 更正自述

* 应该完成了

* 内嵌资源

* Update LocalizationHelper.cs
2024-11-18 09:57:38 +08:00
2dust
10513e0f3b Fixed the problem that the statistics column would not be hidden 2024-11-18 09:56:13 +08:00
Slnanx
2e32de2fbb fix (#6099)
* fix

* fix

* 移除自述

* 改用单例模式,避免多次初始化。

* 小修正

* 修正

* 更正自述

* 应该完成了
2024-11-17 19:42:14 +08:00
2dust
30a838df77 Bug fix
https://github.com/2dust/v2rayN/issues/6092
2024-11-17 16:18:46 +08:00
2dust
7cf9b9f57e up 7.1.2 2024-11-17 14:15:37 +08:00
2dust
736d995d4c up PackageReference 2024-11-17 14:11:51 +08:00
2dust
e335b2c0d6 Fix with AppendQuotes 2024-11-17 14:11:17 +08:00
2dust
96ae5517f6 Improve core msg 2024-11-17 09:58:57 +08:00
Slnanx
fb4b8d923a 可以通过判断系统语言来显示对应语言 (#6083) 2024-11-17 09:42:40 +08:00
2dust
2ade705e51 Bug fix 2024-11-16 20:15:05 +08:00
NagisaEfi
e0086b4b79 Update ResUI.zh-Hant.resx (#6080) 2024-11-16 10:34:55 +08:00
2dust
8f6d443104 Hide to tray when closing the window
https://github.com/2dust/v2rayN/issues/6076
2024-11-15 19:50:37 +08:00
2dust
5dbce16895 up 7.1.1 2024-11-15 13:36:44 +08:00
2dust
1016dcb3d1 Improve PAC 2024-11-15 11:59:22 +08:00
2dust
ba5ad12e13 Linux password encryption storage 2024-11-15 09:42:49 +08:00
2dust
57f9c8158e up 7.1.0 2024-11-14 15:20:14 +08:00
2dust
b8a0293b52 Add xhttp extra for xray
https://github.com/XTLS/Xray-core/pull/4000
2024-11-14 14:37:03 +08:00
2dust
59b7daaef5 Improve UI 2024-11-14 14:25:58 +08:00
2dust
d781c768e9 Add xhttp mode for xray
https://github.com/XTLS/Xray-core/pull/3994
2024-11-14 09:48:43 +08:00
2dust
04efed2079 SplitHTTP is now XHTTP for xray 2024-11-13 19:48:44 +08:00
2dust
2de9e14c7d xray-core uses quic to add failure prompts and plans to remove quic 2024-11-13 19:00:35 +08:00
2dust
a849dec6c2 Remove SagerNet 2024-11-13 18:00:31 +08:00
2dust
28019dc511 Migrate xray traffic statistics to Metrics
https://xtls.github.io/config/metrics.html
2024-11-13 16:45:23 +08:00
2dust
9d638968a9 Use tun mode without running with sudo in linux 2024-11-13 16:22:56 +08:00
2dust
f921ff7d77 Update README.md 2024-11-13 16:00:01 +08:00
NagisaEfi
e3ea329795 Update ResUI.zh-Hant.resx (#6049) 2024-11-13 09:49:41 +08:00
TTG
87f1c129b6 Update DNS Routing (#6045)
* Update DNS Routing

* Removed outdated DNS IP
2024-11-12 09:42:10 +08:00
2dust
a1c8bc0e61 Improve the code 2024-11-11 16:56:08 +08:00
fonaix
61e9101851 添加:MacOS 打开存储所在位置功能 (#6038)
* 添加:MacOS 代理配置与清除

* 修复:点击表头排序时,超时服务器排在前面的问题

* 添加:MacOS 打开存储所在位置功能

* 修复:删除全部节点时,UI不更新的问题
2024-11-11 09:48:20 +08:00
2dust
a6289347cc Bug fix
https://github.com/2dust/v2rayN/issues/6037
2024-11-11 09:37:49 +08:00
2dust
9e84de8e76 Migrating the sing-box configuration to 1.10.0
https://sing-box.sagernet.org/migration/#tun-address-fields-are-merged
2024-11-10 17:30:03 +08:00
2dust
d04cc53152 Fill ResUI 2024-11-10 17:25:36 +08:00
2dust
1ff3c5fc07 Fix
https://github.com/2dust/v2rayN/issues/6032
2024-11-10 17:24:41 +08:00
2dust
3db047a12f Fix 2024-11-09 14:37:48 +08:00
TTG
bf4615f2f2 Update Configuration to Optimize (#6027)
* Remove geolocation-cn

* Segment and update DNS lists
2024-11-09 09:28:10 +08:00
2dust
798c7fad9a up 7.0.9 2024-11-08 20:44:28 +08:00
2dust
5797b37262 Bug fix
https://github.com/2dust/v2rayN/issues/6023
2024-11-08 20:41:07 +08:00
2dust
ce22f34cd6 up 7.0.8 2024-11-08 20:01:36 +08:00
2dust
4c49e52e26 Bug fix
https://github.com/2dust/v2rayN/issues/5963
2024-11-08 19:24:36 +08:00
2dust
47318b5d70 Improve the code for Desktop Exit 2024-11-08 11:11:06 +08:00
2dust
d12297909c Improve the code for WPF Global Window 2024-11-08 11:04:03 +08:00
fonaix
5fb4edae2d 添加:MacOS 代理配置与清除 (#6018)
* 添加:MacOS 代理配置与清除

* 修复:点击表头排序时,超时服务器排在前面的问题
2024-11-08 09:21:43 +08:00
DecorativeFamily
c4b490e46d [CodeFactor] Apply fixes (#6005)
Co-authored-by: codefactor-io <support@codefactor.io>
2024-11-07 14:46:27 +08:00
2dust
45febe3fff up 7.0.7
https://github.com/2dust/v2rayN/issues/5970
2024-11-06 15:00:45 +08:00
2dust
689a81a985 Built-in font for Desktop
https://github.com/2dust/v2rayN/issues/5970
2024-11-06 14:52:54 +08:00
2dust
28620b385a Update MsgView.xaml
https://github.com/2dust/v2rayN/issues/5997
2024-11-05 19:49:27 +08:00
2dust
be13446e69 Speed ​​test address maintenance 2024-11-04 14:21:11 +08:00
2dust
ee57d5b8e6 Improve checkup date 2024-11-04 14:15:59 +08:00
2dust
4eda3dd8fa Add Memo attribute to subscription group
https://github.com/2dust/v2rayN/issues/5981
2024-11-04 10:42:42 +08:00
2dust
911dc7f90e Revert
9fd20ff001
2024-11-04 10:37:44 +08:00
fonaix
18005b96e8 修复:双击表头弹出编辑窗口的问题 (#5984)
* 修复:日志文本框垂直显示上下空白问题

* 修复:双击表头弹出编辑窗口的问题
2024-11-04 09:44:03 +08:00
2dust
a3e45d206e Bug fix
https://github.com/2dust/v2rayN/issues/5979
2024-11-03 21:15:50 +08:00
2dust
0accf262dc up 7.0.6 2024-11-03 16:49:06 +08:00
2dust
e0eb73bb0a Code clean 2024-11-03 16:45:48 +08:00
2dust
258e822c13 Add exit function to the main interface for Desktop 2024-11-03 14:48:13 +08:00
2dust
4f05b93d63 Bug fix
MainModule FileName only exists in Win32.
2024-11-03 13:44:12 +08:00
2dust
bb661d4f50 Only one instance is allowed to run 2024-11-03 13:30:32 +08:00
2dust
201cfaa922 Fix
https://github.com/2dust/v2rayN/issues/5966
2024-11-02 15:02:30 +08:00
2dust
c339aa349c up PackageReference 2024-11-02 14:42:26 +08:00
2dust
046421f345 Code clean 2024-11-02 14:42:01 +08:00
fonaix
3a2c9e7aaa 修复:日志文本框垂直显示上下空白问题 (#5967) 2024-11-02 10:28:18 +08:00
2dust
0bb6e6bd86 up 7.0.5 2024-11-01 16:54:16 +08:00
2dust
693e8ab157 Add startup auto-start for desktop 2024-11-01 14:54:23 +08:00
2dust
033c16c992 Refactor to select active nodes when updating subscriptions 2024-11-01 10:19:31 +08:00
2dust
6ec61433fb Only update the stable version of the core
https://github.com/2dust/v2rayN/issues/5950
2024-11-01 09:26:15 +08:00
2dust
072f773245 up 7.0.4 2024-10-31 09:59:59 +08:00
2dust
0086f65a96 Bug fix
b7f4fd7469
2024-10-30 08:57:10 +08:00
2dust
281f14f47e Adjustment of preset rule sets 2024-10-28 13:45:39 +08:00
2dust
9fd20ff001 De-duplication after subscription update 2024-10-28 09:38:20 +08:00
2dust
7df90a6034 Bug fix
https://github.com/2dust/v2rayN/issues/5928
2024-10-28 09:16:24 +08:00
109 changed files with 2823 additions and 1312 deletions

View File

@@ -1,5 +1,5 @@
# v2rayN
A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
A GUI client for Windows and Linux, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master)

View File

@@ -8,5 +8,10 @@
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
<FileVersion>1.3.0</FileVersion>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Assets\en-US.json" />
<EmbeddedResource Include="Assets\zh-CN.json" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,14 @@
{
"Restart_v2rayN": "Start v2rayN, please wait...",
"Guidelines": "Please run it from the main application.",
"Upgrade_File_Not_Found": "Upgrade failed, file not found.",
"In_Progress": "In progress, please wait...",
"Try_Terminate_Process": "Try to terminate the v2rayN process.",
"Failed_Terminate_Process": "Failed to terminate the v2rayN.Close it manually,or the upgrade may fail.",
"Start_Unzipping": "Start extracting the update package.",
"Success_Unzipping": "Successfully extracted the update package!",
"Failed_Unzipping": "Failed to extract the update package!",
"Failed_Upgrade": "Upgrade failed!",
"Success_Upgrade": "Upgrade success!",
"Information": "Information"
}

View File

@@ -0,0 +1,14 @@
{
"Restart_v2rayN": "正在重启,请等待...",
"Guidelines": "请从主应用运行!",
"Upgrade_File_Not_Found": "升级失败,文件不存在!",
"In_Progress": "正在进行中,请等待...",
"Try_Terminate_Process": "尝试结束 v2rayN 进程...",
"Failed_Terminate_Process": "请手动关闭正在运行的v2rayN否则可能升级失败。",
"Start_Unzipping": "开始解压缩更新包...",
"Success_Unzipping": "解压缩更新包成功!",
"Failed_Unzipping": "解压缩更新包失败!",
"Failed_Upgrade": "升级失败!",
"Success_Upgrade": "升级成功!",
"Information": "提示"
}

View File

@@ -0,0 +1,59 @@
using System.Globalization;
using System.Reflection;
using System.Text.Json;
namespace AmazTool
{
public class LocalizationHelper
{
private static Dictionary<string, string> _languageResources = [];
static LocalizationHelper()
{
// 加载语言资源
LoadLanguageResources();
}
private static void LoadLanguageResources()
{
try
{
var currentLanguage = CultureInfo.CurrentCulture.Name;
if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
{
currentLanguage = "en-US";
}
var resourceName = $"AmazTool.Assets.{currentLanguage}.json";
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream == null) return;
using StreamReader reader = new(stream);
var json = reader.ReadToEnd();
if (!string.IsNullOrEmpty(json))
{
_languageResources = JsonSerializer.Deserialize<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
}
}
catch (IOException ex)
{
Console.WriteLine($"Failed to read language resource file: {ex.Message}");
}
catch (JsonException ex)
{
Console.WriteLine($"Failed to parse JSON data: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error occurred: {ex.Message}");
}
}
public static string GetLocalizedValue(string key)
{
return _languageResources.TryGetValue(key, out var translation) ? translation : key;
}
}
}

View File

@@ -10,7 +10,7 @@
{
if (args.Length == 0)
{
Console.WriteLine("Please run it from the main application.(请从主应用运行)");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Guidelines"));
Thread.Sleep(5000);
return;
}

View File

@@ -8,35 +8,33 @@ namespace AmazTool
{
public static void Upgrade(string fileName)
{
Console.WriteLine(fileName);
Console.WriteLine("In progress, please wait...(正在进行中,请等待)");
Console.WriteLine($"{LocalizationHelper.GetLocalizedValue("Start_Unzipping")}\n{fileName}");
Thread.Sleep(9000);
if (!File.Exists(fileName))
{
Console.WriteLine("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Upgrade_File_Not_Found"));
return;
}
Console.WriteLine("Try to end the process(尝试结束进程).");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Try_Terminate_Process"));
try
{
var path = GetPath(V2rayN);
Console.WriteLine(path);
var existing = Process.GetProcessesByName(V2rayN);
var pp = existing.FirstOrDefault(p => p.MainModule?.FileName != null && p.MainModule?.FileName.Contains(path) == true);
pp?.Kill();
pp?.WaitForExit(1000);
foreach (var pp in existing)
{
pp?.Kill();
pp?.WaitForExit(1000);
}
}
catch (Exception ex)
{
// Access may be denied without admin right. The user may not be an administrator.
Console.WriteLine("Failed to close v2rayN(关闭v2rayN失败).\n" +
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace);
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Terminate_Process") + ex.StackTrace);
}
Console.WriteLine("Start extracting files(开始解压文件).");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Start_Unzipping"));
StringBuilder sb = new();
try
{
@@ -79,16 +77,16 @@ namespace AmazTool
}
catch (Exception ex)
{
Console.WriteLine("Upgrade Failed(升级失败)." + ex.StackTrace);
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + ex.StackTrace);
//return;
}
if (sb.Length > 0)
{
Console.WriteLine("Upgrade Failed(升级失败)." + sb.ToString());
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + sb.ToString());
//return;
}
Console.WriteLine("Start v2rayN, please wait...(正在重启,请等待)");
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Restart_v2rayN"));
Thread.Sleep(9000);
Process process = new()
{

View File

@@ -11,11 +11,11 @@ public class PacHandler
private static int _httpPort;
private static int _pacPort;
private static TcpListener? _tcpListener;
private static string _pacText;
private static byte[] _writeContent;
private static bool _isRunning;
private static bool _needRestart = true;
public static void Start(string configPath, int httpPort, int pacPort)
public static async Task Start(string configPath, int httpPort, int pacPort)
{
_needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
@@ -23,7 +23,7 @@ public class PacHandler
_httpPort = httpPort;
_pacPort = pacPort;
InitText();
await InitText();
if (_needRestart)
{
@@ -32,15 +32,24 @@ public class PacHandler
}
}
private static void InitText()
private static async Task InitText()
{
var path = Path.Combine(_configPath, "pac.txt");
if (!File.Exists(path))
{
File.AppendAllText(path, Resources.ResourceManager.GetString("pac"));
await File.AppendAllTextAsync(path, Resources.ResourceManager.GetString("pac"));
}
_pacText = File.ReadAllText(path).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
var pacText = (await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
sb.AppendLine();
sb.Append(pacText);
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
}
private static void RunListener()
@@ -60,21 +69,8 @@ public class PacHandler
continue;
}
var client = _tcpListener.AcceptTcpClient();
await Task.Run(() =>
{
var stream = client.GetStream();
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(_pacText));
sb.AppendLine();
sb.Append(_pacText);
var content = Encoding.UTF8.GetBytes(sb.ToString());
stream.Write(content, 0, content.Length);
stream.Flush();
});
var client = await _tcpListener.AcceptTcpClientAsync();
await Task.Run(() => { WriteContent(client); });
}
catch
{
@@ -84,6 +80,13 @@ public class PacHandler
}, TaskCreationOptions.LongRunning);
}
private static void WriteContent(TcpClient client)
{
var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush();
}
public static void Stop()
{
if (_tcpListener == null) return;

View File

@@ -0,0 +1,75 @@
using System.Security.Cryptography;
using System.Text;
namespace ServiceLib.Common
{
public class DesUtils
{
/// <summary>
/// Encrypt
/// </summary>
/// <param name="text"></param>
/// /// <param name="key"></param>
/// <returns></returns>
public static string Encrypt(string? text, string? key = null)
{
if (text.IsNullOrEmpty())
{
return string.Empty;
}
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
var dsp = DES.Create();
using var memStream = new MemoryStream();
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
using var sWriter = new StreamWriter(cryStream);
sWriter.Write(text);
sWriter.Flush();
cryStream.FlushFinalBlock();
memStream.Flush();
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
}
/// <summary>
/// Decrypt
/// </summary>
/// <param name="encryptText"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Decrypt(string? encryptText, string? key = null)
{
if (encryptText.IsNullOrEmpty())
{
return string.Empty;
}
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
var dsp = DES.Create();
var buffer = Convert.FromBase64String(encryptText);
using var memStream = new MemoryStream();
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
cryStream.Write(buffer, 0, buffer.Length);
cryStream.FlushFinalBlock();
return Encoding.UTF8.GetString(memStream.ToArray());
}
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
{
if (key.IsNullOrEmpty())
{
throw new ArgumentNullException("The key cannot be null");
}
if (key.Length <= 8)
{
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
}
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
}
private static string GetDefaultKey()
{
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Net.Http.Headers;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
@@ -98,7 +98,7 @@ namespace ServiceLib.Common
totalRead += read;
if (read == 0) break;
await file.WriteAsync(buffer, 0, read, token);
await file.WriteAsync(buffer.AsMemory(0, read), token);
if (canReportProgress)
{

View File

@@ -37,40 +37,41 @@ namespace ServiceLib.Common
foreach (var filePath in files)
{
var file = new FileInfo(filePath);
if (file.CreationTime < now)
if (file.CreationTime >= now) continue;
try
{
try
{
file.Delete();
}
catch { }
file.Delete();
}
catch
{
// ignored
}
}
}
catch { }
catch
{
// ignored
}
});
}
public static void SaveLog(string strContent)
{
if (LogManager.IsLoggingEnabled())
{
var logger = LogManager.GetLogger("Log1");
logger.Info(strContent);
}
if (!LogManager.IsLoggingEnabled()) return;
LogManager.GetLogger("Log1").Info(strContent);
}
public static void SaveLog(string strTitle, Exception ex)
{
if (LogManager.IsLoggingEnabled())
if (!LogManager.IsLoggingEnabled()) return;
var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace);
if (ex?.InnerException != null)
{
var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace);
if (ex?.InnerException != null)
{
logger.Error(ex.InnerException);
}
logger.Error(ex.InnerException);
}
}
}

View File

@@ -1,4 +1,4 @@
using CliWrap;
using CliWrap;
using CliWrap.Buffered;
using System.Collections.Specialized;
using System.Diagnostics;
@@ -38,6 +38,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return result;
}
@@ -58,6 +59,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return null;
}
@@ -92,6 +94,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return string.Empty;
}
@@ -116,6 +119,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return null;
}
@@ -137,6 +141,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return null;
}
@@ -156,6 +161,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog("Base64Encode", ex);
}
return string.Empty;
}
@@ -170,16 +176,16 @@ namespace ServiceLib.Common
{
if (plainText.IsNullOrEmpty()) return "";
plainText = plainText.Trim()
.Replace(Environment.NewLine, "")
.Replace("\n", "")
.Replace("\r", "")
.Replace('_', '/')
.Replace('-', '+')
.Replace(" ", "");
.Replace(Environment.NewLine, "")
.Replace("\n", "")
.Replace("\r", "")
.Replace('_', '/')
.Replace('-', '+')
.Replace(" ", "");
if (plainText.Length % 4 > 0)
{
plainText = plainText.PadRight(plainText.Length + 4 - plainText.Length % 4, '=');
plainText = plainText.PadRight(plainText.Length + 4 - (plainText.Length % 4), '=');
}
var data = Convert.FromBase64String(plainText);
@@ -189,6 +195,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog("Base64Decode", ex);
}
return string.Empty;
}
@@ -251,14 +258,17 @@ namespace ServiceLib.Common
unit = "TB";
return;
}
result = GBs + ((MBs % factor) / (factor + 0.0));
unit = "GB";
return;
}
result = MBs + ((KBs % factor) / (factor + 0.0));
unit = "MB";
return;
}
result = KBs + ((amount % factor) / (factor + 0.0));
unit = "KB";
return;
@@ -302,6 +312,7 @@ namespace ServiceLib.Common
{
continue;
}
var key = Uri.UnescapeDataString(keyValue[0]);
var val = Uri.UnescapeDataString(keyValue[1]);
@@ -323,6 +334,7 @@ namespace ServiceLib.Common
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
@@ -337,6 +349,7 @@ namespace ServiceLib.Common
{
return url;
}
try
{
Uri uri = new(url);
@@ -368,6 +381,7 @@ namespace ServiceLib.Common
{
return text;
}
return text.Replace("", ",").Replace(Environment.NewLine, ",");
}
@@ -391,6 +405,7 @@ namespace ServiceLib.Common
{
return true;
}
return text == "null";
}
@@ -424,6 +439,7 @@ namespace ServiceLib.Common
_ => false,
};
}
return false;
}
@@ -448,6 +464,7 @@ namespace ServiceLib.Common
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31) return true;
if (ipBytes[0] == 192 && ipBytes[1] == 168) return true;
}
return false;
}
@@ -468,6 +485,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return false;
}
@@ -489,6 +507,7 @@ namespace ServiceLib.Common
catch
{
}
return 59090;
}
@@ -512,7 +531,8 @@ namespace ServiceLib.Common
{
if (blFull)
{
return $"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture} - {File.GetLastWriteTime(GetExePath()):yyyy/MM/dd}";
return
$"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture} - {File.GetLastWriteTime(GetExePath()):yyyy/MM/dd}";
}
else
{
@@ -523,6 +543,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return Global.AppName;
}
@@ -560,6 +581,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return string.Empty;
}
@@ -572,7 +594,11 @@ namespace ServiceLib.Common
{
try
{
if (fileName.IsNullOrEmpty()) { return; }
if (fileName.IsNullOrEmpty())
{
return;
}
Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = true });
}
catch (Exception ex)
@@ -605,6 +631,7 @@ namespace ServiceLib.Common
{
Logging.SaveLog(ex.Message, ex);
}
return systemHosts;
}
@@ -629,17 +656,20 @@ namespace ServiceLib.Common
cmd = cmd.WithArguments(args);
}
}
var result = await cmd.ExecuteBufferedAsync();
if (result.IsSuccess)
{
return result.StandardOutput.ToString();
}
Logging.SaveLog(result.ToString() ?? "");
}
catch (Exception ex)
{
Logging.SaveLog("GetCliWrapOutput", ex);
}
return null;
}
@@ -654,6 +684,7 @@ namespace ServiceLib.Common
{
return startupPath;
}
return Path.Combine(startupPath, fileName);
}
@@ -674,6 +705,7 @@ namespace ServiceLib.Common
{
Directory.CreateDirectory(tempPath);
}
if (IsNullOrEmpty(filename))
{
return tempPath;
@@ -691,6 +723,7 @@ namespace ServiceLib.Common
{
Directory.CreateDirectory(tempPath);
}
return Path.Combine(tempPath, filename);
}
@@ -701,6 +734,7 @@ namespace ServiceLib.Common
{
Directory.CreateDirectory(tempPath);
}
if (Utils.IsNullOrEmpty(filename))
{
return tempPath;
@@ -718,6 +752,7 @@ namespace ServiceLib.Common
{
Directory.CreateDirectory(tempPath);
}
if (coreType != null)
{
tempPath = Path.Combine(tempPath, coreType.ToLower().ToString());
@@ -726,6 +761,7 @@ namespace ServiceLib.Common
Directory.CreateDirectory(tempPath);
}
}
if (IsNullOrEmpty(filename))
{
return tempPath;
@@ -743,6 +779,7 @@ namespace ServiceLib.Common
{
Directory.CreateDirectory(tempPath);
}
if (Utils.IsNullOrEmpty(filename))
{
return tempPath;
@@ -760,6 +797,7 @@ namespace ServiceLib.Common
{
Directory.CreateDirectory(tempPath);
}
if (Utils.IsNullOrEmpty(filename))
{
return tempPath;
@@ -820,11 +858,18 @@ namespace ServiceLib.Common
public static async Task<string?> GetLinuxFontFamily(string lang)
{
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
var arg = new List<string>() { "-c", $"fc-list : family" };
return await GetCliWrapOutput("/bin/bash", arg);
}
public static string? GetHomePath()
{
return IsWindows()
? Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%")
: Environment.GetEnvironmentVariable("HOME");
}
#endregion Platform
}
}

View File

@@ -0,0 +1,52 @@
using Microsoft.Win32;
namespace ServiceLib.Common
{
internal static class WindowsUtils
{
public static string? RegReadValue(string path, string name, string def)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.OpenSubKey(path, false);
var value = regKey?.GetValue(name) as string;
return Utils.IsNullOrEmpty(value) ? def : 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 (Utils.IsNullOrEmpty(value.ToString()))
{
regKey?.DeleteValue(name, false);
}
else
{
regKey?.SetValue(name, value);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
}
}
}

View File

@@ -4,12 +4,8 @@
{
v2fly = 1,
Xray = 2,
//SagerNet = 3,
v2fly_v5 = 4,
//clash = 11,
//clash_meta = 12,
mihomo = 13,
hysteria = 21,

View File

@@ -5,6 +5,7 @@
ClearMsg,
SendMsgView,
SendSnackMsg,
RefreshProfiles
RefreshProfiles,
StopSpeedtest
}
}

View File

@@ -7,6 +7,7 @@
ws,
httpupgrade,
splithttp,
xhttp,
h2,
http,
quic,

View File

@@ -28,21 +28,24 @@
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
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 NamespaceSample = "ServiceLib.Sample.";
public const string V2raySampleClient = NamespaceSample + "SampleClientConfig";
public const string SingboxSampleClient = NamespaceSample + "SingboxSampleClientConfig";
public const string V2raySampleHttpRequestFileName = NamespaceSample + "SampleHttpRequest";
public const string V2raySampleHttpResponseFileName = NamespaceSample + "SampleHttpResponse";
public const string V2raySampleInbound = NamespaceSample + "SampleInbound";
public const string V2raySampleOutbound = NamespaceSample + "SampleOutbound";
public const string SingboxSampleOutbound = NamespaceSample + "SingboxSampleOutbound";
public const string CustomRoutingFileName = NamespaceSample + "custom_routing_";
public const string TunSingboxDNSFileName = NamespaceSample + "tun_singbox_dns";
public const string TunSingboxInboundFileName = NamespaceSample + "tun_singbox_inbound";
public const string TunSingboxRulesFileName = NamespaceSample + "tun_singbox_rules";
public const string DNSV2rayNormalFileName = NamespaceSample + "dns_v2ray_normal";
public const string DNSSingboxNormalFileName = NamespaceSample + "dns_singbox_normal";
public const string ClashMixinYaml = NamespaceSample + "clash_mixin_yaml";
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp";
@@ -102,9 +105,9 @@
public static readonly List<string> SpeedTestUrls = new() {
@"https://speed.cloudflare.com/__down?bytes=100000000",
@"https://speed.cloudflare.com/__down?bytes=50000000",
@"https://speed.cloudflare.com/__down?bytes=10000000",
@"http://cachefly.cachefly.net/50mb.test",
@"http://cachefly.cachefly.net/10mb.test"
@"https://cachefly.cachefly.net/50mb.test",
};
public static readonly List<string> SpeedPingTestUrls = new() {
@@ -172,11 +175,10 @@
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
public static readonly List<string> SsSecuritiesInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" };
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "xhttp", "splithttp", "h2", "quic", "grpc" };
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
public static readonly List<string> CoreTypes = new() { "v2fly", "Xray", "sing_box" };
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
@@ -185,6 +187,7 @@
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" };
public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
public static readonly List<string> XhttpMode = new() { "auto", "packet-up", "stream-up" };
public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
@@ -204,9 +207,9 @@
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" };
public static readonly List<string> allowSelectType = new() { "selector", "urltest", "loadbalance", "fallback" };
public static readonly List<string> notAllowTestType = new() { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
public static readonly List<string> proxyVehicleType = new() { "file", "http" };
#endregion const
}

View File

@@ -71,7 +71,7 @@
public bool InitComponents()
{
Logging.Setup();
Logging.LoggingEnabled(true);
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
Logging.ClearLogs();
@@ -247,7 +247,7 @@
case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox;
}
return Global.SsSecuritiesInSagerNet;
return Global.SsSecuritiesInSingbox;
}
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)

View File

@@ -0,0 +1,155 @@
using System.Security.Principal;
using System.Text.RegularExpressions;
namespace ServiceLib.Handler
{
public static class AutoStartupHandler
{
public static async Task<bool> UpdateTask(Config config)
{
if (Utils.IsWindows())
{
await ClearTaskWindows();
if (config.GuiItem.AutoRun)
{
await SetTaskWindows();
}
}
else if (Utils.IsLinux())
{
await ClearTaskLinux();
if (config.GuiItem.AutoRun)
{
await SetTaskLinux();
}
}
return true;
}
#region Windows
private static async Task ClearTaskWindows()
{
var autoRunName = GetAutoRunNameWindows();
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, "");
if (Utils.IsAdministrator())
{
AutoStartTaskService(autoRunName, "", "");
}
}
private static async Task SetTaskWindows()
{
try
{
var autoRunName = GetAutoRunNameWindows();
var exePath = Utils.GetExePath();
if (Utils.IsAdministrator())
{
AutoStartTaskService(autoRunName, exePath, "");
}
else
{
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath.AppendQuotes());
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
/// <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 AutoStartTaskService(string taskName, string fileName, string description)
{
if (Utils.IsNullOrEmpty(taskName))
{
return;
}
var logonUser = WindowsIdentity.GetCurrent().Name;
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
if (Utils.IsNullOrEmpty(fileName))
{
foreach (var t in tasks)
{
taskService.RootFolder.DeleteTask(t.Name);
}
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = description;
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 Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
taskService.RootFolder.RegisterTaskDefinition(taskName, task);
}
private static string GetAutoRunNameWindows()
{
return $"{Global.AutoRunName}_{Utils.GetMd5(Utils.StartupPath())}";
}
#endregion Windows
#region Linux
private static async Task ClearTaskLinux()
{
try
{
File.Delete(GetHomePathLinux());
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
private static async Task SetTaskLinux()
{
try
{
var linuxConfig = Utils.GetEmbedText(Global.LinuxAutostartConfig);
if (linuxConfig.IsNotEmpty())
{
linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath());
Logging.SaveLog(linuxConfig);
var homePath = GetHomePathLinux();
await File.WriteAllTextAsync(homePath, linuxConfig);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
private static string GetHomePathLinux()
{
var homePath = Path.Combine(Utils.GetHomePath(), ".config", "autostart", $"{Global.AppName}.desktop");
Directory.CreateDirectory(Path.GetDirectoryName(homePath));
return homePath;
}
#endregion Linux
}
}

View File

@@ -1,4 +1,4 @@
using System.Data;
using System.Data;
using System.Text.RegularExpressions;
namespace ServiceLib.Handler
@@ -162,6 +162,7 @@ namespace ServiceLib.Handler
config.ClashUIItem ??= new();
config.SystemProxyItem ??= new();
config.WebDavItem ??= new();
config.CheckUpdateItem ??= new();
return config;
}
@@ -239,6 +240,7 @@ namespace ServiceLib.Handler
item.PublicKey = profileItem.PublicKey;
item.ShortId = profileItem.ShortId;
item.SpiderX = profileItem.SpiderX;
item.Extra = profileItem.Extra;
}
var ret = item.ConfigType switch
@@ -465,7 +467,7 @@ namespace ServiceLib.Handler
break;
}
case EMove.Position:
sort = pos * 10 + 1;
sort = (pos * 10) + 1;
break;
}
@@ -957,7 +959,6 @@ namespace ServiceLib.Handler
&& o.Address == n.Address
&& o.Port == n.Port
&& o.Id == n.Id
&& o.AlterId == n.AlterId
&& o.Security == n.Security
&& o.Network == n.Network
&& o.HeaderType == n.HeaderType
@@ -966,6 +967,10 @@ namespace ServiceLib.Handler
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& o.Flow == n.Flow
&& o.Sni == n.Sni
&& o.Alpn == n.Alpn
&& o.Fingerprint == n.Fingerprint
&& o.PublicKey == n.PublicKey
&& o.ShortId == n.ShortId
&& (!remarks || o.Remarks == n.Remarks);
}
@@ -1034,14 +1039,14 @@ namespace ServiceLib.Handler
/// <param name="strData"></param>
/// <param name="subid"></param>
/// <returns>成功导入的数量</returns>
private static async Task<int> AddBatchServers(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
private static async Task<int> AddBatchServersCommon(Config config, string strData, string subid, bool isSub)
{
if (Utils.IsNullOrEmpty(strData))
{
return -1;
}
string subFilter = string.Empty;
var subFilter = string.Empty;
//remove sub items
if (isSub && Utils.IsNotEmpty(subid))
{
@@ -1049,16 +1054,14 @@ namespace ServiceLib.Handler
subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? "";
}
int countServers = 0;
//Check for duplicate indexId
List<string>? lstDbIndexId = null;
var countServers = 0;
List<ProfileItem> lstAdd = new();
var arrData = strData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
if (isSub)
{
arrData = arrData.Distinct();
}
foreach (string str in arrData)
foreach (var str in arrData)
{
//maybe sub
if (!isSub && (str.StartsWith(Global.HttpsProtocol) || str.StartsWith(Global.HttpProtocol)))
@@ -1075,35 +1078,12 @@ namespace ServiceLib.Handler
continue;
}
//exist sub items
if (isSub && Utils.IsNotEmpty(subid))
//exist sub items //filter
if (isSub && Utils.IsNotEmpty(subid) && Utils.IsNotEmpty(subFilter))
{
var existItem = lstOriSub?.FirstOrDefault(t => t.IsSub == isSub
&& config.UiItem.EnableUpdateSubOnlyRemarksExist ? t.Remarks == profileItem.Remarks : CompareProfileItem(t, profileItem, true));
if (existItem != null)
if (!Regex.IsMatch(profileItem.Remarks, subFilter))
{
//Check for duplicate indexId
if (lstDbIndexId is null)
{
lstDbIndexId = await AppHandler.Instance.ProfileItemIndexes("");
}
if (lstAdd.Any(t => t.IndexId == existItem.IndexId)
|| lstDbIndexId.Any(t => t == existItem.IndexId))
{
profileItem.IndexId = string.Empty;
}
else
{
profileItem.IndexId = existItem.IndexId;
}
}
//filter
if (Utils.IsNotEmpty(subFilter))
{
if (!Regex.IsMatch(profileItem.Remarks, subFilter))
{
continue;
}
continue;
}
}
profileItem.Subid = subid;
@@ -1138,7 +1118,7 @@ namespace ServiceLib.Handler
return countServers;
}
private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub)
{
if (Utils.IsNullOrEmpty(strData))
{
@@ -1222,10 +1202,7 @@ namespace ServiceLib.Handler
{
await RemoveServerViaSubid(config, subid, isSub);
}
if (isSub && lstOriSub?.Count == 1)
{
profileItem.IndexId = lstOriSub[0].IndexId;
}
profileItem.Subid = subid;
profileItem.IsSub = isSub;
profileItem.PreSocksPort = preSocksPort;
@@ -1239,7 +1216,7 @@ namespace ServiceLib.Handler
}
}
private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub)
{
if (Utils.IsNullOrEmpty(strData))
{
@@ -1278,34 +1255,47 @@ namespace ServiceLib.Handler
return -1;
}
List<ProfileItem>? lstOriSub = null;
ProfileItem? activeProfile = null;
if (isSub && Utils.IsNotEmpty(subid))
{
lstOriSub = await AppHandler.Instance.ProfileItems(subid);
activeProfile = lstOriSub?.FirstOrDefault(t => t.IndexId == config.IndexId);
}
var counter = 0;
if (Utils.IsBase64String(strData))
{
counter = await AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub);
counter = await AddBatchServersCommon(config, Utils.Base64Decode(strData), subid, isSub);
}
if (counter < 1)
{
counter = await AddBatchServers(config, strData, subid, isSub, lstOriSub);
counter = await AddBatchServersCommon(config, strData, subid, isSub);
}
if (counter < 1)
{
counter = await AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub);
counter = await AddBatchServersCommon(config, Utils.Base64Decode(strData), subid, isSub);
}
if (counter < 1)
{
counter = await AddBatchServers4SsSIP008(config, strData, subid, isSub, lstOriSub);
counter = await AddBatchServers4SsSIP008(config, strData, subid, isSub);
}
//maybe other sub
if (counter < 1)
{
counter = await AddBatchServers4Custom(config, strData, subid, isSub, lstOriSub);
counter = await AddBatchServers4Custom(config, strData, subid, isSub);
}
//Select active node
if (activeProfile != null)
{
var lstSub = await AppHandler.Instance.ProfileItems(subid);
var existItem = lstSub?.FirstOrDefault(t => config.UiItem.EnableUpdateSubOnlyRemarksExist ? t.Remarks == activeProfile.Remarks : CompareProfileItem(t, activeProfile, true));
if (existItem != null)
{
await ConfigHandler.SetDefaultServerIndex(config, existItem.IndexId);
}
}
return counter;
@@ -1373,6 +1363,7 @@ namespace ServiceLib.Handler
item.PrevProfile = subItem.PrevProfile;
item.NextProfile = subItem.NextProfile;
item.PreSocksPort = subItem.PreSocksPort;
item.Memo = subItem.Memo;
}
if (Utils.IsNullOrEmpty(item.Id))

View File

@@ -59,15 +59,18 @@ namespace ServiceLib.Handler
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
ShowMsg(false, result.Msg);
if (result.Success != true)
{
ShowMsg(true, result.Msg);
return;
}
else
{
ShowMsg(true, $"{node.GetSummary()}");
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop();
await Task.Delay(100);
await CoreStart(node);
//In tun mode, do a delay check and restart the core
@@ -99,6 +102,8 @@ namespace ServiceLib.Handler
ShowMsg(false, result.Msg);
if (result.Success)
{
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
pid = await CoreStartSpeedtest(configPath, coreType);
}
return pid;
@@ -108,13 +113,11 @@ namespace ServiceLib.Handler
{
try
{
bool hasProc = false;
if (_process != null)
{
await KillProcess(_process);
_process.Dispose();
_process = null;
hasProc = true;
}
if (_processPre != null)
@@ -122,26 +125,6 @@ namespace ServiceLib.Handler
await KillProcess(_processPre);
_processPre.Dispose();
_processPre = null;
hasProc = true;
}
if (!hasProc)
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfo)
{
if (it.CoreType == ECoreType.v2rayN)
{
continue;
}
foreach (var name in it.CoreExes)
{
var path = Utils.GetBinPath(Utils.GetExeName(name), it.CoreType.ToString());
var existing = Process.GetProcessesByName(name);
var pp = existing.FirstOrDefault(p => p.MainModule?.FileName != null && p.MainModule?.FileName.Contains(path) == true);
await KillProcess(pp);
}
}
}
}
catch (Exception ex)
@@ -167,7 +150,7 @@ namespace ServiceLib.Handler
private string CoreFindExe(CoreInfo coreInfo)
{
string fileName = string.Empty;
var fileName = string.Empty;
foreach (var name in coreInfo.CoreExes)
{
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
@@ -179,7 +162,7 @@ namespace ServiceLib.Handler
}
if (Utils.IsNullOrEmpty(fileName))
{
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
var msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
Logging.SaveLog(msg);
ShowMsg(false, msg);
}
@@ -188,24 +171,12 @@ namespace ServiceLib.Handler
private async Task CoreStart(ProfileItem node)
{
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
//ECoreType coreType;
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
//{
// coreType = ECoreType.sing_box;
//}
//else
//{
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
//}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
_config.RunningCoreType = coreType;
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
var proc = await RunProcess(node, coreInfo, "", displayLog);
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
if (proc is null)
{
return;
@@ -242,12 +213,12 @@ namespace ServiceLib.Handler
}
if (itemSocks != null)
{
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
var fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2);
if (result.Success)
{
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc2 = await RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
var proc2 = await RunProcess(coreInfo2, Global.CorePreConfigFileName, true, true);
if (proc2 is not null)
{
_processPre = proc2;
@@ -259,13 +230,10 @@ namespace ServiceLib.Handler
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
{
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
try
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false);
if (proc is null)
{
return -1;
@@ -276,8 +244,7 @@ namespace ServiceLib.Handler
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
string msg = ex.Message;
ShowMsg(false, msg);
ShowMsg(false, ex.Message);
return -1;
}
}
@@ -287,19 +254,29 @@ namespace ServiceLib.Handler
_updateFunc?.Invoke(notify, msg);
}
private bool IsNeedSudo(ECoreType eCoreType)
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& Utils.IsLinux()
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
#endregion Private
#region Process
private async Task<Process?> RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog)
private async Task<Process?> RunProcess(CoreInfo coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
{
var fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
try
{
string fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
Process proc = new()
{
StartInfo = new()
@@ -315,33 +292,44 @@ namespace ServiceLib.Handler
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
}
};
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
if (isNeedSudo)
{
await RunProcessAsLinuxRoot(proc, fileName, coreInfo, configPath);
}
var startUpErrorMessage = new StringBuilder();
var startUpSuccessful = false;
if (displayLog)
{
proc.OutputDataReceived += (sender, e) =>
{
if (Utils.IsNotEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
}
if (Utils.IsNullOrEmpty(e.Data)) return;
ShowMsg(false, e.Data + Environment.NewLine);
};
proc.ErrorDataReceived += (sender, e) =>
{
if (Utils.IsNotEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
if (Utils.IsNullOrEmpty(e.Data)) return;
ShowMsg(false, e.Data + Environment.NewLine);
if (!startUpSuccessful)
{
startUpErrorMessage.Append(msg);
}
if (!startUpSuccessful)
{
startUpErrorMessage.Append(e.Data + Environment.NewLine);
}
};
}
proc.Start();
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
if (displayLog)
{
proc.BeginOutputReadLine();
@@ -364,32 +352,68 @@ namespace ServiceLib.Handler
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
string msg = ex.Message;
ShowMsg(true, msg);
ShowMsg(true, ex.Message);
return null;
}
}
private async Task RunProcessAsLinuxRoot(Process proc, string fileName, CoreInfo coreInfo, string configPath)
{
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
//Prefer shell scripts
var shFilePath = Utils.GetBinPath("run_as_root.sh");
File.Delete(shFilePath);
var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh");
sb.AppendLine(cmdLine);
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
//Replace command
var args = File.Exists(shFilePath) ? shFilePath : cmdLine;
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
proc.StartInfo.FileName = $"/bin/sudo";
proc.StartInfo.Arguments = $"-S {args}";
}
else
{
proc.StartInfo.FileName = $"/bin/pkexec";
proc.StartInfo.Arguments = $"{args}";
}
proc.StartInfo.WorkingDirectory = null;
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
Logging.SaveLog(proc.StartInfo.Arguments);
}
private async Task KillProcess(Process? proc)
{
if (proc is null)
{
return;
}
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
try
{
await proc.WaitForExitAsync(timeout.Token);
}
catch (OperationCanceledException)
{
proc.Kill();
proc.WaitForExit(100);
if (!proc.HasExited)
}
if (!proc.HasExited)
{
try
{
await proc.WaitForExitAsync(timeout.Token);
}
catch (Exception)
{
proc.Kill();
proc.WaitForExit(100);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
#endregion Process

View File

@@ -1,6 +1,4 @@
using System.Runtime.Intrinsics.X86;
namespace ServiceLib.Handler
namespace ServiceLib.Handler
{
public sealed class CoreInfoHandler
{
@@ -74,7 +72,7 @@ namespace ServiceLib.Handler
{
CoreType = ECoreType.Xray,
CoreExes = new List<string> { "xray", "wxray" },
Arguments = "run {0}",
Arguments = "run -c {0}",
Url = Global.XrayCoreUrl,
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
@@ -89,7 +87,7 @@ namespace ServiceLib.Handler
_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" },
CoreExes = new List<string> { "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "mihomo", "clash" },
Arguments = "-f config.json" + PortableMode(),
Url = Global.MihomoCoreUrl,
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -105,7 +103,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.hysteria,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria" },
Arguments = "",
Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -134,7 +132,7 @@ namespace ServiceLib.Handler
{
CoreType = ECoreType.sing_box,
CoreExes = new List<string> { "sing-box-client", "sing-box" },
Arguments = "run {0} --disable-color",
Arguments = "run -c {0} --disable-color",
Url = Global.SingboxCoreUrl,
RedirectInfo = true,
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -157,7 +155,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.hysteria2,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria" },
Arguments = "",
Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -167,7 +165,7 @@ namespace ServiceLib.Handler
private string PortableMode()
{
return $" -d \"{Utils.GetBinPath("")}\"";
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
}
}
}

View File

@@ -83,7 +83,6 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
if (Utils.IsNotEmpty(item.RequestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
@@ -94,6 +93,26 @@ namespace ServiceLib.Handler.Fmt
}
break;
case nameof(ETransport.splithttp):
case nameof(ETransport.xhttp):
if (Utils.IsNotEmpty(item.RequestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (Utils.IsNotEmpty(item.Path))
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
if (Utils.IsNotEmpty(item.HeaderType) && Global.XhttpMode.Contains(item.HeaderType))
{
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
}
if (Utils.IsNotEmpty(item.Extra))
{
dicQuery.Add("extra", Utils.UrlEncode(item.Extra));
}
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
dicQuery["type"] = nameof(ETransport.http);
@@ -156,11 +175,18 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.splithttp):
case nameof(ETransport.xhttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
item.HeaderType = Utils.UrlDecode(query["mode"] ?? "");
item.Extra = Utils.UrlDecode(query["extra"] ?? "");
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
item.Network = nameof(ETransport.h2);

View File

@@ -9,7 +9,8 @@
private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat;
private Action<ServerSpeedItem>? _updateFunc;
private StatisticsV2rayService? _statisticsV2Ray;
//private StatisticsV2rayService? _statisticsV2Ray;
private StatisticsXrayService? _statisticsXray;
private StatisticsSingboxService? _statisticsSingbox;
public List<ServerStatItem> ServerStat => _lstServerStat;
@@ -25,7 +26,8 @@
await InitData();
_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler);
//_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler);
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
}
@@ -33,7 +35,8 @@
{
try
{
_statisticsV2Ray?.Close();
//_statisticsV2Ray?.Close();
_statisticsXray?.Close();
_statisticsSingbox?.Close();
}
catch (Exception ex)

View File

@@ -2,12 +2,81 @@
{
public class ProxySettingOSX
{
/*
* 仅测试了MacOS 13.7.1 x86 版本,其他版本有待确认
*/
/// <summary>
/// 应用接口类型
/// </summary>
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge"];
/// <summary>
/// 代理类型,对应 http,https,socks
/// </summary>
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
public static async Task SetProxy(string host, int port)
{
var lstCmd = GetSetCmds(host, port);
await ExecCmd(lstCmd);
}
public static async Task UnsetProxy()
{
var lstCmd = GetUnsetCmds();
await ExecCmd(lstCmd);
}
private static async Task ExecCmd(List<CmdItem> lstCmd)
{
foreach (var cmd in lstCmd)
{
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
{
continue;
}
await Task.Delay(10);
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
}
}
private static List<CmdItem> GetSetCmds(string host, int port)
{
List<CmdItem> lstCmd = [];
foreach (var interf in LstInterface)
{
foreach (var type in LstTypes)
{
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = [$"-{type}", interf, host, (type.Contains("socks") ? (port - 1) : port).ToString()]
});
}
}
return lstCmd;
}
private static List<CmdItem> GetUnsetCmds()
{
List<CmdItem> lstCmd = [];
foreach (var interf in LstInterface)
{
foreach (var type in LstTypes)
{
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = [$"-{type}state", interf, "off"]
});
}
}
return lstCmd;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using static ServiceLib.Handler.SysProxy.ProxySettingWindows.InternetConnectionOption;
namespace ServiceLib.Handler.SysProxy
@@ -11,24 +11,24 @@ namespace ServiceLib.Handler.SysProxy
{
if (type == 1)
{
RegWriteValue(_regPath, "ProxyEnable", 0);
RegWriteValue(_regPath, "ProxyServer", string.Empty);
RegWriteValue(_regPath, "ProxyOverride", string.Empty);
RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
}
if (type == 2)
{
RegWriteValue(_regPath, "ProxyEnable", 1);
RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 1);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
}
else if (type == 4)
{
RegWriteValue(_regPath, "ProxyEnable", 0);
RegWriteValue(_regPath, "ProxyServer", string.Empty);
RegWriteValue(_regPath, "ProxyOverride", string.Empty);
RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
}
return true;
}
@@ -144,12 +144,12 @@ namespace ServiceLib.Handler.SysProxy
{
if (Environment.Is64BitOperatingSystem)
{
nint opt = new(optionsPtr.ToInt64() + i * optSize);
nint opt = new(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
else
{
nint opt = new(optionsPtr.ToInt32() + i * optSize);
nint opt = new(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
}
@@ -247,7 +247,7 @@ namespace ServiceLib.Handler.SysProxy
//[MarshalAs(UnmanagedType.)]
public nint options;
};
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption
@@ -356,30 +356,5 @@ namespace ServiceLib.Handler.SysProxy
ref int lpcEntries // Number of entries written to the buffer
);
}
private static void RegWriteValue(string path, string name, object value)
{
Microsoft.Win32.RegistryKey? regKey = null;
try
{
regKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(path);
if (string.IsNullOrEmpty(value.ToString()))
{
regKey?.DeleteValue(name, false);
}
else
{
regKey?.SetValue(name, value);
}
}
catch (Exception ex)
{
//Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
}
}
}

View File

@@ -33,15 +33,10 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.SetProxy(Global.Loopback, port);
break;
case ESysProxyType.ForcedChange:
{
if (Utils.IsOSX())
{
await ProxySettingOSX.SetProxy(Global.Loopback, port);
}
case ESysProxyType.ForcedChange when Utils.IsOSX():
await ProxySettingOSX.SetProxy(Global.Loopback, port);
break;
break;
}
case ESysProxyType.ForcedClear when Utils.IsWindows():
ProxySettingWindows.UnsetProxy();
break;
@@ -50,23 +45,13 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.UnsetProxy();
break;
case ESysProxyType.ForcedClear:
{
if (Utils.IsOSX())
{
await ProxySettingOSX.UnsetProxy();
}
case ESysProxyType.ForcedClear when Utils.IsOSX():
await ProxySettingOSX.UnsetProxy();
break;
break;
}
case ESysProxyType.Pac when Utils.IsWindows():
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
break;
}
await SetWindowsProxyPac(port);
break;
}
if (type != ESysProxyType.Pac && Utils.IsWindows())
@@ -102,5 +87,13 @@ namespace ServiceLib.Handler.SysProxy
.Replace("{socks_port}", portSocks.ToString());
}
}
private static async Task SetWindowsProxyPac(int port)
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
}
}
}

View File

@@ -1,6 +1,6 @@
namespace ServiceLib.Models
{
public class CheckUpdateItem
public class CheckUpdateModel
{
public bool? IsSelected { get; set; }
public string? CoreType { get; set; }

View File

@@ -15,15 +15,14 @@
public bool IsRunningCore(ECoreType type)
{
if (type == ECoreType.Xray && RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5)
switch (type)
{
return true;
case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5:
case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo:
return true;
default:
return false;
}
if (type == ECoreType.sing_box && RunningCoreType is ECoreType.sing_box or ECoreType.mihomo)
{
return true;
}
return false;
}
#endregion property
@@ -46,6 +45,7 @@
public ClashUIItem ClashUIItem { get; set; }
public SystemProxyItem SystemProxyItem { get; set; }
public WebDavItem WebDavItem { get; set; }
public CheckUpdateItem CheckUpdateItem { get; set; }
public List<InItem> Inbound { get; set; }
public List<KeyEventItem> GlobalHotkeys { get; set; }
public List<CoreTypeItem> CoreTypeItem { get; set; }

View File

@@ -81,13 +81,13 @@
public int AutoUpdateInterval { get; set; }
public bool CheckPreReleaseUpdate { get; set; } = false;
public bool EnableSecurityProtocolTls13 { get; set; }
public int TrayMenuServersLimit { get; set; } = 20;
public bool EnableHWA { get; set; } = false;
public bool EnableLog { get; set; } = true;
}
[Serializable]
@@ -116,6 +116,7 @@
public bool EnableDragDropSort { get; set; }
public bool DoubleClick2Activate { get; set; }
public bool AutoHideStartup { get; set; }
public bool Hide2TrayWhenClose { get; set; }
public List<ColumnItem> MainColumnItem { get; set; }
public bool ShowInTaskbar { get; set; }
}
@@ -161,6 +162,7 @@
public int Mtu { get; set; }
public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; }
public string? LinuxSudoPwd { get; set; }
}
[Serializable]
@@ -243,4 +245,11 @@
public string? Password { get; set; }
public string? DirName { get; set; }
}
[Serializable]
public class CheckUpdateItem
{
public bool CheckPreReleaseUpdate { get; set; }
public List<string>? SelectedCoreTypes { get; set; }
}
}

View File

@@ -30,44 +30,25 @@ namespace ServiceLib.Models
public string GetSummary()
{
string summary = string.Format("[{0}] ", (ConfigType).ToString());
string[] arrAddr = Address.Split('.');
string addr;
if (arrAddr.Length > 2)
var summary = $"[{(ConfigType).ToString()}] ";
var arrAddr = Address.Split('.');
var addr = arrAddr.Length switch
{
addr = $"{arrAddr.First()}***{arrAddr.Last()}";
}
else if (arrAddr.Length > 1)
> 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
> 1 => $"***{arrAddr.Last()}",
_ => Address
};
summary += ConfigType switch
{
addr = $"***{arrAddr.Last()}";
}
else
{
addr = Address;
}
switch (ConfigType)
{
case EConfigType.Custom:
summary += string.Format("[{1}]{0}", Remarks, CoreType.ToString());
break;
default:
summary += string.Format("{0}({1}:{2})", Remarks, addr, Port);
break;
}
EConfigType.Custom => $"[{CoreType.ToString()}]{Remarks}",
_ => $"{Remarks}({addr}:{Port})"
};
return summary;
}
public List<string>? GetAlpn()
{
if (Utils.IsNullOrEmpty(Alpn))
{
return null;
}
else
{
return Utils.String2List(Alpn);
}
return Utils.IsNullOrEmpty(Alpn) ? null : Utils.String2List(Alpn);
}
public string GetNetwork()
@@ -110,5 +91,6 @@ namespace ServiceLib.Models
public string PublicKey { get; set; }
public string ShortId { get; set; }
public string SpiderX { get; set; }
public string Extra { get; set; }
}
}

View File

@@ -78,8 +78,7 @@
public int? listen_port { get; set; }
public string? domain_strategy { get; set; }
public string interface_name { get; set; }
public string inet4_address { get; set; }
public string? inet6_address { get; set; }
public List<string>? address { get; set; }
public int? mtu { get; set; }
public bool? auto_route { get; set; }
public bool? strict_route { get; set; }

View File

@@ -33,5 +33,7 @@ namespace ServiceLib.Models
public string? NextProfile { get; set; }
public int? PreSocksPort { get; set; }
public string? Memo { get; set; }
}
}

View File

@@ -1,61 +1,34 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;
namespace ServiceLib.Models
{
/// <summary>
/// v2ray配置文件实体类 例子SampleConfig.txt
/// </summary>
public class V2rayConfig
{
/// <summary>
/// Properties that do not belong to Ray
/// </summary>
public string? remarks { get; set; }
/// <summary>
/// 日志配置
/// </summary>
public Log4Ray log { get; set; }
/// <summary>
/// 传入连接配置
/// </summary>
public List<Inbounds4Ray> inbounds { get; set; }
/// <summary>
/// 传出连接配置
/// </summary>
public List<Outbounds4Ray> outbounds { get; set; }
/// <summary>
/// 统计需要, 空对象
/// </summary>
public Stats4Ray stats { get; set; }
public Stats4Ray? stats { get; set; }
/// </summary>
public API4Ray api { get; set; }
public Metrics4Ray? metrics { get; set; }
/// </summary>
public Policy4Ray policy { get; set; }
public Policy4Ray? policy { get; set; }
/// <summary>
/// DNS 配置
/// </summary>
public object dns { get; set; }
/// <summary>
/// 路由配置
/// </summary>
public Routing4Ray routing { get; set; }
}
public class Stats4Ray
{ };
{ }
public class API4Ray
public class Metrics4Ray
{
public string tag { get; set; }
public List<string> services { get; set; }
}
public class Policy4Ray
@@ -71,124 +44,59 @@ namespace ServiceLib.Models
public class Log4Ray
{
/// <summary>
///
/// </summary>
public string access { get; set; }
public string? access { get; set; }
/// <summary>
///
/// </summary>
public string error { get; set; }
public string? error { get; set; }
/// <summary>
///
/// </summary>
public string loglevel { get; set; }
public string? loglevel { get; set; }
}
public class Inbounds4Ray
{
public string tag { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; }
/// <summary>
///
/// </summary>
public string listen { get; set; }
/// <summary>
///
/// </summary>
public string protocol { get; set; }
/// <summary>
///
/// </summary>
public Sniffing4Ray sniffing { get; set; }
/// <summary>
///
/// </summary>
public Inboundsettings4Ray settings { get; set; }
/// <summary>
///
/// </summary>
public StreamSettings4Ray streamSettings { get; set; }
}
public class Inboundsettings4Ray
{
/// <summary>
///
/// </summary>
public string auth { get; set; }
public string? auth { get; set; }
/// <summary>
///
/// </summary>
public bool udp { get; set; }
public bool? udp { get; set; }
/// <summary>
///
/// </summary>
public string ip { get; set; }
public string? ip { get; set; }
/// <summary>
/// api 使用
/// </summary>
public string address { get; set; }
public string? address { get; set; }
/// <summary>
///
/// </summary>
public List<UsersItem4Ray> clients { get; set; }
public List<UsersItem4Ray>? clients { get; set; }
/// <summary>
/// VLESS
/// </summary>
public string decryption { get; set; }
public string? decryption { get; set; }
public bool allowTransparent { get; set; }
public bool? allowTransparent { get; set; }
public List<AccountsItem4Ray> accounts { get; set; }
public List<AccountsItem4Ray>? accounts { get; set; }
}
public class UsersItem4Ray
{
/// <summary>
///
/// </summary>
public string id { get; set; }
public string? id { get; set; }
/// <summary>
///
/// </summary>
public int alterId { get; set; }
public int? alterId { get; set; }
/// <summary>
///
/// </summary>
public string email { get; set; }
public string? email { get; set; }
/// <summary>
///
/// </summary>
public string security { get; set; }
public string? security { get; set; }
/// <summary>
/// VLESS
/// </summary>
public string encryption { get; set; }
public string? encryption { get; set; }
/// <summary>
/// VLESS
/// </summary>
public string? flow { get; set; }
}
@@ -201,57 +109,27 @@ namespace ServiceLib.Models
public class Outbounds4Ray
{
/// <summary>
/// 默认值agentout
/// </summary>
public string tag { get; set; }
/// <summary>
///
/// </summary>
public string protocol { get; set; }
/// <summary>
///
/// </summary>
public Outboundsettings4Ray settings { get; set; }
/// <summary>
///
/// </summary>
public StreamSettings4Ray streamSettings { get; set; }
/// <summary>
///
/// </summary>
public Mux4Ray mux { get; set; }
}
public class Outboundsettings4Ray
{
/// <summary>
///
/// </summary>
public List<VnextItem4Ray>? vnext { get; set; }
/// <summary>
///
/// </summary>
public List<ServersItem4Ray> servers { get; set; }
public List<ServersItem4Ray>? servers { get; set; }
/// <summary>
///
/// </summary>
public Response4Ray response { get; set; }
public Response4Ray? response { get; set; }
/// <summary>
///
/// </summary>
public string domainStrategy { get; set; }
/// <summary>
///
/// </summary>
public int? userLevel { get; set; }
public FragmentItem4Ray? fragment { get; set; }
@@ -259,85 +137,40 @@ namespace ServiceLib.Models
public class VnextItem4Ray
{
/// <summary>
///
/// </summary>
public string address { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; }
/// <summary>
///
/// </summary>
public List<UsersItem4Ray> users { get; set; }
}
public class ServersItem4Ray
{
/// <summary>
///
/// </summary>
public string email { get; set; }
/// <summary>
///
/// </summary>
public string address { get; set; }
/// <summary>
///
/// </summary>
public string? method { get; set; }
/// <summary>
///
/// </summary>
public bool? ota { get; set; }
/// <summary>
///
/// </summary>
public string? password { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; }
/// <summary>
///
/// </summary>
public int? level { get; set; }
/// <summary>
/// trojan
/// </summary>
public string flow { get; set; }
/// <summary>
///
/// </summary>
public List<SocksUsersItem4Ray> users { get; set; }
}
public class SocksUsersItem4Ray
{
/// <summary>
///
/// </summary>
public string user { get; set; }
/// <summary>
///
/// </summary>
public string pass { get; set; }
/// <summary>
///
/// </summary>
public int? level { get; set; }
}
@@ -351,17 +184,11 @@ namespace ServiceLib.Models
public class Response4Ray
{
/// <summary>
///
/// </summary>
public string type { get; set; }
}
public class Dns4Ray
{
/// <summary>
///
/// </summary>
public List<string> servers { get; set; }
}
@@ -373,19 +200,10 @@ namespace ServiceLib.Models
public class Routing4Ray
{
/// <summary>
///
/// </summary>
public string domainStrategy { get; set; }
/// <summary>
///
/// </summary>
public string? domainMatcher { get; set; }
/// <summary>
///
/// </summary>
public List<RulesItem4Ray> rules { get; set; }
public List<BalancersItem4Ray>? balancers { get; set; }
@@ -426,87 +244,39 @@ namespace ServiceLib.Models
public class StreamSettings4Ray
{
/// <summary>
///
/// </summary>
public string network { get; set; }
/// <summary>
///
/// </summary>
public string security { get; set; }
/// <summary>
///
/// </summary>
public TlsSettings4Ray? tlsSettings { get; set; }
/// <summary>
/// Tcp传输额外设置
/// </summary>
public TcpSettings4Ray? tcpSettings { get; set; }
/// <summary>
/// Kcp传输额外设置
/// </summary>
public KcpSettings4Ray? kcpSettings { get; set; }
/// <summary>
/// ws传输额外设置
/// </summary>
public WsSettings4Ray? wsSettings { get; set; }
/// <summary>
///
/// </summary>
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
/// <summary>
///
/// </summary>
public SplithttpSettings4Ray? splithttpSettings { get; set; }
public XhttpSettings4Ray? xhttpSettings { get; set; }
/// <summary>
/// h2传输额外设置
/// </summary>
public HttpSettings4Ray? httpSettings { get; set; }
/// <summary>
/// QUIC
/// </summary>
public QuicSettings4Ray? quicSettings { get; set; }
/// <summary>
/// VLESS only
/// </summary>
public TlsSettings4Ray? realitySettings { get; set; }
/// <summary>
/// grpc
/// </summary>
public GrpcSettings4Ray? grpcSettings { get; set; }
/// <summary>
/// sockopt
/// </summary>
public Sockopt4Ray? sockopt { get; set; }
}
public class TlsSettings4Ray
{
/// <summary>
/// 是否允许不安全连接(用于客户端)
/// </summary>
public bool? allowInsecure { get; set; }
/// <summary>
///
/// </summary>
public string? serverName { get; set; }
/// <summary>
///
/// </summary>
public List<string>? alpn { get; set; }
public string? fingerprint { get; set; }
@@ -519,157 +289,94 @@ namespace ServiceLib.Models
public class TcpSettings4Ray
{
/// <summary>
/// 数据包头部伪装设置
/// </summary>
public Header4Ray header { get; set; }
}
public class Header4Ray
{
/// <summary>
/// 伪装
/// </summary>
public string type { get; set; }
/// <summary>
/// 结构复杂,直接存起来
/// </summary>
public object request { get; set; }
/// <summary>
/// 结构复杂,直接存起来
/// </summary>
public object response { get; set; }
}
public class KcpSettings4Ray
{
/// <summary>
///
/// </summary>
public int mtu { get; set; }
/// <summary>
///
/// </summary>
public int tti { get; set; }
/// <summary>
///
/// </summary>
public int uplinkCapacity { get; set; }
/// <summary>
///
/// </summary>
public int downlinkCapacity { get; set; }
/// <summary>
///
/// </summary>
public bool congestion { get; set; }
/// <summary>
///
/// </summary>
public int readBufferSize { get; set; }
/// <summary>
///
/// </summary>
public int writeBufferSize { get; set; }
/// <summary>
///
/// </summary>
public Header4Ray header { get; set; }
/// <summary>
///
/// </summary>
public string seed { get; set; }
}
public class WsSettings4Ray
{
/// <summary>
///
/// </summary>
public string path { get; set; }
/// <summary>
///
/// </summary>
public Headers4Ray headers { get; set; }
}
public class Headers4Ray
{
/// <summary>
///
/// </summary>
public string Host { get; set; }
/// <summary>
/// 用户代理
/// </summary>
[JsonPropertyName("User-Agent")]
public string UserAgent { get; set; }
}
public class HttpupgradeSettings4Ray
{
/// <summary>
///
/// </summary>
public string? path { get; set; }
/// <summary>
///
/// </summary>
public string? host { get; set; }
}
public class SplithttpSettings4Ray
public class XhttpSettings4Ray
{
public string? path { get; set; }
public string? host { get; set; }
public string? mode { get; set; }
public string? scMaxEachPostBytes { get; set; }
public string? scMaxConcurrentPosts { get; set; }
public string? scMinPostsIntervalMs { get; set; }
public Xmux4Ray? xmux { get; set; }
public object? extra { get; set; }
}
public int? maxUploadSize { get; set; }
public int? maxConcurrentUploads { get; set; }
public class Xmux4Ray
{
public int? maxConcurrency { get; set; }
public int? maxConnections { get; set; }
public int? cMaxReuseTimes { get; set; }
public int? cMaxLifetimeMs { get; set; }
}
public class HttpSettings4Ray
{
/// <summary>
///
/// </summary>
public string? path { get; set; }
/// <summary>
///
/// </summary>
public List<string>? host { get; set; }
}
public class QuicSettings4Ray
{
/// <summary>
///
/// </summary>
public string security { get; set; }
/// <summary>
///
/// </summary>
public string key { get; set; }
/// <summary>
///
/// </summary>
public Header4Ray header { get; set; }
}
@@ -686,14 +393,8 @@ namespace ServiceLib.Models
public class AccountsItem4Ray
{
/// <summary>
///
/// </summary>
public string user { get; set; }
/// <summary>
///
/// </summary>
public string pass { get; set; }
}

View File

@@ -0,0 +1,20 @@
using System.Collections;
namespace ServiceLib.Models
{
internal class V2rayMetricsVars
{
public V2rayMetricsVarsStats? stats { get; set; }
}
}
public class V2rayMetricsVarsStats
{
public Hashtable? outbound { get; set; }
}
public class V2rayMetricsVarsLink
{
public long downlink { get; set; }
public long uplink { get; set; }
}

View File

@@ -447,6 +447,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Remarks Memo 的本地化字符串。
/// </summary>
public static string LvMemo {
get {
return ResourceManager.GetString("LvMemo", resourceCulture);
}
}
/// <summary>
/// 查找类似 More URLs, separated by commas; Subscription conversion will be invalid 的本地化字符串。
/// </summary>
@@ -870,6 +879,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Are you sure to exit? 的本地化字符串。
/// </summary>
public static string menuExitTips {
get {
return ResourceManager.GetString("menuExitTips", resourceCulture);
}
}
/// <summary>
/// 查找类似 Export selected server for complete configuration 的本地化字符串。
/// </summary>
@@ -3085,6 +3103,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Hide to tray when closing the window 的本地化字符串。
/// </summary>
public static string TbSettingsHide2TrayWhenClose {
get {
return ResourceManager.GetString("TbSettingsHide2TrayWhenClose", resourceCulture);
}
}
/// <summary>
/// 查找类似 HTTP Port 的本地化字符串。
/// </summary>
@@ -3130,6 +3157,42 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Linux system sudo password 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPassword {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPassword", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please set the sudo password in Tun mode settings first 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordIsEmpty {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordIsEmpty", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please do not run this app with sudo 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordNotSudoRunApp {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordNotSudoRunApp", resourceCulture);
}
}
/// <summary>
/// 查找类似 The password is encrypted and stored only in local files. 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordTip {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Enable Log 的本地化字符串。
/// </summary>
@@ -3643,6 +3706,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 XHTTP Extra raw JSON, format: { XHTTPObject } 的本地化字符串。
/// </summary>
public static string TransportExtraTip {
get {
return ResourceManager.GetString("TransportExtraTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 *tcp camouflage type 的本地化字符串。
/// </summary>
@@ -3680,7 +3752,16 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 *ws/httpupgrade/splithttp path 的本地化字符串。
/// 查找类似 *xhttp mode 的本地化字符串。
/// </summary>
public static string TransportHeaderTypeTip5 {
get {
return ResourceManager.GetString("TransportHeaderTypeTip5", resourceCulture);
}
}
/// <summary>
/// 查找类似 *ws/httpupgrade/xhttp path 的本地化字符串。
/// </summary>
public static string TransportPathTip1 {
get {
@@ -3734,7 +3815,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 *ws/httpupgrade/splithttp host 的本地化字符串。
/// 查找类似 *ws/httpupgrade/xhttp host 的本地化字符串。
/// </summary>
public static string TransportRequestHostTip2 {
get {

View File

@@ -1033,4 +1033,361 @@
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value>
</data>
<data name="menuRemoteBackup" xml:space="preserve">
<value>Backup to remote (WebDAV)</value>
</data>
<data name="menuRemoteRestore" xml:space="preserve">
<value>Restore from remote (WebDAV)</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>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>Backup and Restore</value>
</data>
<data name="menuLocalBackup" xml:space="preserve">
<value>Backup to local</value>
</data>
<data name="menuLocalRestore" xml:space="preserve">
<value>Restore from local</value>
</data>
<data name="menuLocalBackupAndRestore" xml:space="preserve">
<value>Local</value>
</data>
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
<value>Remote (WebDAV)</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav Url</value>
</data>
<data name="LvWebDavUserName" xml:space="preserve">
<value>WebDav User Name</value>
</data>
<data name="LvWebDavPassword" xml:space="preserve">
<value>WebDav Password</value>
</data>
<data name="LvWebDavCheck" xml:space="preserve">
<value>WebDav Check</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>Remote folder name (optional)</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>Invalid backup file</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>Host filter</value>
</data>
<data name="TipActiveServer" xml:space="preserve">
<value>Active</value>
</data>
<data name="menuStorageUI" xml:space="preserve">
<value>Save Interface Layout</value>
</data>
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
<value>Geo files source (optional)</value>
</data>
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
<value>sing-box ruleset files source (optional)</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>UpgradeApp does not exist</value>
</data>
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
<value>Routing rules source (optional)</value>
</data>
<data name="menuRegionalPresets" xml:space="preserve">
<value>Regional presets setting</value>
</data>
<data name="menuRegionalPresetsDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>Russia</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>Users in China region can ignore this item</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve">
<value>Scan QR code in the image</value>
</data>
<data name="InvalidUrlTip" xml:space="preserve">
<value>Invalid address (Url)</value>
</data>
<data name="InsecureUrlProtocol" xml:space="preserve">
<value>Please do not use the insecure HTTP protocol subscription address</value>
</data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>Are you sure to exit?</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value>
</data>
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
<value>Enable logging to file</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>Updates are not enabled, skip this subscription</value>
</data>
<data name="menuRebootAsAdmin" xml:space="preserve">
<value>Restart as Administrator</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0} : {1}/s↑ | {2}/s↓</value>
</data>
<data name="LvAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval (minutes)</value>
</data>
<data name="LvConvertTarget" xml:space="preserve">
<value>Convert target type</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>Please leave blank if no conversion is required</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value>
</data>
<data name="menuDNSSetting" xml:space="preserve">
<value>DNS Settings</value>
</data>
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
<value>Please fill in DNS Structure, Click to view the document</value>
</data>
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
<value>Click to import default DNS config</value>
</data>
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
<value>sing-box domain strategy</value>
</data>
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>sing-box Mux Protocol</value>
</data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>Full process name (Tun mode)</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP or IP CIDR</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>Domain</value>
</data>
<data name="TbSettingsCoreDnsSingbox" xml:space="preserve">
<value>sing-box DNS settings</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing (press ESC to terminate)...</value>
</data>
<data name="TbSpiderX" xml:space="preserve">
<value>SpiderX</value>
</data>
<data name="TbShortId" xml:space="preserve">
<value>ShortId</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve">
<value>Move to group</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Enable Server Drag Drop Sort(Require restart)</value>
</data>
<data name="TbAutoRefresh" xml:space="preserve">
<value>AutoRefresh</value>
</data>
<data name="SpeedtestingSkip" xml:space="preserve">
<value>Skip test</value>
</data>
<data name="menuEditServer" xml:space="preserve">
<value>Edit Server (Ctrl+D)</value>
</data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>Double-click server make active</value>
</data>
<data name="SpeedtestingCompleted" xml:space="preserve">
<value>Test completed</value>
</data>
<data name="TbSettingsDefFingerprint" xml:space="preserve">
<value>Default TLS fingerprint</value>
</data>
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
<value>FontFamily(Require restart)</value>
</data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<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 = +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>
</data>
<data name="TbSettingsFontSize" xml:space="preserve">
<value>Font Size</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="menuMoveTo" xml:space="preserve">
<value>Move up and down</value>
</data>
<data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Hysteria2] server</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria Max bandwidth (Up/Dw)</value>
</data>
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
<value>Follow System Theme</value>
</data>
<data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] server</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>Updating subscription, only determine remarks exists</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>Refresh Proxies</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>Network</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>Type</value>
</data>
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Add [HTTP] server</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>Speed Ping Test URL</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>Custom the rule-set of sing-box</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>Successful operation. Click the settings menu to reboot the app.</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>Open the storage location</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>Chain</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>Host</value>
</data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>Use System Hosts</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</value>
</data>
<data name="TbAutoScrollToEnd" xml:space="preserve">
<value>Auto ScrollToEnd</value>
</data>
<data name="SpeedtestingStop" xml:space="preserve">
<value>Test terminating...</value>
</data>
<data name="LvNextProfile" xml:space="preserve">
<value>Next proxy remarks</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>obfs password</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value>
</data>
<data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy remarks</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>Add [WireGuard] server</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Enable additional Inbound</value>
</data>
<data name="LvPrevProfileTip" xml:space="preserve">
<value>Please make sure the remarks exists and is unique</value>
</data>
<data name="TbRuleMatchingTips" xml:space="preserve">
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag =&gt; OutboundTag</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -344,7 +344,7 @@
<value>Please fill in the correct custom DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value>
<value>*ws/httpupgrade/xhttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -359,7 +359,7 @@
<value>*http host Separated by commas (,)</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value>
<value>*ws/httpupgrade/xhttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host Separated by commas (,)</value>
@@ -1363,4 +1363,31 @@
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>Are you sure to exit?</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -1046,6 +1046,348 @@
<value>Россия</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>Используйте Настройки -> Региональные пресеты вместо изменения этого поля</value>
<value>Используйте Настройки -&gt; Региональные пресеты вместо изменения этого поля</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>Speed Ping Test URL</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="TbAutoScrollToEnd" xml:space="preserve">
<value>Auto ScrollToEnd</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value>
</data>
<data name="TbRuleMatchingTips" xml:space="preserve">
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag =&gt; OutboundTag</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>obfs password</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</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="menuProxiesDelaytest" xml:space="preserve">
<value>Latency Test</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>Add [WireGuard] server</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="TbSortingDelay" xml:space="preserve">
<value>Delay</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Enable additional Inbound</value>
</data>
<data name="LvPrevProfileTip" xml:space="preserve">
<value>Please make sure the remarks exists and is unique</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>Export selected server for complete configuration to clipboard</value>
</data>
<data name="LvNextProfile" xml:space="preserve">
<value>Next proxy remarks</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value>
</data>
<data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy remarks</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound DNS address</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>Updating subscription, only determine remarks exists</value>
</data>
<data name="SpeedtestingStop" xml:space="preserve">
<value>Test terminating...</value>
</data>
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>Chain</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>Sorting</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>Open the storage location</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>Successful operation. Click the settings menu to reboot the app.</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>Custom the rule-set of sing-box</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="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>Enable cache file for sing-box (ruleset files)</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="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>Rule</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Add [HTTP] server</value>
</data>
<data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] server</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="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Custom config socks port</value>
</data>
<data name="LvWebDavCheck" xml:space="preserve">
<value>WebDav Check</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>Domain</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP or IP CIDR</value>
</data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>Full process name (Tun mode)</value>
</data>
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>sing-box Mux Protocol</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>Invalid backup file</value>
</data>
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
<value>sing-box domain strategy</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>Host filter</value>
</data>
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
<value>Click to import default DNS config</value>
</data>
<data name="TipActiveServer" xml:space="preserve">
<value>Active</value>
</data>
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
<value>Please fill in DNS Structure, Click to view the document</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>Please leave blank if no conversion is required</value>
</data>
<data name="LvConvertTarget" xml:space="preserve">
<value>Convert target type</value>
</data>
<data name="menuStorageUI" xml:space="preserve">
<value>Save Interface Layout</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0} : {1}/s↑ | {2}/s↓</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>Updates are not enabled, skip this subscription</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>UpgradeApp does not exist</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve">
<value>Scan QR code in the image</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing (press ESC to terminate)...</value>
</data>
<data name="TbSpiderX" xml:space="preserve">
<value>SpiderX</value>
</data>
<data name="TbShortId" xml:space="preserve">
<value>ShortId</value>
</data>
<data name="InvalidUrlTip" xml:space="preserve">
<value>Invalid address (Url)</value>
</data>
<data name="InsecureUrlProtocol" xml:space="preserve">
<value>Please do not use the insecure HTTP protocol subscription address</value>
</data>
<data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
</data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Hysteria2] server</value>
</data>
<data name="LvWebDavPassword" xml:space="preserve">
<value>WebDav Password</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>Remote folder name (optional)</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>Download Speed</value>
</data>
<data name="menuRemoteRestore" xml:space="preserve">
<value>Restore from remote (WebDAV)</value>
</data>
<data name="menuRemoteBackup" xml:space="preserve">
<value>Backup to remote (WebDAV)</value>
</data>
<data name="LvWebDavUserName" xml:space="preserve">
<value>WebDav User Name</value>
</data>
<data name="menuLocalRestore" xml:space="preserve">
<value>Restore from local</value>
</data>
<data name="menuLocalBackup" xml:space="preserve">
<value>Backup to local</value>
</data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>Use System Hosts</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>Backup and Restore</value>
</data>
<data name="menuLocalBackupAndRestore" xml:space="preserve">
<value>Local</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>Are you sure to exit?</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria Max bandwidth (Up/Dw)</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav Url</value>
</data>
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
<value>Remote (WebDAV)</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -344,7 +344,7 @@
<value>请填写正确的自定义DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value>
<value>*ws/httpupgrade/xhttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -359,7 +359,7 @@
<value>*http host中间逗号(,)分隔</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value>
<value>*ws/httpupgrade/xhttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中间逗号(,)分隔</value>
@@ -1271,7 +1271,7 @@
<value>显示或隐藏主界面</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value>
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自定义配置的Socks端口</value>
@@ -1360,4 +1360,31 @@
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>安装字体到系统中,重启设置</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>是否确定退出?</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>备注备忘</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux系统的sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>请先在Tun模式设置中设置sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>请不要用sudo运行本app</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>关闭窗口时隐藏至托盘</value>
</data>
</root>

View File

@@ -127,7 +127,7 @@
<value>設定格式不正確</value>
</data>
<data name="CustomServerTips" xml:space="preserve">
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>下載開始...</value>
@@ -157,7 +157,7 @@
<value>請填寫正確格式伺服器埠</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>請填寫本機聽埠</value>
<value>請填寫本機聽埠</value>
</data>
<data name="FillPassword" xml:space="preserve">
<value>請填寫密碼</value>
@@ -301,7 +301,7 @@
<value>掃描匯入分享链接成功</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>目前服務的真連延遲: {0} ms</value>
<value>目前服務的真連延遲: {0} ms</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value>
@@ -343,7 +343,7 @@
<value>請填寫正確的自訂DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value>
<value>*ws/httpupgrade/xhttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -358,7 +358,7 @@
<value>*http host中間逗號(,)分隔</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value>
<value>*ws/httpupgrade/xhttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中間逗號(,)分隔</value>
@@ -511,7 +511,7 @@
<value>清除所有服務統計資料</value>
</data>
<data name="menuRealPingServer" xml:space="preserve">
<value>測試伺服器真連延遲(多選) (Ctrl+R)</value>
<value>測試伺服器真連延遲(多選) (Ctrl+R)</value>
</data>
<data name="menuSortServerResult" xml:space="preserve">
<value>按測試結果排序</value>
@@ -683,7 +683,7 @@
<value>進階代理設定, 協定選擇(可選)</value>
</data>
<data name="TbSettingsAllowLAN" xml:space="preserve">
<value>允許來自區域網路的連</value>
<value>允許來自區域網路的連</value>
</data>
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>啟動後隱藏視窗</value>
@@ -722,7 +722,7 @@
<value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value>
</data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>本機HTTP聽埠</value>
<value>本機HTTP聽埠</value>
</data>
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>更新Core時忽略Geo檔案</value>
@@ -755,7 +755,7 @@
<value>開啟流量探測</value>
</data>
<data name="TbSettingsSocksPort" xml:space="preserve">
<value>本機SOCKS聽埠</value>
<value>本機SOCKS聽埠</value>
</data>
<data name="TbSettingsStartBoot" xml:space="preserve">
<value>開機啟動(可能會不成功)</value>
@@ -998,7 +998,7 @@
<value>複製字型TTF/TTC檔案到目錄guiFonts重啟設定</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value>
<value>http連接埠= +1Pac連接埠= +4*ray API連接埠= +5mihomo API連接埠= +6</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
@@ -1094,7 +1094,7 @@
<value>請確保別名存在並且唯一</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>啟用額外監聽端口</value>
<value>啟用額外偵聽連接埠</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>啟用IPv6</value>
@@ -1106,7 +1106,7 @@
<value>自动滚动到末尾</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>真連測試址</value>
<value>真連測試址</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>更新訂閱時只判斷別名是否存在</value>
@@ -1151,10 +1151,10 @@
<value>顯示或隱藏主介面</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自訂設定的Socks端口</value>
<value>自訂設定的Socks連接埠</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>備份和還原</value>
@@ -1187,7 +1187,7 @@
<value>WebDav 密碼</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav 伺服器址</value>
<value>WebDav 伺服器址</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>遠端資料夾名稱(可選)</value>
@@ -1205,25 +1205,25 @@
<value>儲存介面佈局</value>
</data>
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
<value>Geo文件來源(可選)</value>
<value>Geo檔案來源(可選)</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>升工具App不存在</value>
<value>升工具App不存在</value>
</data>
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
<value>sing-box ruleset文件來源(可選)</value>
<value>sing-box ruleset檔案來源(可選)</value>
</data>
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
<value>路由规则集来源(可)</value>
<value>路由規則集來源(可)</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>中国区域用可忽略此</value>
<value>中國區域用可忽略此</value>
</data>
<data name="menuRegionalPresets" xml:space="preserve">
<value>区域预置设置</value>
<value>區域預置設定</value>
</data>
<data name="menuRegionalPresetsDefault" xml:space="preserve">
<value>默认区域</value>
<value>預設區域</value>
</data>
<data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>俄羅斯</value>
@@ -1232,12 +1232,159 @@
<value>掃描圖片中的二維碼</value>
</data>
<data name="InvalidUrlTip" xml:space="preserve">
<value>址(Url)無效</value>
<value>址(Url)無效</value>
</data>
<data name="InsecureUrlProtocol" xml:space="preserve">
<value>請不要使用不安全的HTTP協定訂閱位址</value>
</data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>安裝字到系統中,重新啟動設定</value>
<value>安裝字到系統中,重新啟動設定</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>是否確定退出?</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>備註備忘</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>擁塞控制算法</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>設為活動節點 (Enter)</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>重新整理</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>排序</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>延遲測試</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>規則</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>随原配置</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>全局</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>直連</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>規則模式</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>目前代理</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>關閉所有連線</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Outbound預設解析策略</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>關閉連線</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>上傳流量</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>上傳速度</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>類型</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>時間</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>網路</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>名稱</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>主機</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>下載流量</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>下載速度</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>延遲</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>預設</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>目前連線</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>多伺服器最低延遲 (多選)</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>目前部分節點延遲測試</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>多伺服器負載平衡 (多選)</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>添加[Hysteria2]伺服器</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria 最大頻寬(Up/Dw)</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>主界面佈局方向(需重啟)</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>添加[WireGuard]伺服器</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value>
</data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>使用系統hosts</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>路由鏈</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound域名解析位址</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>混淆密碼(obfs password)</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux系統的sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>請先在Tun模式設定中設定sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>請不要用sudo來運行本app</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>關閉視窗時隱藏至托盤</value>
</data>
</root>

View File

@@ -1,73 +1,149 @@
[
{
"remarks": "绕过bittorrent",
"outboundTag": "direct",
"protocol": [
"bittorrent"
]
},
{
"remarks": "Google cn",
"outboundTag": "proxy",
"domain": [
"domain:googleapis.cn",
"domain:gstatic.com"
]
},
{
"remarks": "阻断udp443",
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{
"remarks": "阻断广告",
"outboundTag": "block",
"domain": [
"geosite:category-ads-all"
]
},
{
"remarks": "绕过局域网IP",
"outboundTag": "direct",
"ip": [
"geoip:private"
]
},
{
"remarks": "绕过局域网域名",
"outboundTag": "direct",
"domain": [
"geosite:private"
]
},
{
"remarks": "代理GFW",
"outboundTag": "proxy",
"domain": [
"geosite:gfw",
"geosite:greatfire"
]
},
{
"remarks": "代理Google等",
"outboundTag": "proxy",
"ip": [
"1.0.0.1",
"1.1.1.1",
"8.8.8.8",
"8.8.4.4",
"geoip:facebook",
"geoip:fastly",
"geoip:google",
"geoip:netflix",
"geoip:telegram",
"geoip:twitter"
]
},
{
"remarks": "最终直连",
"port": "0-65535",
"outboundTag": "direct"
}
{
"remarks": "绕过bittorrent",
"outboundTag": "direct",
"protocol": [
"bittorrent"
]
},
{
"remarks": "Google cn",
"outboundTag": "proxy",
"domain": [
"domain:googleapis.cn",
"domain:gstatic.com"
]
},
{
"remarks": "阻断udp443",
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{
"remarks": "阻断广告",
"outboundTag": "block",
"domain": [
"geosite:category-ads-all"
]
},
{
"remarks": "绕过局域网IP",
"outboundTag": "direct",
"ip": [
"geoip:private"
]
},
{
"remarks": "绕过局域网域名",
"outboundTag": "direct",
"domain": [
"geosite:private"
]
},
{
"remarks": "代理海外公共DNSIP",
"outboundTag": "proxy",
"ip": [
"1.1.1.1",
"1.0.0.1",
"2606:4700:4700::1111",
"2606:4700:4700::1001",
"1.1.1.2",
"1.0.0.2",
"2606:4700:4700::1112",
"2606:4700:4700::1002",
"1.1.1.3",
"1.0.0.3",
"2606:4700:4700::1113",
"2606:4700:4700::1003",
"8.8.8.8",
"8.8.4.4",
"2001:4860:4860::8888",
"2001:4860:4860::8844",
"94.140.14.14",
"94.140.15.15",
"2a10:50c0::ad1:ff",
"2a10:50c0::ad2:ff",
"94.140.14.15",
"94.140.15.16",
"2a10:50c0::bad1:ff",
"2a10:50c0::bad2:ff",
"94.140.14.140",
"94.140.14.141",
"2a10:50c0::1:ff",
"2a10:50c0::2:ff",
"208.67.222.222",
"208.67.220.220",
"2620:119:35::35",
"2620:119:53::53",
"208.67.222.123",
"208.67.220.123",
"2620:119:35::123",
"2620:119:53::123",
"9.9.9.9",
"149.112.112.112",
"2620:fe::9",
"2620:fe::fe",
"9.9.9.11",
"149.112.112.11",
"2620:fe::11",
"2620:fe::fe:11",
"9.9.9.10",
"149.112.112.10",
"2620:fe::10",
"2620:fe::fe:10",
"77.88.8.8",
"77.88.8.1",
"2a02:6b8::feed:0ff",
"2a02:6b8:0:1::feed:0ff",
"77.88.8.88",
"77.88.8.2",
"2a02:6b8::feed:bad",
"2a02:6b8:0:1::feed:bad",
"77.88.8.7",
"77.88.8.3",
"2a02:6b8::feed:a11",
"2a02:6b8:0:1::feed:a11"
]
},
{
"remarks": "代理海外公共DNS域名",
"outboundTag": "proxy",
"domain": [
"domain:cloudflare-dns.com",
"domain:one.one.one.one",
"domain:dns.google",
"domain:adguard-dns.com",
"domain:opendns.com",
"domain:umbrella.com",
"domain:quad9.net",
"domain:yandex.net"
]
},
{
"remarks": "代理IP",
"outboundTag": "proxy",
"ip": [
"geoip:facebook",
"geoip:fastly",
"geoip:google",
"geoip:netflix",
"geoip:telegram",
"geoip:twitter"
]
},
{
"remarks": "代理GFW",
"outboundTag": "proxy",
"domain": [
"geosite:gfw",
"geosite:greatfire"
]
},
{
"remarks": "最终直连",
"port": "0-65535",
"outboundTag": "direct"
}
]

View File

@@ -1,4 +1,5 @@
[{
[
{
"remarks": "block",
"outboundTag": "block",
"domain": [
@@ -12,14 +13,14 @@
"geosite:cn"
]
},
{
"remarks": "direct",
"outboundTag": "direct",
"ip": [
"geoip:private",
"geoip:cn"
]
},
{
"remarks": "direct",
"outboundTag": "direct",
"ip": [
"geoip:private",
"geoip:cn"
]
},
{
"remarks": "proxy",
"port": "0-65535",

View File

@@ -35,44 +35,71 @@
]
},
{
"remarks": "绕过中国域名",
"remarks": "绕过中国公共DNSIP",
"outboundTag": "direct",
"ip": [
"223.5.5.5",
"223.6.6.6",
"2400:3200::1",
"2400:3200:baba::1",
"119.29.29.29",
"1.12.12.12",
"120.53.53.53",
"2402:4e00::",
"2402:4e00:1::",
"180.76.76.76",
"2400:da00::6666",
"114.114.114.114",
"114.114.115.115",
"114.114.114.119",
"114.114.115.119",
"114.114.114.110",
"114.114.115.110",
"180.184.1.1",
"180.184.2.2",
"101.226.4.6",
"218.30.118.6",
"123.125.81.6",
"140.207.198.6",
"1.2.4.8",
"210.2.4.8",
"52.80.66.66",
"117.50.22.22",
"2400:7fc0:849e:200::4",
"2404:c2c0:85d8:901::4",
"117.50.10.10",
"52.80.52.52",
"2400:7fc0:849e:200::8",
"2404:c2c0:85d8:901::8",
"117.50.60.30",
"52.80.60.30"
]
},
{
"remarks": "绕过中国公共DNS域名",
"outboundTag": "direct",
"domain": [
"domain:dns.alidns.com",
"domain:alidns.com",
"domain:doh.pub",
"domain:dot.pub",
"domain:doh.360.cn",
"domain:dot.360.cn",
"geosite:cn",
"geosite:geolocation-cn"
"domain:360.cn",
"domain:onedns.net"
]
},
{
"remarks": "绕过中国IP",
"outboundTag": "direct",
"ip": [
"223.5.5.5/32",
"223.6.6.6/32",
"2400:3200::1/128",
"2400:3200:baba::1/128",
"119.29.29.29/32",
"1.12.12.12/32",
"120.53.53.53/32",
"2402:4e00::/128",
"2402:4e00:1::/128",
"180.76.76.76/32",
"2400:da00::6666/128",
"114.114.114.114/32",
"114.114.115.115/32",
"180.184.1.1/32",
"180.184.2.2/32",
"101.226.4.6/32",
"218.30.118.6/32",
"123.125.81.6/32",
"140.207.198.6/32",
"geoip:cn"
]
},
{
"remarks": "绕过中国域名",
"outboundTag": "direct",
"domain": [
"geosite:cn"
]
},
{
"remarks": "最终代理",
"port": "0-65535",

View File

@@ -20,8 +20,7 @@
"rules": [
{
"rule_set": [
"geosite-cn",
"geosite-geolocation-cn"
"geosite-cn"
],
"server": "local"
},

View File

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

View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Application
Exec=$ExecPath$
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_US]=v2rayN
Name=v2rayN
Comment[en_US]=v2rayN
Comment=v2rayN

View File

@@ -2,8 +2,10 @@
"type": "tun",
"tag": "tun-in",
"interface_name": "singbox_tun",
"inet4_address": "172.19.0.1/30",
"inet6_address": "fdfe:dcba:9876::1/126",
"address": [
"172.18.0.1/30",
"fdfe:dcba:9876::1/126"
],
"mtu": 9000,
"auto_route": true,
"strict_route": false,

View File

@@ -4,9 +4,9 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>7.0.3</Version>
<Version>7.1.3</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Downloader" Version="3.2.1" />
<PackageReference Include="ReactiveUI" Version="20.1.63" />
@@ -14,11 +14,13 @@
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="Splat.NLog" Version="15.2.22" />
<PackageReference Include="WebDav.Client" Version="2.8.0" />
<PackageReference Include="YamlDotNet" Version="16.1.3" />
<PackageReference Include="YamlDotNet" Version="16.2.0" />
<PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="CliWrap" Version="3.6.6" />
<PackageReference Include="CliWrap" Version="3.6.7" />
<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" />
<PackageReference Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
<PackageReference Include="TaskScheduler" Version="2.11.0" />
</ItemGroup>
<ItemGroup>
@@ -41,6 +43,7 @@
<EmbeddedResource Include="Sample\tun_singbox_dns" />
<EmbeddedResource Include="Sample\tun_singbox_inbound" />
<EmbeddedResource Include="Sample\tun_singbox_rules" />
<EmbeddedResource Include="Sample\linux_autostart_config" />
</ItemGroup>

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Services.CoreConfig
namespace ServiceLib.Services.CoreConfig
{
/// <summary>
/// Core configuration file processing class
@@ -66,7 +66,7 @@
txtFile = txtFile.Replace(tagYamlStr1, tagYamlStr2);
//YAML anchors
if (txtFile.Contains("<<:") && txtFile.Contains("*") && txtFile.Contains("&"))
if (txtFile.Contains("<<:") && txtFile.Contains('*') && txtFile.Contains('&'))
{
txtFile = YamlUtils.PreprocessYaml(txtFile);
}

View File

@@ -1,4 +1,4 @@
using System.Data;
using System.Data;
using System.Net;
using System.Net.NetworkInformation;
@@ -26,7 +26,7 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.CheckServerSettings;
return ret;
}
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.splithttp))
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.splithttp) or nameof(ETransport.xhttp))
{
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret;
@@ -484,7 +484,7 @@ namespace ServiceLib.Services.CoreConfig
singboxConfig.inbounds = [];
if (!_config.TunModeItem.EnableTun
|| _config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && _config.RunningCoreType == ECoreType.sing_box)
|| (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && _config.RunningCoreType == ECoreType.sing_box))
{
var inbound = new Inbound4Sbox()
{
@@ -558,7 +558,7 @@ namespace ServiceLib.Services.CoreConfig
//tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
if (_config.TunModeItem.EnableIPv6Address == false)
{
tunInbound.inet6_address = null;
tunInbound.address = ["172.18.0.1/30"];
}
singboxConfig.inbounds.Add(tunInbound);

View File

@@ -27,6 +27,12 @@ namespace ServiceLib.Services.CoreConfig
return ret;
}
if (node.GetNetwork() is nameof(ETransport.quic))
{
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret;
}
ret.Msg = ResUI.InitialConfiguration;
var result = Utils.GetEmbedText(Global.V2raySampleClient);
@@ -366,8 +372,8 @@ namespace ServiceLib.Services.CoreConfig
else
{
v2rayConfig.log.loglevel = _config.CoreBasicItem.Loglevel;
v2rayConfig.log.access = "";
v2rayConfig.log.error = "";
v2rayConfig.log.access = null;
v2rayConfig.log.error = null;
}
}
catch (Exception ex)
@@ -920,23 +926,35 @@ namespace ServiceLib.Services.CoreConfig
streamSettings.httpupgradeSettings = httpupgradeSettings;
break;
//splithttp
//splithttp //xhttp
case nameof(ETransport.splithttp):
SplithttpSettings4Ray splithttpSettings = new()
case nameof(ETransport.xhttp):
streamSettings.network = ETransport.xhttp.ToString();
XhttpSettings4Ray xhttpSettings = new()
{
maxUploadSize = 1000000,
maxConcurrentUploads = 10
scMaxEachPostBytes = "500000-1000000",
scMaxConcurrentPosts = "50-100",
scMinPostsIntervalMs = "30-50"
};
if (Utils.IsNotEmpty(node.Path))
{
splithttpSettings.path = node.Path;
xhttpSettings.path = node.Path;
}
if (Utils.IsNotEmpty(host))
{
splithttpSettings.host = host;
xhttpSettings.host = host;
}
streamSettings.splithttpSettings = splithttpSettings;
if (Utils.IsNotEmpty(node.HeaderType) && Global.XhttpMode.Contains(node.HeaderType))
{
xhttpSettings.mode = node.HeaderType;
}
if (Utils.IsNotEmpty(node.Extra))
{
xhttpSettings.extra = JsonUtils.ParseJson(node.Extra);
}
streamSettings.xhttpSettings = xhttpSettings;
break;
//h2
@@ -1006,18 +1024,17 @@ namespace ServiceLib.Services.CoreConfig
//request Host
string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
string[] arrHost = host.Split(',');
string host2 = string.Join("\",\"", arrHost);
request = request.Replace("$requestHost$", $"\"{host2}\"");
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost()));
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
string host2 = string.Join(",".AppendQuotes(), arrHost);
request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
//Path
string pathHttp = @"/";
if (Utils.IsNotEmpty(node.Path))
{
string[] arrPath = node.Path.Split(',');
pathHttp = string.Join("\",\"", arrPath);
pathHttp = string.Join(",".AppendQuotes(), arrPath);
}
request = request.Replace("$requestPath$", $"\"{pathHttp}\"");
request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
tcpSettings.header.request = JsonUtils.Deserialize<object>(request);
streamSettings.tcpSettings = tcpSettings;
@@ -1120,17 +1137,14 @@ namespace ServiceLib.Services.CoreConfig
if (_config.GuiItem.EnableStatistics)
{
string tag = EInboundProtocol.api.ToString();
API4Ray apiObj = new();
Metrics4Ray apiObj = new();
Policy4Ray policyObj = new();
SystemPolicy4Ray policySystemSetting = new();
string[] services = { "StatsService" };
v2rayConfig.stats = new Stats4Ray();
apiObj.tag = tag;
apiObj.services = services.ToList();
v2rayConfig.api = apiObj;
v2rayConfig.metrics = apiObj;
policySystemSetting.statsOutboundDownlink = true;
policySystemSetting.statsOutboundUplink = true;

View File

@@ -1,4 +1,5 @@
using System.Diagnostics;
using ReactiveUI;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
@@ -80,10 +81,12 @@ namespace ServiceLib.Services
Task.Run(RunMixedtestAsync);
break;
}
MessageBus.Current.Listen<string>(EMsgCommand.StopSpeedtest.ToString()).Subscribe(ExitLoop);
}
public void ExitLoop()
private void ExitLoop(string x)
{
if (_exitLoop) return;
_exitLoop = true;
UpdateFunc("", ResUI.SpeedtestingStop);
}

View File

@@ -0,0 +1,106 @@
namespace ServiceLib.Services.Statistics
{
public class StatisticsXrayService
{
private const long linkBase = 1024;
private string _url;
private ServerSpeedItem _serverSpeedItem = new();
private Config _config;
private bool _exitFlag;
private Action<ServerSpeedItem>? _updateFunc;
public StatisticsXrayService(Config config, Action<ServerSpeedItem> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
_exitFlag = false;
_url = $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort}/debug/vars";
Task.Run(Run);
}
public void Close()
{
_exitFlag = true;
}
private async void Run()
{
while (!_exitFlag)
{
await Task.Delay(1000);
try
{
if (_config.RunningCoreType != ECoreType.Xray)
{
continue;
}
var result = await HttpClientHelper.Instance.TryGetAsync(_url);
if (result != null)
{
var server = ParseOutput(result) ?? new ServerSpeedItem();
_updateFunc?.Invoke(server);
}
}
catch
{
// ignored
}
}
}
private ServerSpeedItem? ParseOutput(string result)
{
try
{
var source = JsonUtils.Deserialize<V2rayMetricsVars>(result);
if (source?.stats?.outbound == null)
{
return null;
}
ServerSpeedItem server = new();
foreach (string key in source.stats.outbound.Keys)
{
var value = source.stats.outbound[key];
if (value == null) continue;
var state = JsonUtils.Deserialize<V2rayMetricsVarsLink>(value.ToString());
if (key.StartsWith(Global.ProxyTag))
{
server.ProxyUp += state.uplink / linkBase;
server.ProxyDown += state.downlink / linkBase;
}
else if (key == Global.DirectTag)
{
server.DirectUp = state.uplink / linkBase;
server.DirectDown = state.downlink / linkBase;
}
}
if (server.DirectDown < _serverSpeedItem.DirectDown || server.ProxyDown < _serverSpeedItem.ProxyDown)
{
_serverSpeedItem = new();
return null;
}
ServerSpeedItem curItem = new()
{
ProxyUp = server.ProxyUp - _serverSpeedItem.ProxyUp,
ProxyDown = server.ProxyDown - _serverSpeedItem.ProxyDown,
DirectUp = server.DirectUp - _serverSpeedItem.DirectUp,
DirectDown = server.DirectDown - _serverSpeedItem.DirectDown,
};
_serverSpeedItem = server;
return curItem;
}
catch
{
// ignored
}
return null;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace ServiceLib.Services
@@ -6,12 +6,10 @@ namespace ServiceLib.Services
public class UpdateService
{
private Action<bool, string>? _updateFunc;
private Config _config;
private int _timeout = 30;
public async Task CheckUpdateGuiN(Config config, Action<bool, string> updateFunc, bool preRelease)
{
_config = config;
_updateFunc = updateFunc;
var url = string.Empty;
var fileName = string.Empty;
@@ -53,7 +51,6 @@ namespace ServiceLib.Services
public async Task CheckUpdateCore(ECoreType type, Config config, Action<bool, string> updateFunc, bool preRelease)
{
_config = config;
_updateFunc = updateFunc;
var url = string.Empty;
var fileName = string.Empty;
@@ -108,13 +105,12 @@ namespace ServiceLib.Services
public async Task UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
_updateFunc?.Invoke(false, ResUI.MsgUpdateSubscriptionStart);
var subItem = await AppHandler.Instance.SubItems();
if (subItem == null || subItem.Count <= 0)
if (subItem is not { Count: > 0 })
{
_updateFunc?.Invoke(false, ResUI.MsgNoValidSubscription);
return;
@@ -122,11 +118,11 @@ namespace ServiceLib.Services
foreach (var item in subItem)
{
string id = item.Id.TrimEx();
string url = item.Url.TrimEx();
string userAgent = item.UserAgent.TrimEx();
string hashCode = $"{item.Remarks}->";
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || Utils.IsNotEmpty(subId) && item.Id != subId)
var id = item.Id.TrimEx();
var url = item.Url.TrimEx();
var userAgent = item.UserAgent.TrimEx();
var hashCode = $"{item.Remarks}->";
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (Utils.IsNotEmpty(subId) && item.Id != subId))
{
//_updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
continue;
@@ -219,7 +215,7 @@ namespace ServiceLib.Services
_updateFunc?.Invoke(false, $"{hashCode}{result}");
}
int ret = await ConfigHandler.AddBatchServers(config, result, id, true);
var ret = await ConfigHandler.AddBatchServers(config, result, id, true);
if (ret <= 0)
{
Logging.SaveLog("FailedImportSubscription");
@@ -231,6 +227,8 @@ namespace ServiceLib.Services
: $"{hashCode}{ResUI.MsgFailedImportSubscription}");
}
_updateFunc?.Invoke(false, "-------------------------------------------------------");
//await ConfigHandler.DedupServerList(config, id);
}
_updateFunc?.Invoke(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
@@ -452,7 +450,6 @@ namespace ServiceLib.Services
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
var geoUrl = string.IsNullOrEmpty(config?.ConstItem.GeoSourceUrl)
@@ -468,7 +465,6 @@ namespace ServiceLib.Services
private async Task UpdateSrsFileAll(Config config, Action<bool, string> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
var geoipFiles = new List<string>();
@@ -519,9 +515,9 @@ namespace ServiceLib.Services
private async Task UpdateSrsFile(string type, string srsName, Config config, Action<bool, string> updateFunc)
{
var srsUrl = string.IsNullOrEmpty(_config.ConstItem.SrsSourceUrl)
var srsUrl = string.IsNullOrEmpty(config.ConstItem.SrsSourceUrl)
? Global.SingboxRulesetUrl
: _config.ConstItem.SrsSourceUrl;
: config.ConstItem.SrsSourceUrl;
var fileName = $"{type}-{srsName}.srs";
var targetPath = Path.Combine(Utils.GetBinPath("srss"), fileName);

View File

@@ -12,10 +12,10 @@ namespace ServiceLib.ViewModels
{
private const string _geo = "GeoFiles";
private string _v2rayN = ECoreType.v2rayN.ToString();
private List<CheckUpdateItem> _lstUpdated = [];
private List<CheckUpdateModel> _lstUpdated = [];
private IObservableCollection<CheckUpdateItem> _checkUpdateItem = new ObservableCollectionExtended<CheckUpdateItem>();
public IObservableCollection<CheckUpdateItem> CheckUpdateItems => _checkUpdateItem;
private IObservableCollection<CheckUpdateModel> _checkUpdateModel = new ObservableCollectionExtended<CheckUpdateModel>();
public IObservableCollection<CheckUpdateModel> CheckUpdateModels => _checkUpdateModel;
public ReactiveCommand<Unit, Unit> CheckUpdateCmd { get; }
[Reactive] public bool EnableCheckPreReleaseUpdate { get; set; }
@@ -29,65 +29,56 @@ namespace ServiceLib.ViewModels
await CheckUpdate();
});
EnableCheckPreReleaseUpdate = _config.GuiItem.CheckPreReleaseUpdate;
EnableCheckPreReleaseUpdate = _config.CheckUpdateItem.CheckPreReleaseUpdate;
this.WhenAnyValue(
x => x.EnableCheckPreReleaseUpdate,
y => y == true)
.Subscribe(c => { _config.GuiItem.CheckPreReleaseUpdate = EnableCheckPreReleaseUpdate; });
.Subscribe(c => { _config.CheckUpdateItem.CheckPreReleaseUpdate = EnableCheckPreReleaseUpdate; });
RefreshSubItems();
RefreshCheckUpdateItems();
}
private void RefreshSubItems()
private void RefreshCheckUpdateItems()
{
_checkUpdateItem.Clear();
_checkUpdateModel.Clear();
if (RuntimeInformation.ProcessArchitecture != Architecture.X86)
{
_checkUpdateItem.Add(new CheckUpdateItem()
{
IsSelected = false,
CoreType = _v2rayN,
Remarks = ResUI.menuCheckUpdate,
});
_checkUpdateItem.Add(new CheckUpdateItem()
{
IsSelected = true,
CoreType = ECoreType.Xray.ToString(),
Remarks = ResUI.menuCheckUpdate,
});
_checkUpdateItem.Add(new CheckUpdateItem()
{
IsSelected = true,
CoreType = ECoreType.mihomo.ToString(),
Remarks = ResUI.menuCheckUpdate,
});
_checkUpdateItem.Add(new CheckUpdateItem()
{
IsSelected = true,
CoreType = ECoreType.sing_box.ToString(),
Remarks = ResUI.menuCheckUpdate,
});
_checkUpdateModel.Add(GetCheckUpdateModel(_v2rayN));
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.Xray.ToString()));
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.mihomo.ToString()));
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.sing_box.ToString()));
}
_checkUpdateModel.Add(GetCheckUpdateModel(_geo));
}
_checkUpdateItem.Add(new CheckUpdateItem()
private CheckUpdateModel GetCheckUpdateModel(string coreType)
{
return new()
{
IsSelected = true,
CoreType = _geo,
IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(coreType) ?? true,
CoreType = coreType,
Remarks = ResUI.menuCheckUpdate,
});
};
}
private async Task SaveSelectedCoreTypes()
{
_config.CheckUpdateItem.SelectedCoreTypes = _checkUpdateModel.Where(t => t.IsSelected == true).Select(t => t.CoreType ?? "").ToList();
await ConfigHandler.SaveConfig(_config);
}
private async Task CheckUpdate()
{
_lstUpdated.Clear();
_lstUpdated = _checkUpdateItem.Where(x => x.IsSelected == true)
.Select(x => new CheckUpdateItem() { CoreType = x.CoreType }).ToList();
_lstUpdated = _checkUpdateModel.Where(x => x.IsSelected == true)
.Select(x => new CheckUpdateModel() { CoreType = x.CoreType }).ToList();
await SaveSelectedCoreTypes();
for (var k = _checkUpdateItem.Count - 1; k >= 0; k--)
for (var k = _checkUpdateModel.Count - 1; k >= 0; k--)
{
var item = _checkUpdateItem[k];
var item = _checkUpdateModel[k];
if (item.IsSelected != true) continue;
UpdateView(item.CoreType, "...");
@@ -99,13 +90,13 @@ namespace ServiceLib.ViewModels
{
await CheckUpdateN(EnableCheckPreReleaseUpdate);
}
else if (item.CoreType == ECoreType.mihomo.ToString())
else if (item.CoreType == ECoreType.Xray.ToString())
{
await CheckUpdateCore(item, false);
await CheckUpdateCore(item, EnableCheckPreReleaseUpdate);
}
else
{
await CheckUpdateCore(item, EnableCheckPreReleaseUpdate);
await CheckUpdateCore(item, false);
}
}
@@ -161,23 +152,23 @@ namespace ServiceLib.ViewModels
});
}
private async Task CheckUpdateCore(CheckUpdateItem item, bool preRelease)
private async Task CheckUpdateCore(CheckUpdateModel model, bool preRelease)
{
void _updateUI(bool success, string msg)
{
UpdateView(item.CoreType, msg);
UpdateView(model.CoreType, msg);
if (success)
{
UpdateView(item.CoreType, ResUI.MsgUpdateV2rayCoreSuccessfullyMore);
UpdateView(model.CoreType, ResUI.MsgUpdateV2rayCoreSuccessfullyMore);
UpdatedPlusPlus(item.CoreType, msg);
UpdatedPlusPlus(model.CoreType, msg);
}
}
var type = (ECoreType)Enum.Parse(typeof(ECoreType), item.CoreType);
var type = (ECoreType)Enum.Parse(typeof(ECoreType), model.CoreType);
await (new UpdateService()).CheckUpdateCore(type, _config, _updateUI, preRelease)
.ContinueWith(t =>
{
UpdatedPlusPlus(item.CoreType, "");
UpdatedPlusPlus(model.CoreType, "");
});
}
@@ -276,7 +267,7 @@ namespace ServiceLib.ViewModels
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
foreach (var file in filesList)
{
await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType));
await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType.ToLower()));
}
}
@@ -291,7 +282,7 @@ namespace ServiceLib.ViewModels
private void UpdateView(string coreType, string msg)
{
var item = new CheckUpdateItem()
var item = new CheckUpdateModel()
{
CoreType = coreType,
Remarks = msg,
@@ -299,13 +290,13 @@ namespace ServiceLib.ViewModels
_updateView?.Invoke(EViewAction.DispatcherCheckUpdate, item);
}
public void UpdateViewResult(CheckUpdateItem item)
public void UpdateViewResult(CheckUpdateModel model)
{
var found = _checkUpdateItem.FirstOrDefault(t => t.CoreType == item.CoreType);
var found = _checkUpdateModel.FirstOrDefault(t => t.CoreType == model.CoreType);
if (found == null) return;
var itemCopy = JsonUtils.DeepCopy(found);
itemCopy.Remarks = item.Remarks;
_checkUpdateItem.Replace(found, itemCopy);
itemCopy.Remarks = model.Remarks;
_checkUpdateModel.Replace(found, itemCopy);
}
}
}

View File

@@ -1,4 +1,4 @@
using ReactiveUI;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Reactive;
@@ -105,7 +105,7 @@ namespace ServiceLib.ViewModels
item2.DomainStrategy4Freedom = domainStrategy4Freedom2;
item2.DomainDNSAddress = domainDNSAddress2;
item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(normalDNS2));
item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2)); ;
item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2));
await ConfigHandler.SaveDNSItems(_config, item2);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);

View File

@@ -219,6 +219,7 @@ namespace ServiceLib.ViewModels
await Reload();
await AutoHideStartup();
Locator.Current.GetService<StatusBarViewModel>()?.RefreshRoutingsMenu();
}
#endregion Init
@@ -266,7 +267,7 @@ namespace ServiceLib.ViewModels
try
{
Locator.Current.GetService<StatusBarViewModel>()?.UpdateStatistics(update);
if ((update.ProxyUp + update.ProxyDown) > 0 && DateTime.Now.Second % 3 == 0)
if ((update.ProxyUp + update.ProxyDown) > 0 && DateTime.Now.Second % 9 == 0)
{
Locator.Current.GetService<ProfilesViewModel>()?.UpdateStatistics(update);
}
@@ -289,7 +290,7 @@ namespace ServiceLib.ViewModels
await ProfileExHandler.Instance.SaveTo();
await StatisticsHandler.Instance.SaveTo();
StatisticsHandler.Instance.Close();
CoreHandler.Instance.CoreStop();
await CoreHandler.Instance.CoreStop();
Logging.SaveLog("MyAppExit End");
}
@@ -531,6 +532,10 @@ namespace ServiceLib.ViewModels
{
Utils.ProcessStart("nautilus", Utils.GetConfigPath());
}
else if (Utils.IsOSX())
{
Utils.ProcessStart("open", Utils.GetConfigPath());
}
}
#endregion Setting

View File

@@ -53,7 +53,7 @@ namespace ServiceLib.ViewModels
[Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; }
[Reactive] public bool EnableSecurityProtocolTls13 { get; set; }
[Reactive] public bool AutoHideStartup { get; set; }
[Reactive] public bool EnableCheckPreReleaseUpdate { get; set; }
[Reactive] public bool Hide2TrayWhenClose { get; set; }
[Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int AutoUpdateInterval { get; set; }
@@ -86,6 +86,7 @@ namespace ServiceLib.ViewModels
[Reactive] public int TunMtu { get; set; }
[Reactive] public bool TunEnableExInbound { get; set; }
[Reactive] public bool TunEnableIPv6Address { get; set; }
[Reactive] public string TunLinuxSudoPassword { get; set; }
#endregion Tun mode
@@ -166,7 +167,7 @@ namespace ServiceLib.ViewModels
EnableUpdateSubOnlyRemarksExist = _config.UiItem.EnableUpdateSubOnlyRemarksExist;
EnableSecurityProtocolTls13 = _config.GuiItem.EnableSecurityProtocolTls13;
AutoHideStartup = _config.UiItem.AutoHideStartup;
EnableCheckPreReleaseUpdate = _config.GuiItem.CheckPreReleaseUpdate;
Hide2TrayWhenClose = _config.UiItem.Hide2TrayWhenClose;
EnableDragDropSort = _config.UiItem.EnableDragDropSort;
DoubleClick2Activate = _config.UiItem.DoubleClick2Activate;
AutoUpdateInterval = _config.GuiItem.AutoUpdateInterval;
@@ -199,6 +200,7 @@ namespace ServiceLib.ViewModels
TunMtu = _config.TunModeItem.Mtu;
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
#endregion Tun mode
@@ -316,8 +318,8 @@ namespace ServiceLib.ViewModels
_config.UiItem.EnableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist;
_config.GuiItem.EnableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.UiItem.AutoHideStartup = AutoHideStartup;
_config.UiItem.Hide2TrayWhenClose = Hide2TrayWhenClose;
_config.GuiItem.AutoUpdateInterval = AutoUpdateInterval;
_config.GuiItem.CheckPreReleaseUpdate = EnableCheckPreReleaseUpdate;
_config.UiItem.EnableDragDropSort = EnableDragDropSort;
_config.UiItem.DoubleClick2Activate = DoubleClick2Activate;
_config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit;
@@ -343,20 +345,19 @@ namespace ServiceLib.ViewModels
_config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
{
_config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
}
//coreType
await SaveCoreType();
if (await ConfigHandler.SaveConfig(_config) == 0)
{
if (needReboot)
{
NoticeHandler.Instance.Enqueue(ResUI.NeedRebootTips);
}
else
{
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
}
await AutoStartupHandler.UpdateTask(_config);
NoticeHandler.Instance.Enqueue(needReboot ? ResUI.NeedRebootTips : ResUI.OperationSuccess);
_updateView?.Invoke(EViewAction.CloseWindow, null);
}
else

View File

@@ -16,7 +16,6 @@ namespace ServiceLib.ViewModels
private List<ProfileItem> _lstProfile;
private string _serverFilter = string.Empty;
private Dictionary<string, bool> _dicHeaderSort = new();
private SpeedtestService? _speedtestHandler;
#endregion private prop
@@ -480,7 +479,10 @@ namespace ServiceLib.ViewModels
await ConfigHandler.RemoveServer(_config, lstSelecteds);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
if (lstSelecteds.Count == _profileItems.Count)
{
_profileItems.Clear();
}
RefreshServers();
if (exists)
{
@@ -686,12 +688,12 @@ namespace ServiceLib.ViewModels
}
//ClearTestResult();
_speedtestHandler = new SpeedtestService(_config, lstSelecteds, actionType, UpdateSpeedtestHandler);
_ = new SpeedtestService(_config, lstSelecteds, actionType, UpdateSpeedtestHandler);
}
public void ServerSpeedtestStop()
{
_speedtestHandler?.ExitLoop();
MessageBus.Current.SendMessage("", EMsgCommand.StopSpeedtest.ToString());
}
private async Task Export2ClientConfigAsync(bool blClipboard)
@@ -727,7 +729,7 @@ namespace ServiceLib.ViewModels
{
return;
}
var result = await CoreConfigHandler.GenerateClientConfig(item, null);
var result = await CoreConfigHandler.GenerateClientConfig(item, fileName);
if (result.Success != true)
{
NoticeHandler.Instance.Enqueue(result.Msg);

View File

@@ -86,7 +86,7 @@ namespace ServiceLib.ViewModels
return;
}
//NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
_updateView?.Invoke(EViewAction.CloseWindow, null);
await _updateView?.Invoke(EViewAction.CloseWindow, null);
}
}
}

View File

@@ -108,7 +108,7 @@ namespace ServiceLib.ViewModels
SelectedServer = new();
RunningServerToolTipText = "-";
if (_config.TunModeItem.EnableTun && AppHandler.Instance.IsAdministrator)
if (_config.TunModeItem.EnableTun && AllowEnableTun())
{
EnableTun = true;
}
@@ -414,17 +414,37 @@ namespace ServiceLib.ViewModels
{
_config.TunModeItem.EnableTun = EnableTun;
// When running as a non-administrator, reboot to administrator mode
if (EnableTun && !AppHandler.Instance.IsAdministrator)
if (EnableTun && AllowEnableTun() == false)
{
_config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return;
if (Utils.IsWindows())
{
_config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return;
}
//else if (Utils.IsLinux())
//{
// NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
//}
}
await ConfigHandler.SaveConfig(_config);
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
}
}
private bool AllowEnableTun()
{
if (Utils.IsWindows())
{
return AppHandler.Instance.IsAdministrator;
}
else if (Utils.IsLinux())
{
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
}
return false;
}
#endregion System proxy and Routings
#region UI

View File

@@ -9,8 +9,6 @@ namespace v2rayN.Desktop;
public partial class App : Application
{
//public static EventWaitHandle ProgramStarted;
public override void Initialize()
{
if (!AppHandler.Instance.InitApp())
@@ -32,7 +30,7 @@ public partial class App : Application
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
OnStartup(desktop.Args);
AppHandler.Instance.InitComponents();
desktop.Exit += OnExit;
desktop.MainWindow = new MainWindow();
@@ -41,22 +39,6 @@ public partial class App : Application
base.OnFrameworkInitializationCompleted();
}
private void OnStartup(string[]? Args)
{
var exePathKey = Utils.GetMd5(Utils.GetExePath());
var rebootas = (Args ?? new string[] { }).Any(t => t == Global.RebootAs);
//ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
//if (!rebootas && !bCreatedNew)
//{
// ProgramStarted.Set();
// Environment.Exit(0);
// return;
//}
AppHandler.Instance.InitComponents();
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject != null)
@@ -87,11 +69,12 @@ public partial class App : Application
}
}
private void MenuExit_Click(object? sender, EventArgs e)
private async void MenuExit_Click(object? sender, EventArgs e)
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
Locator.Current.GetService<MainWindowViewModel>()?.MyAppExitAsync(false);
var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null) await service.MyAppExitAsync(false);
desktop.Shutdown();
}

View File

@@ -0,0 +1,19 @@
using Avalonia;
using Avalonia.Media;
using System.Reflection;
namespace v2rayN.Desktop.Common
{
public static class AppBuilderExtension
{
public static AppBuilder WithFontByDefault(this AppBuilder appBuilder)
{
var uri = $"avares://{Assembly.GetExecutingAssembly().GetName().Name}/Assets/Fonts#Noto Sans SC";
return appBuilder.With(new FontManagerOptions()
{
DefaultFamilyName = uri,
FontFallbacks = new[] { new FontFallback { FontFamily = new FontFamily(uri) } }
});
}
}
}

View File

@@ -1,22 +1,56 @@
using Avalonia;
using Avalonia;
using Avalonia.ReactiveUI;
using v2rayN.Desktop.Common;
namespace v2rayN.Desktop;
internal class Program
{
public static EventWaitHandle ProgramStarted;
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static void Main(string[] args)
{
OnStartup(args);
BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
}
private static void OnStartup(string[]? Args)
{
if (Utils.IsWindows())
{
var exePathKey = Utils.GetMd5(Utils.GetExePath());
var rebootas = (Args ?? Array.Empty<string>()).Any(t => t == Global.RebootAs);
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
if (!rebootas && !bCreatedNew)
{
ProgramStarted.Set();
Environment.Exit(0);
return;
}
}
else
{
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
if (!bOnlyOneInstance)
{
Environment.Exit(0);
return;
}
}
}
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
//.WithInterFont()
.WithFontByDefault()
.LogToTrace()
.UseReactiveUI();
}

View File

@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Notifications;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
using Avalonia.Styling;
@@ -94,6 +95,7 @@ namespace v2rayN.Desktop.ViewModels
x.OfType<TextBox>(),
x.OfType<TextBlock>(),
x.OfType<Menu>(),
x.OfType<ContextMenu>(),
x.OfType<DataGridRow>(),
x.OfType<ListBoxItem>()
));
@@ -120,8 +122,10 @@ namespace v2rayN.Desktop.ViewModels
x.OfType<TextBox>(),
x.OfType<TextBlock>(),
x.OfType<Menu>(),
x.OfType<ContextMenu>(),
x.OfType<DataGridRow>(),
x.OfType<ListBoxItem>()
x.OfType<ListBoxItem>(),
x.OfType<WindowNotificationManager>()
));
style.Add(new Setter()
{

View File

@@ -112,7 +112,7 @@
x:Name="txtPort"
Grid.Row="3"
Grid.Column="1"
Width="100"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8" />
</Grid>
@@ -164,7 +164,7 @@
x:Name="txtAlterId"
Grid.Row="2"
Grid.Column="1"
Width="100"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8" />
@@ -458,7 +458,7 @@
x:Name="cmbHeaderType8"
Grid.Row="3"
Grid.Column="1"
Width="100"
Width="200"
Classes="Margin8" />
</Grid>
<Grid
@@ -541,7 +541,7 @@
x:Name="txtShortId9"
Grid.Row="5"
Grid.Column="1"
Width="100"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8" />
</Grid>
@@ -584,7 +584,7 @@
x:Name="cmbNetwork"
Grid.Row="1"
Grid.Column="1"
Width="100"
Width="200"
Classes="Margin8" />
<TextBlock
Grid.Row="1"
@@ -600,12 +600,50 @@
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbHeaderType}" />
<ComboBox
x:Name="cmbHeaderType"
<StackPanel
Grid.Row="2"
Grid.Column="1"
Width="100"
Classes="Margin8" />
VerticalAlignment="Center"
Orientation="Horizontal">
<ComboBox
x:Name="cmbHeaderType"
Width="200"
Classes="Margin8" />
<Button
x:Name="btnExtra"
Width="30"
Height="30"
Margin="10,0"
Theme="{DynamicResource BorderlessButton}">
<Button.Content>
<PathIcon
Width="20"
Height="20"
Data="{StaticResource building_more}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TransportExtraTip}" />
<TextBox
x:Name="txtExtra"
Width="400"
MinHeight="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Classes="TextArea Margin8"
MinLines="6"
TextWrapping="Wrap" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
<TextBlock
x:Name="tipHeaderType"
Grid.Row="2"
@@ -680,7 +718,7 @@
x:Name="cmbStreamSecurity"
Grid.Row="0"
Grid.Column="1"
Width="100"
Width="200"
Classes="Margin8" />
</Grid>
<Grid
@@ -749,7 +787,7 @@
x:Name="cmbAllowInsecure"
Grid.Row="4"
Grid.Column="1"
Width="100"
Width="200"
Classes="Margin8" />
</Grid>
<Grid

View File

@@ -208,7 +208,8 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Extra, v => v.txtExtra.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.SelectedValue).DisposeWith(disposables);
@@ -299,6 +300,13 @@ namespace v2rayN.Desktop.Views
cmbHeaderType.Items.Add(it);
});
}
else if (network is nameof(ETransport.splithttp) or nameof(ETransport.xhttp))
{
Global.XhttpMode.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
}
else if (network == nameof(ETransport.grpc))
{
cmbHeaderType.Items.Add(Global.GrpcGunMode);
@@ -319,6 +327,7 @@ namespace v2rayN.Desktop.Views
network = Global.DefaultNetwork;
}
labHeaderType.IsVisible = true;
btnExtra.IsVisible = false;
tipRequestHost.Text =
tipPath.Text =
tipHeaderType.Text = string.Empty;
@@ -337,11 +346,19 @@ namespace v2rayN.Desktop.Views
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
break;
case nameof(ETransport.splithttp):
case nameof(ETransport.xhttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip5;
labHeaderType.IsVisible = false;
btnExtra.IsVisible = true;
break;
case nameof(ETransport.h2):
tipRequestHost.Text = ResUI.TransportRequestHostTip3;
tipPath.Text = ResUI.TransportPathTip2;

View File

@@ -39,7 +39,7 @@
<ListBox
x:Name="lstCheckUpdates"
BorderThickness="1"
ItemsSource="{Binding CheckUpdateItems}">
ItemsSource="{Binding CheckUpdateModels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
@@ -50,7 +50,7 @@
<Border
Width="500"
Height="80"
Margin="0"
Margin="-2"
VerticalAlignment="Center"
Theme="{StaticResource CardBorder}">
<Grid>

View File

@@ -15,7 +15,7 @@ namespace v2rayN.Desktop.Views
this.WhenActivated(disposables =>
{
this.OneWayBind(ViewModel, vm => vm.CheckUpdateItems, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.CheckUpdateModels, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CheckUpdateCmd, v => v.btnCheckUpdate).DisposeWith(disposables);
@@ -29,7 +29,7 @@ namespace v2rayN.Desktop.Views
case EViewAction.DispatcherCheckUpdate:
if (obj is null) return false;
Dispatcher.UIThread.Post(() =>
ViewModel?.UpdateViewResult((CheckUpdateItem)obj),
ViewModel?.UpdateViewResult((CheckUpdateModel)obj),
DispatcherPriority.Default);
break;

View File

@@ -114,7 +114,7 @@
<MenuItem x:Name="menuClose" Padding="8,0">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Static resx:ResUI.menuClose}" />
<TextBlock Text="{x:Static resx:ResUI.menuExit}" />
</StackPanel>
</MenuItem.Header>
</MenuItem>

View File

@@ -7,9 +7,9 @@ using Avalonia.Interactivity;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
using DialogHostAvalonia;
using MsBox.Avalonia.Enums;
using ReactiveUI;
using Splat;
using System.ComponentModel;
using System.Reactive.Disposables;
using v2rayN.Desktop.Common;
@@ -29,15 +29,12 @@ namespace v2rayN.Desktop.Views
_config = AppHandler.Instance.Config;
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.BottomRight };
//ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
this.Closing += MainWindow_Closing;
this.KeyDown += MainWindow_KeyDown;
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
menuPromotion.Click += menuPromotion_Click;
menuClose.Click += menuClose_Click;
menuCheckUpdate.Click += MenuCheckUpdate_Click;
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
menuClose.Click += MenuClose_Click;
MessageBus.Current.Listen<string>(EMsgCommand.SendSnackMsg.ToString()).Subscribe(DelegateSnackMsg);
ViewModel = new MainWindowViewModel(UpdateViewHandler);
@@ -114,10 +111,17 @@ namespace v2rayN.Desktop.Views
this.Title = $"{Utils.GetVersion()} - {(AppHandler.Instance.IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
if (Utils.IsWindows())
{
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
menuGlobalHotkeySetting.IsVisible = false;
}
else
{
if (AppHandler.Instance.IsAdministrator)
{
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
}
menuRebootAsAdmin.IsVisible = false;
menuSettingsSetUWP.IsVisible = false;
menuGlobalHotkeySetting.IsVisible = false;
@@ -158,7 +162,9 @@ namespace v2rayN.Desktop.Views
private void OnProgramStarted(object state, bool timeout)
{
ShowHideWindow(true);
Dispatcher.UIThread.Post(() =>
ShowHideWindow(true),
DispatcherPriority.Default);
}
private void DelegateSnackMsg(string content)
@@ -271,10 +277,23 @@ namespace v2rayN.Desktop.Views
}
}
private void MainWindow_Closing(object? sender, CancelEventArgs e)
protected override async void OnClosing(WindowClosingEventArgs e)
{
e.Cancel = true;
ShowHideWindow(false);
Logging.SaveLog("OnClosing -> " + e.CloseReason.ToString());
switch (e.CloseReason)
{
case WindowCloseReason.OwnerWindowClosing or WindowCloseReason.WindowClosing:
e.Cancel = true;
ShowHideWindow(false);
break;
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
await ViewModel?.MyAppExitAsync(true);
break;
}
base.OnClosing(e);
}
private async void MainWindow_KeyDown(object? sender, KeyEventArgs e)
@@ -302,12 +321,6 @@ namespace v2rayN.Desktop.Views
}
}
private void menuClose_Click(object? sender, RoutedEventArgs e)
{
StorageUI();
ShowHideWindow(false);
}
private void menuPromotion_Click(object? sender, RoutedEventArgs e)
{
Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}");
@@ -355,10 +368,21 @@ namespace v2rayN.Desktop.Views
DialogHost.Show(_backupAndRestoreView);
}
private async void MenuClose_Click(object? sender, RoutedEventArgs e)
{
if (await UI.ShowYesNo(this, ResUI.menuExitTips) == ButtonResult.No)
{
return;
}
StorageUI();
await ViewModel?.MyAppExitAsync(false);
}
#endregion Event
#region UI
public void ShowHideWindow(bool? blShow)
{
var bl = blShow ?? !_config.UiItem.ShowInTaskbar;
@@ -374,8 +398,16 @@ namespace v2rayN.Desktop.Views
}
else
{
this.Hide();
if (_config.UiItem.Hide2TrayWhenClose)
{
this.Hide();
}
else
{
this.WindowState = WindowState.Minimized;
}
}
_config.UiItem.ShowInTaskbar = bl;
}

View File

@@ -83,6 +83,7 @@
Classes="TextArea"
IsReadOnly="True"
TextAlignment="Left"
VerticalAlignment="Stretch"
TextWrapping="Wrap">
<TextBox.ContextMenu>
<ContextMenu>

View File

@@ -377,7 +377,7 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--
<TextBlock
Grid.Row="1"
Grid.Column="0"
@@ -390,7 +390,8 @@
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
<!--
<TextBlock
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Center"
@@ -493,14 +494,15 @@
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsEnableCheckPreReleaseUpdate}" />
Text="{x:Static resx:ResUI.TbSettingsHide2TrayWhenClose}" />
<ToggleSwitch
x:Name="togEnableCheckPreReleaseUpdate"
x:Name="togHide2TrayWhenClose"
Grid.Row="9"
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
Grid.Row="11"
Grid.Column="0"
@@ -731,6 +733,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -804,6 +807,27 @@
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
<TextBox
x:Name="txtLinuxSudoPassword"
Grid.Row="7"
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
Grid.Row="7"
Grid.Column="2"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
TextWrapping="Wrap" />
</Grid>
</DockPanel>
</TabItem>

View File

@@ -123,7 +123,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.hyDownMbps, v => v.txtDownMbps.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.enableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableStatistics, v => v.togEnableStatistics.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.KeepOlderDedupl, v => v.togKeepOlderDedupl.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.IgnoreGeoUpdateCore, v => v.togIgnoreGeoUpdateCore.IsChecked).DisposeWith(disposables);
@@ -131,7 +131,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.EnableUpdateSubOnlyRemarksExist, v => v.togEnableUpdateSubOnlyRemarksExist.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.SelectedValue).DisposeWith(disposables);
@@ -153,6 +153,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
@@ -175,7 +176,6 @@ namespace v2rayN.Desktop.Views
switch (action)
{
case EViewAction.CloseWindow:
// WindowsUtils.SetAutoRun(Global.AutoRunRegPath, Global.AutoRunName, togAutoRun.IsChecked ?? false);
this.Close(true);
break;

View File

@@ -61,6 +61,7 @@
Width="54"
Height="30"
Margin="20,0"
Padding="2"
Classes="Tertiary"
Theme="{DynamicResource BorderlessSplitButton}"
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
@@ -204,7 +205,7 @@
Binding="{Binding SubRemarks}"
Header="{x:Static resx:ResUI.LvSubscription}"
Tag="SubRemarks" />
<DataGridTemplateColumn SortMemberPath="Delay" Tag="Delay">
<DataGridTemplateColumn SortMemberPath="Delay" Tag="DelayVal">
<DataGridTemplateColumn.Header>
<TextBlock Text="{x:Static resx:ResUI.LvTestDelay}" />
</DataGridTemplateColumn.Header>

View File

@@ -32,6 +32,7 @@ namespace v2rayN.Desktop.Views
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
lstProfiles.DoubleTapped += LstProfiles_DoubleTapped;
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
lstProfiles.Sorting += LstProfiles_Sorting;
//if (_config.uiItem.enableDragDropSort)
//{
// lstProfiles.AllowDrop = true;
@@ -92,6 +93,13 @@ namespace v2rayN.Desktop.Views
ViewModel?.RefreshServers();
}
private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
{
e.Handled = true;
await ViewModel?.SortServer(e.Column.Tag.ToString());
e.Handled = false;
}
//#region Event
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
@@ -189,6 +197,8 @@ namespace v2rayN.Desktop.Views
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
{
var source = e.Source as Border;
if (source?.Name == "HeaderBackground") return;
if (_config.UiItem.DoubleClick2Activate)
{
ViewModel?.SetDefaultServer();
@@ -343,10 +353,10 @@ namespace v2rayN.Desktop.Views
}
else
{
item2.Width = new DataGridLength(item.Width, DataGridLengthUnitType.Pixel); ;
item2.Width = new DataGridLength(item.Width, DataGridLengthUnitType.Pixel);
item2.DisplayIndex = displayIndex++;
}
if (item.Name.StartsWith("to"))
if (item.Name.ToLower().StartsWith("to"))
{
if (!_config.GuiItem.EnableStatistics)
{

View File

@@ -43,11 +43,11 @@ namespace v2rayN.Desktop.Views
{
rulesItem.Protocol?.ForEach(it =>
{
clbProtocol.SelectedItems.Add(it);
clbProtocol?.SelectedItems?.Add(it);
});
rulesItem.InboundTag?.ForEach(it =>
{
clbInboundTag.SelectedItems.Add(it);
clbInboundTag?.SelectedItems?.Add(it);
});
}

View File

@@ -41,7 +41,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables);
});
spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
//spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
}
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View File

@@ -52,6 +52,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -94,6 +95,41 @@
Classes="Margin8"
TextWrapping="Wrap"
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
<Button
Grid.Row="2"
Grid.Column="2"
Width="30"
Height="30"
Margin="10,0"
Theme="{DynamicResource BorderlessButton}">
<Button.Content>
<PathIcon
Width="20"
Height="20"
Data="{StaticResource building_more}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvMoreUrl}" />
<TextBox
x:Name="txtMoreUrl"
Width="400"
MinHeight="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Classes="TextArea Margin8"
MinLines="4"
TextWrapping="Wrap"
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<TextBlock
Grid.Row="3"
@@ -114,7 +150,7 @@
<TextBox
x:Name="txtAutoUpdateInterval"
Width="200"
Width="100"
VerticalAlignment="Center"
Classes="Margin8"
DockPanel.Dock="Right"
@@ -233,21 +269,17 @@
<TextBlock
Grid.Row="12"
Grid.Column="0"
Grid.ColumnSpan="2"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvMoreUrl}" />
Text="{x:Static resx:ResUI.LvMemo}" />
<TextBox
x:Name="txtMoreUrl"
Grid.Row="13"
x:Name="txtMemo"
Grid.Row="12"
Grid.Column="1"
MinHeight="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Classes="TextArea Margin8"
MinLines="4"
TextWrapping="Wrap"
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
Classes="Margin8"
TextWrapping="Wrap" />
</Grid>
</ScrollViewer>
</DockPanel>

View File

@@ -41,6 +41,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.SelectedSource.PrevProfile, v => v.txtPrevProfile.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.NextProfile, v => v.txtNextProfile.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.PreSocksPort, v => v.txtPreSocksPort.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Memo, v => v.txtMemo.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
});

View File

@@ -20,16 +20,16 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.1.4" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.1.4" />
<PackageReference Include="Avalonia.Desktop" Version="11.1.4" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.1.4" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.4" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.1.4" />
<PackageReference Include="Avalonia" Version="11.2.1" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.1" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.1" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.1" />
<PackageReference Include="DialogHost.Avalonia" Version="0.8.1" />
<PackageReference Include="MessageBox.Avalonia" Version="3.1.6.13" />
<PackageReference Include="Semi.Avalonia" Version="11.1.0.4" />
<PackageReference Include="Semi.Avalonia.DataGrid" Version="11.1.0.4" />
<PackageReference Include="MessageBox.Avalonia" Version="3.2.0" />
<PackageReference Include="Semi.Avalonia" Version="11.2.1" />
<PackageReference Include="Semi.Avalonia.DataGrid" Version="11.2.1" />
<PackageReference Include="ReactiveUI" Version="20.1.63" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
</ItemGroup>

View File

@@ -1,9 +1,9 @@
<Application
x:Class="v2rayN.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
ShutdownMode="OnExplicitShutdown"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
@@ -211,6 +211,11 @@
<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="TextOptions.TextRenderingMode" Value="ClearType" />
<Setter Property="TextOptions.TextHintingMode" Value="Fixed" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource MaterialDesignBody}" />
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
<Setter Property="TextElement.FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
<Setter Property="ResizeMode" Value="NoResize" />
</Style>
<Style
x:Key="ViewGlobal"
@@ -219,6 +224,10 @@
<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="TextOptions.TextRenderingMode" Value="ClearType" />
<Setter Property="TextOptions.TextHintingMode" Value="Fixed" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource MaterialDesignBody}" />
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
<Setter Property="TextElement.FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
</Style>
</ResourceDictionary>
</Application.Resources>

View File

@@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
@@ -28,7 +28,7 @@ namespace v2rayN
{
var exePathKey = Utils.GetMd5(Utils.GetExePath());
var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs);
var rebootas = (e.Args ?? Array.Empty<string>()).Any(t => t == Global.RebootAs);
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
if (!rebootas && !bCreatedNew)
{

View File

@@ -1,13 +1,9 @@
using Microsoft.Win32;
using Microsoft.Win32.TaskScheduler;
using System.Diagnostics;
using System.Drawing;
using System.IO;
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;
@@ -55,49 +51,6 @@ namespace v2rayN
}
}
/// <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);
}
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize);
@@ -116,58 +69,6 @@ namespace v2rayN
return value is int i && i > 0;
}
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 (Utils.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 (Utils.IsNullOrEmpty(value.ToString()))
{
regKey?.DeleteValue(name, false);
}
else
{
regKey?.SetValue(name, value);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
}
public static void RemoveTunDevice()
{
try
@@ -209,42 +110,6 @@ namespace v2rayN
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize);
}
/// <summary>
/// 开机自动启动
/// </summary>
/// <param name="run"></param>
/// <returns></returns>
public static void SetAutoRun(string AutoRunRegPath, string AutoRunName, bool run)
{
try
{
var autoRunName = $"{AutoRunName}_{Utils.GetMd5(Utils.StartupPath())}";
//delete first
RegWriteValue(AutoRunRegPath, autoRunName, "");
if (Utils.IsAdministrator())
{
AutoStart(autoRunName, "", "");
}
if (run)
{
string exePath = Utils.GetExePath();
if (Utils.IsAdministrator())
{
AutoStart(autoRunName, exePath, "");
}
else
{
RegWriteValue(AutoRunRegPath, autoRunName, exePath.AppendQuotes());
}
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
#region Windows API
[Flags]

View File

@@ -2,7 +2,6 @@
x:Class="v2rayN.Views.AddServer2Window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,13 +12,8 @@
Width="700"
Height="500"
x:TypeArguments="vms:AddServer2ViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
Style="{StaticResource WindowGlobal}"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<DockPanel Margin="{StaticResource Margin8}">

View File

@@ -2,7 +2,6 @@
x:Class="v2rayN.Views.AddServerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,15 +12,18 @@
Width="900"
Height="700"
x:TypeArguments="vms:AddServerViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="CanResize"
ShowInTaskbar="False"
Style="{StaticResource WindowGlobal}"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<DockPanel Margin="{StaticResource Margin8}">
<StackPanel
Margin="{StaticResource Margin4}"
@@ -133,7 +135,7 @@
x:Name="txtPort"
Grid.Row="3"
Grid.Column="1"
Width="100"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
@@ -193,7 +195,7 @@
x:Name="txtAlterId"
Grid.Row="2"
Grid.Column="1"
Width="100"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
@@ -518,7 +520,7 @@
x:Name="cmbHeaderType8"
Grid.Row="3"
Grid.Column="1"
Width="100"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
</Grid>
@@ -611,7 +613,7 @@
x:Name="txtShortId9"
Grid.Row="5"
Grid.Column="1"
Width="100"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
@@ -658,7 +660,7 @@
x:Name="cmbNetwork"
Grid.Row="1"
Grid.Column="1"
Width="100"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
<TextBlock
@@ -677,13 +679,40 @@
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbHeaderType}" />
<ComboBox
x:Name="cmbHeaderType"
<StackPanel
Grid.Row="2"
Grid.Column="1"
Width="100"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
VerticalAlignment="Center"
Orientation="Horizontal">
<ComboBox
x:Name="cmbHeaderType"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
<materialDesign:PopupBox
x:Name="popExtra"
HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
<StackPanel>
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TransportExtraTip}" />
<TextBox
x:Name="txtExtra"
Width="400"
Margin="{StaticResource Margin4}"
VerticalAlignment="Top"
AcceptsReturn="True"
MinLines="6"
Style="{StaticResource MyOutlinedTextBox}"
TextWrapping="Wrap" />
</StackPanel>
</materialDesign:PopupBox>
</StackPanel>
<TextBlock
x:Name="tipHeaderType"
Grid.Row="2"
@@ -769,7 +798,7 @@
x:Name="cmbStreamSecurity"
Grid.Row="0"
Grid.Column="1"
Width="100"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
</Grid>
@@ -847,7 +876,7 @@
x:Name="cmbAllowInsecure"
Grid.Row="4"
Grid.Column="1"
Width="100"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
</Grid>

View File

@@ -202,7 +202,8 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Extra, v => v.txtExtra.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables);
@@ -294,6 +295,13 @@ namespace v2rayN.Views
cmbHeaderType.Items.Add(it);
});
}
else if (network is nameof(ETransport.splithttp) or nameof(ETransport.xhttp))
{
Global.XhttpMode.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
}
else if (network == nameof(ETransport.grpc))
{
cmbHeaderType.Items.Add(Global.GrpcGunMode);
@@ -314,6 +322,7 @@ namespace v2rayN.Views
network = Global.DefaultNetwork;
}
labHeaderType.Visibility = Visibility.Visible;
popExtra.Visibility = Visibility.Hidden;
tipRequestHost.Text =
tipPath.Text =
tipHeaderType.Text = string.Empty;
@@ -332,11 +341,19 @@ namespace v2rayN.Views
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
break;
case nameof(ETransport.splithttp):
case nameof(ETransport.xhttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip5;
labHeaderType.Visibility = Visibility.Hidden;
popExtra.Visibility = Visibility.Visible;
break;
case nameof(ETransport.h2):
tipRequestHost.Text = ResUI.TransportRequestHostTip3;
tipPath.Text = ResUI.TransportPathTip2;

View File

@@ -119,7 +119,6 @@
Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
<materialDesign:PopupBox
Padding="8,0"
HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">

View File

@@ -15,7 +15,7 @@ namespace v2rayN.Views
this.WhenActivated(disposables =>
{
this.OneWayBind(ViewModel, vm => vm.CheckUpdateItems, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.CheckUpdateModels, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CheckUpdateCmd, v => v.btnCheckUpdate).DisposeWith(disposables);
@@ -30,7 +30,7 @@ namespace v2rayN.Views
if (obj is null) return false;
Application.Current?.Dispatcher.Invoke((() =>
{
ViewModel?.UpdateViewResult((CheckUpdateItem)obj);
ViewModel?.UpdateViewResult((CheckUpdateModel)obj);
}), DispatcherPriority.Normal);
break;

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ClashConnectionsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
d:DesignHeight="450"

View File

@@ -1,14 +1,14 @@
<reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ClashProxiesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
xmlns:converters="clr-namespace:v2rayN.Converters"
d:DesignHeight="450"
d:DesignWidth="800"
x:TypeArguments="vms:ClashProxiesViewModel"

View File

@@ -2,7 +2,6 @@
x:Class="v2rayN.Views.DNSSettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,13 +12,8 @@
Width="1000"
Height="700"
x:TypeArguments="vms:DNSSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
Style="{StaticResource WindowGlobal}"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<DockPanel Margin="{StaticResource Margin8}">

View File

@@ -2,7 +2,6 @@
x:Class="v2rayN.Views.GlobalHotkeySettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,14 +12,9 @@
Width="700"
Height="500"
x:TypeArguments="vms:SubEditViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
KeyDown="GlobalHotkeySettingWindow_KeyDown"
ResizeMode="NoResize"
ShowInTaskbar="False"
Style="{StaticResource WindowGlobal}"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<DockPanel Margin="{StaticResource Margin8}">

View File

@@ -2,7 +2,6 @@
x:Class="v2rayN.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -15,12 +14,9 @@
Height="700"
MinWidth="900"
x:TypeArguments="vms:MainWindowViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="True"
Style="{StaticResource WindowGlobal}"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.Resources>
@@ -281,7 +277,7 @@
</Menu>
<materialDesign:PopupBox
Padding="8,0"
Padding="-2"
HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">

View File

@@ -270,11 +270,11 @@ namespace v2rayN.Views
StorageUI();
}
private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e)
private async void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e)
{
Logging.SaveLog("Current_SessionEnding");
StorageUI();
ViewModel?.MyAppExitAsync(true);
await ViewModel?.MyAppExitAsync(true);
}
private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
@@ -367,17 +367,17 @@ namespace v2rayN.Views
var bl = blShow ?? !_config.UiItem.ShowInTaskbar;
if (bl)
{
Application.Current.MainWindow.Show();
if (Application.Current.MainWindow.WindowState == WindowState.Minimized)
this?.Show();
if (this?.WindowState == WindowState.Minimized)
{
Application.Current.MainWindow.WindowState = WindowState.Normal;
this.WindowState = WindowState.Normal;
}
Application.Current.MainWindow.Activate();
Application.Current.MainWindow.Focus();
this?.Activate();
this?.Focus();
}
else
{
Application.Current.MainWindow.Hide();
this?.Hide();
}
_config.UiItem.ShowInTaskbar = bl;
}

View File

@@ -69,6 +69,8 @@
</WrapPanel>
<TextBox
Name="txtMsg"
VerticalAlignment="Stretch"
AcceptsReturn="True"
BorderThickness="0"
FontSize="{DynamicResource StdFontSize-1}"
HorizontalScrollBarVisibility="Auto"

View File

@@ -2,7 +2,6 @@
x:Class="v2rayN.Views.OptionSettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,13 +12,8 @@
Width="1000"
Height="700"
x:TypeArguments="vms:OptionSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
Style="{StaticResource WindowGlobal}"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<DockPanel Margin="{StaticResource Margin8}">
@@ -661,20 +655,6 @@
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="9"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsEnableCheckPreReleaseUpdate}" />
<ToggleButton
x:Name="togEnableCheckPreReleaseUpdate"
Grid.Row="9"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="10"
Grid.Column="0"

View File

@@ -141,7 +141,6 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.EnableUpdateSubOnlyRemarksExist, v => v.togEnableUpdateSubOnlyRemarksExist.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableDragDropSort, v => v.togEnableDragDropSort.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
@@ -184,7 +183,6 @@ namespace v2rayN.Views
switch (action)
{
case EViewAction.CloseWindow:
WindowsUtils.SetAutoRun(Global.AutoRunRegPath, Global.AutoRunName, togAutoRun.IsChecked ?? false);
this.DialogResult = true;
break;

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