diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fb66bdc4..9e566754 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,13 +18,13 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: 删除工作流运行 - uses: Mattraks/delete-workflow-runs@v2 - with: - token: ${{ github.token }} - repository: ${{ github.repository }} - retain_days: 0 - keep_minimum_runs: 1 + # - name: 删除工作流运行 + # uses: Mattraks/delete-workflow-runs@v2 + # with: + # token: ${{ github.token }} + # repository: ${{ github.repository }} + # retain_days: 0 + # keep_minimum_runs: 1 - name: Build run: cd v2rayN && @@ -36,13 +36,12 @@ jobs: # 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory - name: Upload build artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: v2rayN - path: + path: | .\v2rayN\v2rayN.zip - # - name: Release # uses: softprops/action-gh-release@v1 # env: @@ -58,4 +57,4 @@ jobs: # * This is an automated deployment of GitHub Actions, the change log should be updated manually soon # ## 更新日志 - # * 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新 \ No newline at end of file + # * 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新 diff --git a/v2rayN/PacLib/PacLib.csproj b/v2rayN/PacLib/PacLib.csproj index ed5be34b..feb6e55d 100644 --- a/v2rayN/PacLib/PacLib.csproj +++ b/v2rayN/PacLib/PacLib.csproj @@ -1,7 +1,7 @@  - net6.0-windows + net8.0 enable diff --git a/v2rayN/ProtosLib/ProtosLib.csproj b/v2rayN/ProtosLib/ProtosLib.csproj index 3beb2fef..74f5428d 100644 --- a/v2rayN/ProtosLib/ProtosLib.csproj +++ b/v2rayN/ProtosLib/ProtosLib.csproj @@ -1,6 +1,6 @@  - net6.0-windows + net8.0 enable @@ -9,9 +9,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/v2rayN/v2rayN/App.xaml b/v2rayN/v2rayN/App.xaml index 3fc23de2..e9c027a0 100644 --- a/v2rayN/v2rayN/App.xaml +++ b/v2rayN/v2rayN/App.xaml @@ -34,6 +34,12 @@ Left="8" Right="8" Top="8" /> + + \ No newline at end of file diff --git a/v2rayN/v2rayN/App.xaml.cs b/v2rayN/v2rayN/App.xaml.cs index caa6570c..78199e70 100644 --- a/v2rayN/v2rayN/App.xaml.cs +++ b/v2rayN/v2rayN/App.xaml.cs @@ -2,7 +2,6 @@ using System.Windows.Threading; using v2rayN.Handler; using v2rayN.Mode; -using v2rayN.Tool; namespace v2rayN { @@ -28,10 +27,10 @@ namespace v2rayN /// protected override void OnStartup(StartupEventArgs e) { - Global.ExePathKey = Utils.GetMD5(Utils.GetExePath()); + var exePathKey = Utils.GetMD5(Utils.GetExePath()); var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs); - ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Global.ExePathKey, out bool bCreatedNew); + ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew); if (!rebootas && !bCreatedNew) { ProgramStarted.Set(); @@ -40,12 +39,10 @@ namespace v2rayN return; } - Global.ProcessJob = new Job(); - Logging.Setup(); Init(); Logging.LoggingEnabled(_config.guiItem.enableLog); - Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}"); + Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}"); Logging.ClearLogs(); Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage); @@ -70,7 +67,7 @@ namespace v2rayN private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { - Utils.SaveLog("App_DispatcherUnhandledException", e.Exception); + Logging.SaveLog("App_DispatcherUnhandledException", e.Exception); e.Handled = true; } @@ -78,13 +75,13 @@ namespace v2rayN { if (e.ExceptionObject != null) { - Utils.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!); + Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!); } } private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) { - Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception); + Logging.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception); } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Base/DownloaderHelper.cs b/v2rayN/v2rayN/Common/DownloaderHelper.cs similarity index 99% rename from v2rayN/v2rayN/Base/DownloaderHelper.cs rename to v2rayN/v2rayN/Common/DownloaderHelper.cs index 51a7840b..21e16535 100644 --- a/v2rayN/v2rayN/Base/DownloaderHelper.cs +++ b/v2rayN/v2rayN/Common/DownloaderHelper.cs @@ -2,7 +2,7 @@ using System.IO; using System.Net; -namespace v2rayN.Base +namespace v2rayN { internal class DownloaderHelper { diff --git a/v2rayN/v2rayN/Tool/FileManager.cs b/v2rayN/v2rayN/Common/FileManager.cs similarity index 89% rename from v2rayN/v2rayN/Tool/FileManager.cs rename to v2rayN/v2rayN/Common/FileManager.cs index fa17fde5..4fa627b8 100644 --- a/v2rayN/v2rayN/Tool/FileManager.cs +++ b/v2rayN/v2rayN/Common/FileManager.cs @@ -2,7 +2,7 @@ using System.IO.Compression; using System.Text; -namespace v2rayN.Tool +namespace v2rayN { public static class FileManager { @@ -15,7 +15,7 @@ namespace v2rayN.Tool } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return false; } @@ -30,7 +30,7 @@ namespace v2rayN.Tool } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } @@ -49,7 +49,7 @@ namespace v2rayN.Tool } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); throw; } } @@ -75,13 +75,13 @@ namespace v2rayN.Tool } catch (IOException ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return false; } return true; diff --git a/v2rayN/v2rayN/Base/HttpClientHelper.cs b/v2rayN/v2rayN/Common/HttpClientHelper.cs similarity index 98% rename from v2rayN/v2rayN/Base/HttpClientHelper.cs rename to v2rayN/v2rayN/Common/HttpClientHelper.cs index 72d9d3c6..7a635e29 100644 --- a/v2rayN/v2rayN/Base/HttpClientHelper.cs +++ b/v2rayN/v2rayN/Common/HttpClientHelper.cs @@ -3,7 +3,7 @@ using System.Net.Http; using System.Net.Mime; using System.Text; -namespace v2rayN.Base +namespace v2rayN { /// /// @@ -35,7 +35,7 @@ namespace v2rayN.Base public async Task PutAsync(string url, Dictionary headers) { - var jsonContent = Utils.ToJson(headers); + var jsonContent = JsonUtils.Serialize(headers); var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json); var result = await httpClient.PutAsync(url, content); diff --git a/v2rayN/v2rayN/Tool/Job.cs b/v2rayN/v2rayN/Common/Job.cs similarity index 97% rename from v2rayN/v2rayN/Tool/Job.cs rename to v2rayN/v2rayN/Common/Job.cs index 78b1a56e..c25a2221 100644 --- a/v2rayN/v2rayN/Tool/Job.cs +++ b/v2rayN/v2rayN/Common/Job.cs @@ -52,7 +52,7 @@ namespace v2rayN if (!succ) { - Utils.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); + Logging.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); } return succ; diff --git a/v2rayN/v2rayN/Common/JsonUtils.cs b/v2rayN/v2rayN/Common/JsonUtils.cs new file mode 100644 index 00000000..2ee9ceb2 --- /dev/null +++ b/v2rayN/v2rayN/Common/JsonUtils.cs @@ -0,0 +1,132 @@ +using System.IO; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + +namespace v2rayN +{ + internal class JsonUtils + { + /// + /// DeepCopy + /// + /// + /// + /// + public static T DeepCopy(T obj) + { + return Deserialize(Serialize(obj, false))!; + } + + /// + /// Deserialize to object + /// + /// + /// + /// + public static T? Deserialize(string? strJson) + { + try + { + if (string.IsNullOrEmpty(strJson)) + { + return default; + } + return JsonSerializer.Deserialize(strJson); + } + catch + { + return default; + } + } + + /// + /// parse + /// + /// + /// + public static JsonNode? ParseJson(string strJson) + { + try + { + if (string.IsNullOrEmpty(strJson)) + { + return null; + } + return JsonNode.Parse(strJson); + } + catch + { + //SaveLog(ex.Message, ex); + return null; + } + } + + /// + /// Serialize Object to Json string + /// + /// + /// + /// + public static string Serialize(object? obj, bool indented = true) + { + string result = string.Empty; + try + { + if (obj == null) + { + return result; + } + var options = new JsonSerializerOptions + { + WriteIndented = indented ? true : false, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + result = JsonSerializer.Serialize(obj, options); + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + return result; + } + + /// + /// SerializeToNode + /// + /// + /// + public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj); + + /// + /// Save as json file + /// + /// + /// + /// + /// + public static int ToFile(object? obj, string filePath, bool nullValue = true) + { + int result; + try + { + using FileStream file = File.Create(filePath); + + var options = new JsonSerializerOptions + { + WriteIndented = true, + DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull + }; + + JsonSerializer.Serialize(file, obj, options); + result = 0; + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + result = -1; + } + return result; + } + } +} \ No newline at end of file diff --git a/v2rayN/v2rayN/Tool/Logging.cs b/v2rayN/v2rayN/Common/Logging.cs similarity index 68% rename from v2rayN/v2rayN/Tool/Logging.cs rename to v2rayN/v2rayN/Common/Logging.cs index b390fc99..ba5b97e7 100644 --- a/v2rayN/v2rayN/Tool/Logging.cs +++ b/v2rayN/v2rayN/Common/Logging.cs @@ -3,7 +3,7 @@ using NLog.Config; using NLog.Targets; using System.IO; -namespace v2rayN.Tool +namespace v2rayN { public class Logging { @@ -51,5 +51,28 @@ namespace v2rayN.Tool catch { } }); } + + public static void SaveLog(string strContent) + { + if (LogManager.IsLoggingEnabled()) + { + var logger = LogManager.GetLogger("Log1"); + logger.Info(strContent); + } + } + + public static void SaveLog(string strTitle, Exception ex) + { + if (LogManager.IsLoggingEnabled()) + { + var logger = LogManager.GetLogger("Log2"); + logger.Debug($"{strTitle},{ex.Message}"); + logger.Debug(ex.StackTrace); + if (ex?.InnerException != null) + { + logger.Error(ex.InnerException); + } + } + } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Handler/QRCodeHelper.cs b/v2rayN/v2rayN/Common/QRCodeHelper.cs similarity index 78% rename from v2rayN/v2rayN/Handler/QRCodeHelper.cs rename to v2rayN/v2rayN/Common/QRCodeHelper.cs index 07af8856..0c4fbdb2 100644 --- a/v2rayN/v2rayN/Handler/QRCodeHelper.cs +++ b/v2rayN/v2rayN/Common/QRCodeHelper.cs @@ -2,15 +2,19 @@ using QRCoder.Xaml; using System.Windows.Media; -namespace v2rayN.Handler +namespace v2rayN { /// /// 含有QR码的描述类和包装编码和渲染 /// public class QRCodeHelper { - public static DrawingImage? GetQRCode(string strContent) + public static DrawingImage? GetQRCode(string? strContent) { + if (strContent is null) + { + return null; + } try { QRCodeGenerator qrGenerator = new(); diff --git a/v2rayN/v2rayN/Tool/QueryableExtension.cs b/v2rayN/v2rayN/Common/QueryableExtension.cs similarity index 98% rename from v2rayN/v2rayN/Tool/QueryableExtension.cs rename to v2rayN/v2rayN/Common/QueryableExtension.cs index 218f7273..258456bf 100644 --- a/v2rayN/v2rayN/Tool/QueryableExtension.cs +++ b/v2rayN/v2rayN/Common/QueryableExtension.cs @@ -1,7 +1,7 @@ using System.Linq.Expressions; using System.Reflection; -namespace v2rayN.Tool +namespace v2rayN { public static class QueryableExtension { diff --git a/v2rayN/v2rayN/Tool/SemanticVersion.cs b/v2rayN/v2rayN/Common/SemanticVersion.cs similarity index 99% rename from v2rayN/v2rayN/Tool/SemanticVersion.cs rename to v2rayN/v2rayN/Common/SemanticVersion.cs index 5b01242e..597ed970 100644 --- a/v2rayN/v2rayN/Tool/SemanticVersion.cs +++ b/v2rayN/v2rayN/Common/SemanticVersion.cs @@ -1,6 +1,4 @@ -using v2rayN.Base; - -namespace v2rayN.Tool +namespace v2rayN { public class SemanticVersion { diff --git a/v2rayN/v2rayN/Base/SqliteHelper.cs b/v2rayN/v2rayN/Common/SqliteHelper.cs similarity index 95% rename from v2rayN/v2rayN/Base/SqliteHelper.cs rename to v2rayN/v2rayN/Common/SqliteHelper.cs index 7903f3f1..5daab53c 100644 --- a/v2rayN/v2rayN/Base/SqliteHelper.cs +++ b/v2rayN/v2rayN/Common/SqliteHelper.cs @@ -1,7 +1,7 @@ using SQLite; using System.Collections; -namespace v2rayN.Base +namespace v2rayN { public sealed class SqliteHelper { @@ -11,10 +11,11 @@ namespace v2rayN.Base private SQLiteConnection _db; private SQLiteAsyncConnection _dbAsync; private static readonly object objLock = new(); + public readonly string _configDB = "guiNDB.db"; public SqliteHelper() { - _connstr = Utils.GetConfigPath(Global.ConfigDB); + _connstr = Utils.GetConfigPath(_configDB); _db = new SQLiteConnection(_connstr, false); _dbAsync = new SQLiteAsyncConnection(_connstr, false); } diff --git a/v2rayN/v2rayN/Base/StringEx.cs b/v2rayN/v2rayN/Common/StringEx.cs similarity index 89% rename from v2rayN/v2rayN/Base/StringEx.cs rename to v2rayN/v2rayN/Common/StringEx.cs index cf0f9106..9a751ce9 100644 --- a/v2rayN/v2rayN/Base/StringEx.cs +++ b/v2rayN/v2rayN/Common/StringEx.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; -namespace v2rayN.Base +namespace v2rayN { internal static class StringEx { @@ -80,5 +80,15 @@ namespace v2rayN.Base return char.ToUpper(value[0]) + value.Substring(1); } + + public static string AppendQuotes(this string value) + { + if (string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + return $"\"{value}\""; + } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Tool/UI.cs b/v2rayN/v2rayN/Common/UI.cs similarity index 56% rename from v2rayN/v2rayN/Tool/UI.cs rename to v2rayN/v2rayN/Common/UI.cs index dccbeee1..226757c4 100644 --- a/v2rayN/v2rayN/Tool/UI.cs +++ b/v2rayN/v2rayN/Common/UI.cs @@ -1,4 +1,5 @@ -using System.Windows; +using Microsoft.Win32; +using System.Windows; namespace v2rayN { @@ -20,5 +21,24 @@ namespace v2rayN { return MessageBox.Show(msg, caption, MessageBoxButton.YesNo, MessageBoxImage.Question); } + + public static bool? OpenFileDialog(out string fileName, string filter) + { + fileName = string.Empty; + + var fileDialog = new OpenFileDialog + { + Multiselect = false, + Filter = filter + }; + + if (fileDialog.ShowDialog() != true) + { + return false; + } + fileName = fileDialog.FileName; + + return true; + } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Tool/Utils.cs b/v2rayN/v2rayN/Common/Utils.cs similarity index 81% rename from v2rayN/v2rayN/Tool/Utils.cs rename to v2rayN/v2rayN/Common/Utils.cs index 15e87396..a56e814e 100644 --- a/v2rayN/v2rayN/Tool/Utils.cs +++ b/v2rayN/v2rayN/Common/Utils.cs @@ -1,8 +1,6 @@ using Microsoft.Win32; using Microsoft.Win32.TaskScheduler; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NLog; +using System.Collections.Specialized; using System.Diagnostics; using System.Drawing; using System.IO; @@ -16,13 +14,10 @@ using System.Security.Cryptography; using System.Security.Principal; using System.Text; using System.Text.RegularExpressions; -using System.Web; using System.Windows; using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; -using v2rayN.Base; -using v2rayN.Mode; using ZXing; using ZXing.Common; using ZXing.QrCode; @@ -53,7 +48,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return result; } @@ -71,111 +66,11 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return null; } - /// - /// 反序列化成对象 - /// - /// - /// - /// - public static T? FromJson(string? strJson) - { - try - { - if (string.IsNullOrEmpty(strJson)) - { - return default; - } - return JsonConvert.DeserializeObject(strJson); - } - catch - { - return default; - } - } - - /// - /// 序列化成Json - /// - /// - /// - public static string ToJson(object? obj, bool indented = true) - { - string result = string.Empty; - try - { - if (obj == null) - { - return result; - } - if (indented) - { - result = JsonConvert.SerializeObject(obj, - Formatting.Indented, - new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - } - else - { - result = JsonConvert.SerializeObject(obj, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - } - } - catch (Exception ex) - { - SaveLog(ex.Message, ex); - } - return result; - } - - /// - /// 保存成json文件 - /// - /// - /// - /// - public static int ToJsonFile(object? obj, string filePath, bool nullValue = true) - { - int result; - try - { - using StreamWriter file = File.CreateText(filePath); - JsonSerializer serializer; - if (nullValue) - { - serializer = new JsonSerializer() { Formatting = Formatting.Indented }; - } - else - { - serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore }; - } - - serializer.Serialize(file, obj); - result = 0; - } - catch (Exception ex) - { - SaveLog(ex.Message, ex); - result = -1; - } - return result; - } - - public static JObject? ParseJson(string strJson) - { - try - { - return JObject.Parse(strJson); - } - catch (Exception ex) - { - //SaveLog(ex.Message, ex); - return null; - } - } - #endregion 资源Json操作 #region 转换函数 @@ -204,7 +99,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return string.Empty; } } @@ -223,7 +118,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return new List(); } } @@ -244,7 +139,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return new List(); } } @@ -263,7 +158,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog("Base64Encode", ex); + Logging.SaveLog("Base64Encode", ex); return string.Empty; } } @@ -277,7 +172,7 @@ namespace v2rayN { try { - plainText = plainText.TrimEx() + plainText = plainText.Trim() .Replace(Environment.NewLine, "") .Replace("\n", "") .Replace("\r", "") @@ -295,7 +190,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog("Base64Decode", ex); + Logging.SaveLog("Base64Decode", ex); return string.Empty; } } @@ -305,13 +200,13 @@ namespace v2rayN /// /// /// - public static int ToInt(object obj) + public static int ToInt(object? obj) { try { - return Convert.ToInt32(obj); + return Convert.ToInt32(obj ?? string.Empty); } - catch (Exception ex) + catch //(Exception ex) { //SaveLog(ex.Message, ex); return 0; @@ -324,7 +219,7 @@ namespace v2rayN { return Convert.ToBoolean(obj); } - catch (Exception ex) + catch //(Exception ex) { //SaveLog(ex.Message, ex); return false; @@ -337,7 +232,7 @@ namespace v2rayN { return obj?.ToString() ?? string.Empty; } - catch (Exception ex) + catch// (Exception ex) { //SaveLog(ex.Message, ex); return string.Empty; @@ -407,7 +302,33 @@ namespace v2rayN public static string UrlDecode(string url) { - return HttpUtility.UrlDecode(url); + return Uri.UnescapeDataString(url); + //return HttpUtility.UrlDecode(url); + } + + public static NameValueCollection ParseQueryString(string query) + { + var result = new NameValueCollection(StringComparer.OrdinalIgnoreCase); + if (IsNullOrEmpty(query)) + { + return result; + } + + var parts = query[1..].Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var part in parts) + { + var keyValue = part.Split(['=']); + if (keyValue.Length != 2) + { + continue; + } + var key = Uri.UnescapeDataString(keyValue[0]); + var val = Uri.UnescapeDataString(keyValue[1]); + + result.Add(key, val); + } + + return result; } public static string GetMD5(string str) @@ -492,7 +413,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return false; } } @@ -591,215 +512,6 @@ namespace v2rayN #endregion 数据检查 - #region 开机自动启动 - - /// - /// 开机自动启动 - /// - /// - /// - public static void SetAutoRun(bool run) - { - try - { - var autoRunName = $"{Global.AutoRunName}_{GetMD5(StartupPath())}"; - - //delete first - RegWriteValue(Global.AutoRunRegPath, autoRunName, ""); - if (IsAdministrator()) - { - AutoStart(autoRunName, "", ""); - } - - if (run) - { - string exePath = $"\"{GetExePath()}\""; - if (IsAdministrator()) - { - AutoStart(autoRunName, exePath, ""); - } - else - { - RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath); - } - } - } - catch (Exception ex) - { - SaveLog(ex.Message, ex); - } - } - - /// - /// 是否已经设置开机自动启动 - /// - /// - public static bool IsAutoRun() - { - try - { - //clear - if (!RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, "").IsNullOrEmpty()) - { - RegWriteValue(Global.AutoRunRegPath, Global.AutoRunName, ""); - } - - string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, ""); - string exePath = GetExePath(); - if (value == exePath || value == $"\"{exePath}\"") - { - return true; - } - } - catch (Exception ex) - { - SaveLog(ex.Message, ex); - } - return false; - } - - /// - /// 获取启动了应用程序的可执行文件的路径 - /// - /// - public static string GetPath(string fileName) - { - string startupPath = StartupPath(); - if (IsNullOrEmpty(fileName)) - { - return startupPath; - } - return Path.Combine(startupPath, fileName); - } - - /// - /// 获取启动了应用程序的可执行文件的路径及文件名 - /// - /// - public static string GetExePath() - { - return Environment.ProcessPath; - } - - public static string StartupPath() - { - return AppDomain.CurrentDomain.BaseDirectory; - } - - public static string? RegReadValue(string path, string name, string def) - { - RegistryKey? regKey = null; - try - { - regKey = Registry.CurrentUser.OpenSubKey(path, false); - string? value = regKey?.GetValue(name) as string; - if (IsNullOrEmpty(value)) - { - return def; - } - else - { - return value; - } - } - catch (Exception ex) - { - SaveLog(ex.Message, ex); - } - finally - { - regKey?.Close(); - } - return def; - } - - public static void RegWriteValue(string path, string name, object value) - { - RegistryKey? regKey = null; - try - { - regKey = Registry.CurrentUser.CreateSubKey(path); - if (IsNullOrEmpty(value.ToString())) - { - regKey?.DeleteValue(name, false); - } - else - { - regKey?.SetValue(name, value); - } - } - catch (Exception ex) - { - SaveLog(ex.Message, ex); - } - finally - { - regKey?.Close(); - } - } - - /// - /// 判断.Net Framework的Release是否符合 - /// (.Net Framework 版本在4.0及以上) - /// - /// 需要的版本4.6.2=394802;4.8=528040 - /// - public static bool CheckForDotNetVersion(int release = 528040) - { - const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; - using RegistryKey? ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey); - if (ndpKey?.GetValue("Release") != null) - { - return (int)ndpKey.GetValue("Release") >= release; - } - return false; - } - - /// - /// Auto Start via TaskService - /// - /// - /// - /// - /// - public static void AutoStart(string taskName, string fileName, string description) - { - if (string.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 (string.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)); - - taskService.RootFolder.RegisterTaskDefinition(TaskName, task); - } - - #endregion 开机自动启动 - #region 测速 /// @@ -859,11 +571,33 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return inUse; } + public static int GetFreePort() + { + try + { + int defaultPort = 9090; + if (!Utils.PortInUse(defaultPort)) + { + return defaultPort; + } + + TcpListener l = new(IPAddress.Loopback, 0); + l.Start(); + int port = ((IPEndPoint)l.LocalEndpoint).Port; + l.Stop(); + return port; + } + catch + { + } + return 69090; + } + #endregion 测速 #region 杂项 @@ -880,45 +614,22 @@ namespace v2rayN if (blFull) { return string.Format("v2rayN - V{0} - {1}", - FileVersionInfo.GetVersionInfo(location).FileVersion.ToString(), + FileVersionInfo.GetVersionInfo(location).FileVersion?.ToString(), File.GetLastWriteTime(location).ToString("yyyy/MM/dd")); } else { return string.Format("v2rayN/{0}", - FileVersionInfo.GetVersionInfo(location).FileVersion.ToString()); + FileVersionInfo.GetVersionInfo(location).FileVersion?.ToString()); } } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return string.Empty; } } - /// - /// DeepCopy - /// - /// - /// - /// - public static T DeepCopy(T obj) - { - return FromJson(ToJson(obj, false))!; - - // object retval; - // MemoryStream ms = new(); - //#pragma warning disable SYSLIB0011 // 类型或成员已过时 - // BinaryFormatter bf = new(); - //#pragma warning restore SYSLIB0011 // 类型或成员已过时 - // //序列化成流 - // bf.Serialize(ms, obj); - // ms.Seek(0, SeekOrigin.Begin); - // //反序列化成对象 - // retval = bf.Deserialize(ms); - // return (T)retval; - } - /// /// 获取剪贴板数 /// @@ -937,7 +648,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return strData; } @@ -976,7 +687,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return string.Empty; } @@ -996,7 +707,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return false; } } @@ -1036,7 +747,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } @@ -1057,11 +768,69 @@ namespace v2rayN return value is int i && i > 0; } + /// + /// 获取系统hosts + /// + /// + public static Dictionary GetSystemHosts() + { + var systemHosts = new Dictionary(); + var hostfile = @"C:\Windows\System32\drivers\etc\hosts"; + try + { + if (File.Exists(hostfile)) + { + var hosts = File.ReadAllText(hostfile).Replace("\r", ""); + var hostsList = hosts.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var host in hostsList) + { + if (host.StartsWith("#")) continue; + var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + if (hostItem.Length < 2) continue; + systemHosts.Add(hostItem[1], hostItem[0]); + } + } + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + return systemHosts; + } + #endregion 杂项 #region TempPath - // return path to store temporary files + /// + /// 获取启动了应用程序的可执行文件的路径 + /// + /// + public static string GetPath(string fileName) + { + string startupPath = StartupPath(); + if (IsNullOrEmpty(fileName)) + { + return startupPath; + } + return Path.Combine(startupPath, fileName); + } + + /// + /// 获取启动了应用程序的可执行文件的路径及文件名 + /// + /// + public static string GetExePath() + { + return Environment.ProcessPath ?? string.Empty; + } + + public static string StartupPath() + { + return AppDomain.CurrentDomain.BaseDirectory; + } + public static string GetTempPath(string filename = "") { string _tempPath = Path.Combine(StartupPath(), "guiTemps"); @@ -1115,7 +884,7 @@ namespace v2rayN } } - public static string GetBinPath(string filename, ECoreType? coreType = null) + public static string GetBinPath(string filename, string? coreType = null) { string _tempPath = Path.Combine(StartupPath(), "bin"); if (!Directory.Exists(_tempPath)) @@ -1176,33 +945,6 @@ namespace v2rayN #endregion TempPath - #region Log - - public static void SaveLog(string strContent) - { - if (LogManager.IsLoggingEnabled()) - { - var logger = LogManager.GetLogger("Log1"); - logger.Info(strContent); - } - } - - public static void SaveLog(string strTitle, Exception ex) - { - if (LogManager.IsLoggingEnabled()) - { - var logger = LogManager.GetLogger("Log2"); - logger.Debug($"{strTitle},{ex.Message}"); - logger.Debug(ex.StackTrace); - if (ex?.InnerException != null) - { - logger.Error(ex.InnerException); - } - } - } - - #endregion Log - #region scan screen public static string ScanScreen(float dpiX, float dpiY) @@ -1248,7 +990,7 @@ namespace v2rayN } catch (Exception ex) { - SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return string.Empty; } @@ -1263,6 +1005,171 @@ namespace v2rayN #endregion scan screen + #region 开机自动启动等 + + /// + /// 开机自动启动 + /// + /// + /// + public static void SetAutoRun(string AutoRunRegPath, string AutoRunName, bool run) + { + try + { + var autoRunName = $"{AutoRunName}_{GetMD5(StartupPath())}"; + + //delete first + RegWriteValue(AutoRunRegPath, autoRunName, ""); + if (IsAdministrator()) + { + AutoStart(autoRunName, "", ""); + } + + if (run) + { + string exePath = $"\"{GetExePath()}\""; + if (IsAdministrator()) + { + AutoStart(autoRunName, exePath, ""); + } + else + { + RegWriteValue(AutoRunRegPath, autoRunName, exePath); + } + } + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + } + + public static string? RegReadValue(string path, string name, string def) + { + RegistryKey? regKey = null; + try + { + regKey = Registry.CurrentUser.OpenSubKey(path, false); + string? value = regKey?.GetValue(name) as string; + if (IsNullOrEmpty(value)) + { + return def; + } + else + { + return value; + } + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + finally + { + regKey?.Close(); + } + return def; + } + + public static void RegWriteValue(string path, string name, object value) + { + RegistryKey? regKey = null; + try + { + regKey = Registry.CurrentUser.CreateSubKey(path); + if (IsNullOrEmpty(value.ToString())) + { + regKey?.DeleteValue(name, false); + } + else + { + regKey?.SetValue(name, value); + } + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + finally + { + regKey?.Close(); + } + } + + /// + /// Auto Start via TaskService + /// + /// + /// + /// + /// + public static void AutoStart(string taskName, string fileName, string description) + { + if (string.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 (string.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)); + + taskService.RootFolder.RegisterTaskDefinition(TaskName, task); + } + + public static void RemoveTunDevice() + { + try + { + string pnputilPath = @"C:\Windows\System32\pnputil.exe"; + string arg = $" /remove-device /deviceid \"wintun\""; + + // Try to remove the device + Process proc = new() + { + StartInfo = new() + { + FileName = pnputilPath, + Arguments = arg, + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true + } + }; + + proc.Start(); + var output = proc.StandardOutput.ReadToEnd(); + proc.WaitForExit(); + } + catch + { + } + } + + #endregion 开机自动启动等 + #region Windows API [Flags] diff --git a/v2rayN/v2rayN/Global.cs b/v2rayN/v2rayN/Global.cs index 007629f6..08dddfea 100644 --- a/v2rayN/v2rayN/Global.cs +++ b/v2rayN/v2rayN/Global.cs @@ -30,15 +30,16 @@ namespace v2rayN public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw="; public const string ConfigFileName = "guiNConfig.json"; - public const string ConfigDB = "guiNDB.db"; public const string CoreConfigFileName = "config.json"; public const string CorePreConfigFileName = "configPre.json"; + public const string CoreSpeedtestConfigFileName = "configSpeedtest.json"; public const string V2raySampleClient = "v2rayN.Sample.SampleClientConfig"; public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig"; public const string V2raySampleHttprequestFileName = "v2rayN.Sample.SampleHttprequest"; public const string V2raySampleHttpresponseFileName = "v2rayN.Sample.SampleHttpresponse"; public const string V2raySampleInbound = "v2rayN.Sample.SampleInbound"; public const string V2raySampleOutbound = "v2rayN.Sample.SampleOutbound"; + public const string SingboxSampleOutbound = "v2rayN.Sample.SingboxSampleOutbound"; public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_"; public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns"; public const string TunSingboxInboundFileName = "v2rayN.Sample.tun_singbox_inbound"; @@ -117,6 +118,10 @@ namespace v2rayN @"http://cachefly.cachefly.net/10mb.test" }; + public static readonly List SpeedPingTestUrls = new() { + @"https://www.google.com/generate_204", + }; + public static readonly Dictionary UserAgentTxts = new() { {"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" }, @@ -136,7 +141,8 @@ namespace v2rayN {EConfigType.VLESS,"vless://"}, {EConfigType.Trojan,"trojan://"}, {EConfigType.Hysteria2,"hysteria2://"}, - {EConfigType.Tuic,"tuic://"} + {EConfigType.Tuic,"tuic://"}, + {EConfigType.Wireguard,"wireguard://"} }; public static readonly Dictionary ProtocolTypes = new() @@ -147,13 +153,15 @@ namespace v2rayN {EConfigType.VLESS,"vless"}, {EConfigType.Trojan,"trojan"}, {EConfigType.Hysteria2,"hysteria2"}, - {EConfigType.Tuic,"tuic"} + {EConfigType.Tuic,"tuic"}, + {EConfigType.Wireguard,"wireguard"} }; public static readonly List VmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" }; public static readonly List SsSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" }; public static readonly List SsSecuritysInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" }; public static readonly List SsSecuritysInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" }; + public static readonly List SsSecuritysInSingbox = 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 Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" }; public static readonly List Networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" }; public static readonly List KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" }; @@ -168,25 +176,16 @@ namespace v2rayN public static readonly List AllowInsecures = new() { "true", "false", "" }; public static readonly List DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" }; public static readonly List Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" }; - public static readonly List Alpns = new() { "h2", "http/1.1", "h2,http/1.1", "h3", "" }; + public static readonly List Alpns = new() { "h3", "h2", "http/1.1", "h3,h2,http/1.1", "h3,h2", "h2,http/1.1", "" }; public static readonly List LogLevels = new() { "debug", "info", "warning", "error", "none" }; public static readonly List InboundTags = new() { "socks", "http", "socks2", "http2" }; public static readonly List RuleProtocols = new() { "http", "tls", "bittorrent" }; - public static readonly List TunMtus = new() { "9000", "1500" }; + public static readonly List TunMtus = new() { "1280", "1408", "1500", "9000" }; public static readonly List TunStacks = new() { "gvisor", "system" }; public static readonly List PresetMsgFilters = new() { "proxy", "direct", "block", "" }; public static readonly List SingboxMuxs = new() { "h2mux", "smux", "yamux", "" }; public static readonly List TuicCongestionControls = new() { "cubic", "new_reno", "bbr" }; #endregion const - - #region global variable - - public static int StatePort { get; set; } - public static Job ProcessJob { get; set; } - public static bool ShowInTaskbar { get; set; } - public static string ExePathKey { get; set; } - - #endregion global variable } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Handler/ConfigHandler.cs b/v2rayN/v2rayN/Handler/ConfigHandler.cs index 70f7993d..ee8fc7dc 100644 --- a/v2rayN/v2rayN/Handler/ConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/ConfigHandler.cs @@ -1,9 +1,7 @@ using System.Data; using System.IO; using System.Text.RegularExpressions; -using v2rayN.Base; using v2rayN.Mode; -using v2rayN.Tool; namespace v2rayN.Handler { @@ -29,13 +27,13 @@ namespace v2rayN.Handler if (!Utils.IsNullOrEmpty(result)) { //转成Json - config = Utils.FromJson(result); + config = JsonUtils.Deserialize(result); } else { if (File.Exists(Utils.GetConfigPath(configRes))) { - Utils.SaveLog("LoadConfig Exception"); + Logging.SaveLog("LoadConfig Exception"); return -1; } } @@ -234,7 +232,7 @@ namespace v2rayN.Handler //save temp file var resPath = Utils.GetConfigPath(configRes); var tempPath = $"{resPath}_temp"; - if (Utils.ToJsonFile(config, tempPath) != 0) + if (JsonUtils.ToFile(config, tempPath) != 0) { return; } @@ -248,26 +246,26 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog("ToJsonFile", ex); + Logging.SaveLog("ToJsonFile", ex); } } } public static int ImportOldGuiConfig(Config config, string fileName) { - string result = Utils.LoadResource(fileName); + var result = Utils.LoadResource(fileName); if (Utils.IsNullOrEmpty(result)) { return -1; } - var configOld = Utils.FromJson(result); + var configOld = JsonUtils.Deserialize(result); if (configOld == null) { return -1; } - var subItem = Utils.FromJson>(Utils.ToJson(configOld.subItem)); + var subItem = JsonUtils.Deserialize>(JsonUtils.Serialize(configOld.subItem)); foreach (var it in subItem) { if (Utils.IsNullOrEmpty(it.id)) @@ -277,7 +275,7 @@ namespace v2rayN.Handler SqliteHelper.Instance.Replace(it); } - var profileItems = Utils.FromJson>(Utils.ToJson(configOld.vmess)); + var profileItems = JsonUtils.Deserialize>(JsonUtils.Serialize(configOld.vmess)); foreach (var it in profileItems) { if (Utils.IsNullOrEmpty(it.indexId)) @@ -293,13 +291,13 @@ namespace v2rayN.Handler { continue; } - var routing = Utils.FromJson(Utils.ToJson(it)); + var routing = JsonUtils.Deserialize(JsonUtils.Serialize(it)); foreach (var it2 in it.rules) { it2.id = Utils.GetGUID(false); } routing.ruleNum = it.rules.Count; - routing.ruleSet = Utils.ToJson(it.rules, false); + routing.ruleSet = JsonUtils.Serialize(it.rules, false); if (Utils.IsNullOrEmpty(routing.id)) { @@ -308,7 +306,7 @@ namespace v2rayN.Handler SqliteHelper.Instance.Replace(routing); } - config = Utils.FromJson(Utils.ToJson(configOld)); + config = JsonUtils.Deserialize(JsonUtils.Serialize(configOld)); if (config.coreBasicItem == null) { @@ -424,7 +422,7 @@ namespace v2rayN.Handler continue; } - ProfileItem profileItem = Utils.DeepCopy(item); + ProfileItem profileItem = JsonUtils.DeepCopy(item); profileItem.indexId = string.Empty; profileItem.remarks = $"{item.remarks}-clone"; @@ -595,7 +593,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return -1; } @@ -715,6 +713,7 @@ namespace v2rayN.Handler profileItem.address = profileItem.address.TrimEx(); profileItem.id = profileItem.id.TrimEx(); + profileItem.path = profileItem.path.TrimEx(); profileItem.network = string.Empty; if (Utils.IsNullOrEmpty(profileItem.streamSecurity)) @@ -770,6 +769,38 @@ namespace v2rayN.Handler return 0; } + /// + /// Add or edit server + /// + /// + /// + /// + public static int AddWireguardServer(Config config, ProfileItem profileItem, bool toFile = true) + { + profileItem.configType = EConfigType.Wireguard; + profileItem.coreType = ECoreType.sing_box; + + profileItem.address = profileItem.address.TrimEx(); + profileItem.id = profileItem.id.TrimEx(); + profileItem.publicKey = profileItem.publicKey.TrimEx(); + profileItem.path = profileItem.path.TrimEx(); + profileItem.requestHost = profileItem.requestHost.TrimEx(); + profileItem.network = string.Empty; + if (profileItem.shortId.IsNullOrEmpty()) + { + profileItem.shortId = Global.TunMtus.FirstOrDefault(); + } + + if (profileItem.id.IsNullOrEmpty()) + { + return -1; + } + + AddServerCommon(config, profileItem, toFile); + + return 0; + } + public static int SortServers(Config config, string subId, string colName, bool asc) { var lstModel = LazyConfig.Instance.ProfileItems(subId, ""); @@ -804,7 +835,6 @@ namespace v2rayN.Handler case EServerColName.remarks: case EServerColName.address: case EServerColName.port: - case EServerColName.security: case EServerColName.network: case EServerColName.streamSecurity: propertyName = name.ToString(); @@ -1007,7 +1037,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog("Remove Item", ex); + Logging.SaveLog("Remove Item", ex); } return 0; @@ -1059,8 +1089,8 @@ namespace v2rayN.Handler } continue; } - ProfileItem profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg); - if (profileItem == null) + var profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg); + if (profileItem is null) { continue; } @@ -1068,7 +1098,8 @@ namespace v2rayN.Handler //exist sub items if (isSub && !Utils.IsNullOrEmpty(subid)) { - var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub && CompareProfileItem(t, profileItem, true)); + var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub + && config.uiItem.enableUpdateSubOnlyRemarksExist ? t.remarks == profileItem.remarks : CompareProfileItem(t, profileItem, true)); if (existItem != null) { //Check for duplicate indexId @@ -1097,36 +1128,19 @@ namespace v2rayN.Handler } profileItem.subid = subid; profileItem.isSub = isSub; - var addStatus = -1; - if (profileItem.configType == EConfigType.VMess) + var addStatus = profileItem.configType switch { - addStatus = AddServer(config, profileItem, false); - } - else if (profileItem.configType == EConfigType.Shadowsocks) - { - addStatus = AddShadowsocksServer(config, profileItem, false); - } - else if (profileItem.configType == EConfigType.Socks) - { - addStatus = AddSocksServer(config, profileItem, false); - } - else if (profileItem.configType == EConfigType.Trojan) - { - addStatus = AddTrojanServer(config, profileItem, false); - } - else if (profileItem.configType == EConfigType.VLESS) - { - addStatus = AddVlessServer(config, profileItem, false); - } - else if (profileItem.configType == EConfigType.Hysteria2) - { - addStatus = AddHysteria2Server(config, profileItem, false); - } - else if (profileItem.configType == EConfigType.Tuic) - { - addStatus = AddTuicServer(config, profileItem, false); - } + EConfigType.VMess => AddServer(config, profileItem, false), + EConfigType.Shadowsocks => AddShadowsocksServer(config, profileItem, false), + EConfigType.Socks => AddSocksServer(config, profileItem, false), + EConfigType.Trojan => AddTrojanServer(config, profileItem, false), + EConfigType.VLESS => AddVlessServer(config, profileItem, false), + EConfigType.Hysteria2 => AddHysteria2Server(config, profileItem, false), + EConfigType.Tuic => AddTuicServer(config, profileItem, false), + EConfigType.Wireguard => AddWireguardServer(config, profileItem, false), + _ => -1, + }; if (addStatus == 0) { @@ -1163,7 +1177,7 @@ namespace v2rayN.Handler ProfileItem profileItem = new(); //Is v2ray configuration - V2rayConfig? v2rayConfig = Utils.FromJson(clipboardData); + V2rayConfig? v2rayConfig = JsonUtils.Deserialize(clipboardData); if (v2rayConfig?.inbounds?.Count > 0 && v2rayConfig.outbounds?.Count > 0) { @@ -1254,10 +1268,10 @@ namespace v2rayN.Handler } //SsSIP008 - var lstSsServer = Utils.FromJson>(clipboardData); + var lstSsServer = JsonUtils.Deserialize>(clipboardData); if (lstSsServer?.Count <= 0) { - var ssSIP008 = Utils.FromJson(clipboardData); + var ssSIP008 = JsonUtils.Deserialize(clipboardData); if (ssSIP008?.servers?.Count > 0) { lstSsServer = ssSIP008.servers; @@ -1469,7 +1483,7 @@ namespace v2rayN.Handler return -1; } - var lstRules = Utils.FromJson>(clipboardData); + var lstRules = JsonUtils.Deserialize>(clipboardData); if (lstRules == null) { return -1; @@ -1480,7 +1494,7 @@ namespace v2rayN.Handler item.id = Utils.GetGUID(false); } routingItem.ruleNum = lstRules.Count; - routingItem.ruleSet = Utils.ToJson(lstRules, false); + routingItem.ruleSet = JsonUtils.Serialize(lstRules, false); if (Utils.IsNullOrEmpty(routingItem.id)) { @@ -1519,7 +1533,7 @@ namespace v2rayN.Handler { return 0; } - var item = Utils.DeepCopy(rules[index]); + var item = JsonUtils.DeepCopy(rules[index]); rules.RemoveAt(index); rules.Insert(0, item); @@ -1531,7 +1545,7 @@ namespace v2rayN.Handler { return 0; } - var item = Utils.DeepCopy(rules[index]); + var item = JsonUtils.DeepCopy(rules[index]); rules.RemoveAt(index); rules.Insert(index - 1, item); @@ -1544,7 +1558,7 @@ namespace v2rayN.Handler { return 0; } - var item = Utils.DeepCopy(rules[index]); + var item = JsonUtils.DeepCopy(rules[index]); rules.RemoveAt(index); rules.Insert(index + 1, item); @@ -1556,7 +1570,7 @@ namespace v2rayN.Handler { return 0; } - var item = Utils.DeepCopy(rules[index]); + var item = JsonUtils.DeepCopy(rules[index]); rules.RemoveAt(index); rules.Add(item); @@ -1565,7 +1579,7 @@ namespace v2rayN.Handler case EMove.Position: { var removeItem = rules[index]; - var item = Utils.DeepCopy(rules[index]); + var item = JsonUtils.DeepCopy(rules[index]); rules.Insert(pos, item); rules.Remove(removeItem); break; diff --git a/v2rayN/v2rayN/Handler/CoreConfigHandler.cs b/v2rayN/v2rayN/Handler/CoreConfigHandler.cs index 00f4e9ec..8c61f69f 100644 --- a/v2rayN/v2rayN/Handler/CoreConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/CoreConfigHandler.cs @@ -35,11 +35,11 @@ namespace v2rayN.Handler } if (Utils.IsNullOrEmpty(fileName)) { - content = Utils.ToJson(singboxConfig); + content = JsonUtils.Serialize(singboxConfig); } else { - Utils.ToJsonFile(singboxConfig, fileName, false); + JsonUtils.ToFile(singboxConfig, fileName, false); } } else @@ -51,17 +51,17 @@ namespace v2rayN.Handler } if (Utils.IsNullOrEmpty(fileName)) { - content = Utils.ToJson(v2rayConfig); + content = JsonUtils.Serialize(v2rayConfig); } else { - Utils.ToJsonFile(v2rayConfig, fileName, false); + JsonUtils.ToFile(v2rayConfig, fileName, false); } } } catch (Exception ex) { - Utils.SaveLog("GenerateClientConfig", ex); + Logging.SaveLog("GenerateClientConfig", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } @@ -143,17 +143,32 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog("GenerateClientCustomConfig", ex); + Logging.SaveLog("GenerateClientCustomConfig", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } return 0; } - public static string GenerateClientSpeedtestConfigString(Config config, List selecteds, out string msg) + public static int GenerateClientSpeedtestConfig(Config config, string fileName, List selecteds, ECoreType coreType, out string msg) { - var coreConfigV2ray = new CoreConfigV2ray(config); - return coreConfigV2ray.GenerateClientSpeedtestConfigString(selecteds, out msg); + if (coreType == ECoreType.sing_box) + { + if ((new CoreConfigSingbox(config)).GenerateClientSpeedtestConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0) + { + return -1; + } + JsonUtils.ToFile(singboxConfig, fileName, false); + } + else + { + if ((new CoreConfigV2ray(config)).GenerateClientSpeedtestConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0) + { + return -1; + } + JsonUtils.ToFile(v2rayConfig, fileName, false); + } + return 0; } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Handler/CoreConfigSingbox.cs b/v2rayN/v2rayN/Handler/CoreConfigSingbox.cs index d1e73c4e..a1505e2e 100644 --- a/v2rayN/v2rayN/Handler/CoreConfigSingbox.cs +++ b/v2rayN/v2rayN/Handler/CoreConfigSingbox.cs @@ -1,4 +1,5 @@ -using v2rayN.Base; +using System.Net; +using System.Net.NetworkInformation; using v2rayN.Mode; using v2rayN.Resx; @@ -34,7 +35,7 @@ namespace v2rayN.Handler return -1; } - singboxConfig = Utils.FromJson(result); + singboxConfig = JsonUtils.Deserialize(result); if (singboxConfig == null) { msg = ResUI.FailedGenDefaultConfiguration; @@ -45,7 +46,9 @@ namespace v2rayN.Handler GenInbounds(singboxConfig); - GenOutbounds(node, singboxConfig); + GenOutbound(node, singboxConfig.outbounds[0]); + + GenMoreOutbounds(node, singboxConfig); GenRouting(singboxConfig); @@ -57,13 +60,15 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog("GenerateClientConfig4Singbox", ex); + Logging.SaveLog("GenerateClientConfig4Singbox", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } return 0; } + #region private gen function + private int GenLog(SingboxConfig singboxConfig) { try @@ -95,13 +100,11 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } - #region inbound private - private int GenInbounds(SingboxConfig singboxConfig) { try @@ -174,48 +177,40 @@ namespace v2rayN.Handler _config.tunModeItem.stack = Global.TunStacks[0]; } - var tunInbound = Utils.FromJson(Utils.GetEmbedText(Global.TunSingboxInboundFileName)); + var tunInbound = JsonUtils.Deserialize(Utils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { }; tunInbound.mtu = _config.tunModeItem.mtu; tunInbound.strict_route = _config.tunModeItem.strictRoute; tunInbound.stack = _config.tunModeItem.stack; + tunInbound.sniff = _config.inbound[0].sniffingEnabled; + tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled; + if (_config.tunModeItem.enableIPv6Address == false) + { + tunInbound.inet6_address = null; + } singboxConfig.inbounds.Add(tunInbound); } } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } - private Inbound4Sbox? GetInbound(Inbound4Sbox inItem, string tag, int offset, bool bSocks) + private Inbound4Sbox GetInbound(Inbound4Sbox inItem, string tag, int offset, bool bSocks) { - var inbound = Utils.DeepCopy(inItem); + var inbound = JsonUtils.DeepCopy(inItem); inbound.tag = tag; inbound.listen_port = inItem.listen_port + offset; inbound.type = bSocks ? Global.InboundSocks : Global.InboundHttp; return inbound; } - #endregion inbound private - - #region outbound private - - private int GenOutbounds(ProfileItem node, SingboxConfig singboxConfig) + private int GenOutbound(ProfileItem node, Outbound4Sbox outbound) { try { - if (_config.tunModeItem.enableTun) - { - singboxConfig.outbounds.Add(new() - { - type = "dns", - tag = "dns_out" - }); - } - - var outbound = singboxConfig.outbounds[0]; outbound.server = node.address; outbound.server_port = node.port; @@ -288,6 +283,15 @@ namespace v2rayN.Handler outbound.password = node.id; + if (!Utils.IsNullOrEmpty(node.path)) + { + outbound.obfs = new() + { + type = "salamander", + password = node.path.TrimEx(), + }; + } + outbound.up_mbps = _config.hysteriaItem.up_mbps > 0 ? _config.hysteriaItem.up_mbps : null; outbound.down_mbps = _config.hysteriaItem.down_mbps > 0 ? _config.hysteriaItem.down_mbps : null; @@ -303,6 +307,17 @@ namespace v2rayN.Handler GenOutboundMux(node, outbound); } + else if (node.configType == EConfigType.Wireguard) + { + outbound.type = Global.ProtocolTypes[EConfigType.Wireguard]; + + outbound.private_key = node.id; + outbound.peer_public_key = node.publicKey; + outbound.reserved = Utils.String2List(node.path).Select(int.Parse).ToArray(); + outbound.local_address = [.. Utils.String2List(node.requestHost)]; + outbound.mtu = Utils.ToInt(node.shortId.IsNullOrEmpty() ? Global.TunMtus.FirstOrDefault() : node.shortId); + GenOutboundMux(node, outbound); + } GenOutboundTls(node, outbound); @@ -310,7 +325,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -335,7 +350,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -385,7 +400,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -437,14 +452,63 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } - #endregion outbound private + private int GenMoreOutbounds(ProfileItem node, SingboxConfig singboxConfig) + { + if (node.subid.IsNullOrEmpty()) + { + return 0; + } + try + { + var subItem = LazyConfig.Instance.GetSubItem(node.subid); + if (subItem is null) + { + return 0; + } - #region routing rule private + //current proxy + var outbound = singboxConfig.outbounds[0]; + var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound); + + //Previous proxy + var prevNode = LazyConfig.Instance.GetProfileItemViaRemarks(subItem.prevProfile!); + if (prevNode is not null + && prevNode.configType != EConfigType.Custom) + { + var prevOutbound = JsonUtils.Deserialize(txtOutbound); + GenOutbound(prevNode, prevOutbound); + prevOutbound.tag = $"{Global.ProxyTag}2"; + singboxConfig.outbounds.Add(prevOutbound); + + outbound.detour = prevOutbound.tag; + } + + //Next proxy + var nextNode = LazyConfig.Instance.GetProfileItemViaRemarks(subItem.nextProfile!); + if (nextNode is not null + && nextNode.configType != EConfigType.Custom) + { + var nextOutbound = JsonUtils.Deserialize(txtOutbound); + GenOutbound(nextNode, nextOutbound); + nextOutbound.tag = Global.ProxyTag; + singboxConfig.outbounds.Insert(0, nextOutbound); + + outbound.tag = $"{Global.ProxyTag}1"; + nextOutbound.detour = outbound.tag; + } + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + + return 0; + } private int GenRouting(SingboxConfig singboxConfig) { @@ -454,7 +518,7 @@ namespace v2rayN.Handler { singboxConfig.route.auto_detect_interface = true; - var tunRules = Utils.FromJson>(Utils.GetEmbedText(Global.TunSingboxRulesFileName)); + var tunRules = JsonUtils.Deserialize>(Utils.GetEmbedText(Global.TunSingboxRulesFileName)); singboxConfig.route.rules.AddRange(tunRules); GenRoutingDirectExe(out List lstDnsExe, out List lstDirectExe); @@ -477,7 +541,7 @@ namespace v2rayN.Handler var routing = ConfigHandler.GetDefaultRouting(_config); if (routing != null) { - var rules = Utils.FromJson>(routing.ruleSet); + var rules = JsonUtils.Deserialize>(routing.ruleSet); foreach (var item in rules!) { if (item.enabled) @@ -492,7 +556,7 @@ namespace v2rayN.Handler var lockedItem = ConfigHandler.GetLockedRoutingItem(_config); if (lockedItem != null) { - var rules = Utils.FromJson>(lockedItem.ruleSet); + var rules = JsonUtils.Deserialize>(lockedItem.ruleSet); foreach (var item in rules!) { GenRoutingUserRule(item, singboxConfig.route.rules); @@ -502,7 +566,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -566,8 +630,8 @@ namespace v2rayN.Handler { rule.inbound = item.inboundTag; } - var rule2 = Utils.DeepCopy(rule); - var rule3 = Utils.DeepCopy(rule); + var rule2 = JsonUtils.DeepCopy(rule); + var rule3 = JsonUtils.DeepCopy(rule); var hasDomainIp = false; if (item.domain?.Count > 0) @@ -604,47 +668,47 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } private void ParseV2Domain(string domain, Rule4Sbox rule) { - if (domain.StartsWith("ext:") || domain.StartsWith("ext-domain:")) + if (domain.StartsWith("#") || domain.StartsWith("ext:") || domain.StartsWith("ext-domain:")) { return; } else if (domain.StartsWith("geosite:")) { - if (rule.geosite is null) { rule.geosite = new(); } + rule.geosite ??= []; rule.geosite?.Add(domain.Substring(8)); } else if (domain.StartsWith("regexp:")) { - if (rule.domain_regex is null) { rule.domain_regex = new(); } + rule.domain_regex ??= []; rule.domain_regex?.Add(domain.Replace(Global.RoutingRuleComma, ",").Substring(7)); } else if (domain.StartsWith("domain:")) { - if (rule.domain is null) { rule.domain = new(); } - if (rule.domain_suffix is null) { rule.domain_suffix = new(); } + rule.domain ??= []; + rule.domain_suffix ??= []; rule.domain?.Add(domain.Substring(7)); rule.domain_suffix?.Add("." + domain.Substring(7)); } else if (domain.StartsWith("full:")) { - if (rule.domain is null) { rule.domain = new(); } + rule.domain ??= []; rule.domain?.Add(domain.Substring(5)); } else if (domain.StartsWith("keyword:")) { - if (rule.domain_keyword is null) { rule.domain_keyword = new(); } + rule.domain_keyword ??= []; rule.domain_keyword?.Add(domain.Substring(8)); } else { - if (rule.domain_keyword is null) { rule.domain_keyword = new(); } + rule.domain_keyword ??= []; rule.domain_keyword?.Add(domain); } } @@ -671,10 +735,6 @@ namespace v2rayN.Handler } } - #endregion routing rule private - - #region dns private - private int GenDns(ProfileItem node, SingboxConfig singboxConfig) { try @@ -688,7 +748,7 @@ namespace v2rayN.Handler { tunDNS = Utils.GetEmbedText(Global.TunSingboxDNSFileName); } - dns4Sbox = Utils.FromJson(tunDNS); + dns4Sbox = JsonUtils.Deserialize(tunDNS); } else { @@ -699,7 +759,7 @@ namespace v2rayN.Handler normalDNS = "{\"servers\":[{\"address\":\"tcp://8.8.8.8\"}]}"; } - dns4Sbox = Utils.FromJson(normalDNS); + dns4Sbox = JsonUtils.Deserialize(normalDNS); } if (dns4Sbox is null) { @@ -726,35 +786,186 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } - #endregion dns private - private int GenStatistic(SingboxConfig singboxConfig) { if (_config.guiItem.enableStatistics) { singboxConfig.experimental = new Experimental4Sbox() { + //cache_file = new CacheFile4Sbox() + //{ + // enabled = true + //}, //v2ray_api = new V2ray_Api4Sbox() //{ - // listen = $"{Global.Loopback}:{Global.statePort}", + // listen = $"{Global.Loopback}:{Global.StatePort}", // stats = new Stats4Sbox() // { // enabled = true, // } - //} + //}, clash_api = new Clash_Api4Sbox() { - external_controller = $"{Global.Loopback}:{Global.StatePort}", - store_selected = true + external_controller = $"{Global.Loopback}:{LazyConfig.Instance.StatePort}", } }; } return 0; } + + #endregion private gen function + + #region Gen speedtest config + + public int GenerateClientSpeedtestConfig(List selecteds, out SingboxConfig? singboxConfig, out string msg) + { + singboxConfig = null; + try + { + if (_config == null) + { + msg = ResUI.CheckServerSettings; + return -1; + } + + msg = ResUI.InitialConfiguration; + + string result = Utils.GetEmbedText(Global.SingboxSampleClient); + string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound); + if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) + { + msg = ResUI.FailedGetDefaultConfiguration; + return -1; + } + + singboxConfig = JsonUtils.Deserialize(result); + if (singboxConfig == null) + { + msg = ResUI.FailedGenDefaultConfiguration; + return -1; + } + List lstIpEndPoints = new(); + List lstTcpConns = new(); + try + { + lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()); + lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners()); + lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections()); + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + + GenLog(singboxConfig); + GenDns(new(), singboxConfig); + singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts. + singboxConfig.outbounds.RemoveAt(0); + + int httpPort = LazyConfig.Instance.GetLocalPort("speedtest"); + + foreach (var it in selecteds) + { + if (it.configType == EConfigType.Custom) + { + continue; + } + if (it.port <= 0) + { + continue; + } + if (it.configType is EConfigType.VMess or EConfigType.VLESS) + { + var item2 = LazyConfig.Instance.GetProfileItem(it.indexId); + if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id)) + { + continue; + } + } + + //find unuse port + var port = httpPort; + for (int k = httpPort; k < Global.MaxPort; k++) + { + if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0) + { + continue; + } + if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0) + { + continue; + } + //found + port = k; + httpPort = port + 1; + break; + } + + //Port In Used + if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0) + { + continue; + } + it.port = port; + it.allowTest = true; + + //inbound + Inbound4Sbox inbound = new() + { + listen = Global.Loopback, + listen_port = port, + type = Global.InboundHttp + }; + inbound.tag = Global.InboundHttp + inbound.listen_port.ToString(); + singboxConfig.inbounds.Add(inbound); + + //outbound + var item = LazyConfig.Instance.GetProfileItem(it.indexId); + if (item is null) + { + continue; + } + if (item.configType == EConfigType.Shadowsocks + && !Global.SsSecuritysInSingbox.Contains(item.security)) + { + continue; + } + if (item.configType == EConfigType.VLESS + && !Global.Flows.Contains(item.flow)) + { + continue; + } + + var outbound = JsonUtils.Deserialize(txtOutbound); + GenOutbound(item, outbound); + outbound.tag = Global.ProxyTag + inbound.listen_port.ToString(); + singboxConfig.outbounds.Add(outbound); + + //rule + Rule4Sbox rule = new() + { + inbound = new List { inbound.tag }, + outbound = outbound.tag + }; + singboxConfig.route.rules.Add(rule); + } + + //msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary()); + return 0; + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + msg = ResUI.FailedGenDefaultConfiguration; + return -1; + } + } + + #endregion Gen speedtest config } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Handler/CoreConfigV2ray.cs b/v2rayN/v2rayN/Handler/CoreConfigV2ray.cs index b592239a..8a650a73 100644 --- a/v2rayN/v2rayN/Handler/CoreConfigV2ray.cs +++ b/v2rayN/v2rayN/Handler/CoreConfigV2ray.cs @@ -1,8 +1,5 @@ -using Newtonsoft.Json.Linq; -using System.IO; -using System.Net; +using System.Net; using System.Net.NetworkInformation; -using v2rayN.Base; using v2rayN.Mode; using v2rayN.Resx; @@ -38,7 +35,7 @@ namespace v2rayN.Handler return -1; } - v2rayConfig = Utils.FromJson(result); + v2rayConfig = JsonUtils.Deserialize(result); if (v2rayConfig == null) { msg = ResUI.FailedGenDefaultConfiguration; @@ -53,6 +50,8 @@ namespace v2rayN.Handler GenOutbound(node, v2rayConfig.outbounds[0]); + GenMoreOutbounds(node, v2rayConfig); + GenDns(v2rayConfig); GenStatistic(v2rayConfig); @@ -61,13 +60,15 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog("GenerateClientConfig4V2ray", ex); + Logging.SaveLog("GenerateClientConfig4V2ray", ex); msg = ResUI.FailedGenDefaultConfiguration; return -1; } return 0; } + #region private gen function + private int GenLog(V2rayConfig v2rayConfig) { try @@ -88,7 +89,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -137,7 +138,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -150,7 +151,7 @@ namespace v2rayN.Handler return null; } - var inbound = Utils.FromJson(result); + var inbound = JsonUtils.Deserialize(result); if (inbound == null) { return null; @@ -183,12 +184,12 @@ namespace v2rayN.Handler { v2rayConfig.routing.domainStrategy = routing.domainStrategy; } - var rules = Utils.FromJson>(routing.ruleSet); + var rules = JsonUtils.Deserialize>(routing.ruleSet); foreach (var item in rules) { if (item.enabled) { - var item2 = Utils.FromJson(Utils.ToJson(item)); + var item2 = JsonUtils.Deserialize(JsonUtils.Serialize(item)); GenRoutingUserRule(item2, v2rayConfig); } } @@ -199,10 +200,10 @@ namespace v2rayN.Handler var lockedItem = ConfigHandler.GetLockedRoutingItem(_config); if (lockedItem != null) { - var rules = Utils.FromJson>(lockedItem.ruleSet); + var rules = JsonUtils.Deserialize>(lockedItem.ruleSet); foreach (var item in rules) { - var item2 = Utils.FromJson(Utils.ToJson(item)); + var item2 = JsonUtils.Deserialize(JsonUtils.Serialize(item)); GenRoutingUserRule(item2, v2rayConfig); } } @@ -211,12 +212,12 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } - private int GenRoutingUserRule(RulesItem4Ray rules, V2rayConfig v2rayConfig) + private int GenRoutingUserRule(RulesItem4Ray? rules, V2rayConfig v2rayConfig) { try { @@ -248,7 +249,7 @@ namespace v2rayN.Handler var hasDomainIp = false; if (rules.domain?.Count > 0) { - var it = Utils.DeepCopy(rules); + var it = JsonUtils.DeepCopy(rules); it.ip = null; it.type = "field"; for (int k = it.domain.Count - 1; k >= 0; k--) @@ -264,7 +265,7 @@ namespace v2rayN.Handler } if (rules.ip?.Count > 0) { - var it = Utils.DeepCopy(rules); + var it = JsonUtils.DeepCopy(rules); it.domain = null; it.type = "field"; v2rayConfig.routing.rules.Add(it); @@ -277,7 +278,7 @@ namespace v2rayN.Handler || (rules.inboundTag?.Count > 0) ) { - var it = Utils.DeepCopy(rules); + var it = JsonUtils.DeepCopy(rules); it.type = "field"; v2rayConfig.routing.rules.Add(it); } @@ -285,7 +286,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -474,7 +475,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -496,7 +497,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -684,7 +685,7 @@ namespace v2rayN.Handler pathHttp = string.Join("\",\"", arrPath); } request = request.Replace("$requestPath$", $"\"{pathHttp}\""); - tcpSettings.header.request = Utils.FromJson(request); + tcpSettings.header.request = JsonUtils.Deserialize(request); streamSettings.tcpSettings = tcpSettings; } @@ -693,7 +694,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -718,46 +719,35 @@ namespace v2rayN.Handler outbound.settings.userLevel = 0; } - var obj = Utils.ParseJson(normalDNS) ?? new JObject(); - - if (!obj.ContainsKey("servers")) + var obj = JsonUtils.ParseJson(normalDNS); + if (obj is null) { - List servers = new(); + List servers = []; string[] arrDNS = normalDNS.Split(','); foreach (string str in arrDNS) { servers.Add(str); } - obj["servers"] = JArray.FromObject(servers); + obj = JsonUtils.ParseJson("{}"); + obj["servers"] = JsonUtils.SerializeToNode(servers); } + // 追加至 dns 设置 if (item.useSystemHosts) { - var hostfile = @"C:\Windows\System32\drivers\etc\hosts"; - - if (File.Exists(hostfile)) + var systemHosts = Utils.GetSystemHosts(); + if (systemHosts.Count > 0) { - var hosts = File.ReadAllText(hostfile).Replace("\r", ""); - var hostsList = hosts.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - - // 获取系统hosts - var systemHosts = new Dictionary(); - foreach (var host in hostsList) + var normalHost = obj["hosts"]; + if (normalHost != null) { - if (host.StartsWith("#")) continue; - var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); - if (hostItem.Length < 2) continue; - systemHosts.Add(hostItem[1], hostItem[0]); + foreach (var host in systemHosts) + { + if (normalHost[host.Key] != null) + continue; + normalHost[host.Key] = host.Value; + } } - - // 追加至 dns 设置 - var normalHost = obj["hosts"] ?? new JObject(); - foreach (var host in systemHosts) - { - if (normalHost[host.Key] != null) continue; - normalHost[host.Key] = host.Value; - } - obj["hosts"] = normalHost; } } @@ -765,7 +755,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return 0; } @@ -798,7 +788,7 @@ namespace v2rayN.Handler Inboundsettings4Ray apiInboundSettings = new(); apiInbound.tag = tag; apiInbound.listen = Global.Loopback; - apiInbound.port = Global.StatePort; + apiInbound.port = LazyConfig.Instance.StatePort; apiInbound.protocol = Global.InboundAPIProtocal; apiInboundSettings.address = Global.Loopback; apiInbound.settings = apiInboundSettings; @@ -820,33 +810,101 @@ namespace v2rayN.Handler return 0; } + private int GenMoreOutbounds(ProfileItem node, V2rayConfig v2rayConfig) + { + if (node.subid.IsNullOrEmpty()) + { + return 0; + } + try + { + var subItem = LazyConfig.Instance.GetSubItem(node.subid); + if (subItem is null) + { + return 0; + } + + //current proxy + var outbound = v2rayConfig.outbounds[0]; + var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound); + + //Previous proxy + var prevNode = LazyConfig.Instance.GetProfileItemViaRemarks(subItem.prevProfile!); + if (prevNode is not null + && prevNode.configType != EConfigType.Custom + && prevNode.configType != EConfigType.Hysteria2 + && prevNode.configType != EConfigType.Tuic + && prevNode.configType != EConfigType.Wireguard) + { + var prevOutbound = JsonUtils.Deserialize(txtOutbound); + GenOutbound(prevNode, prevOutbound); + prevOutbound.tag = $"{Global.ProxyTag}2"; + v2rayConfig.outbounds.Add(prevOutbound); + + outbound.streamSettings.sockopt = new() + { + dialerProxy = prevOutbound.tag + }; + } + + //Next proxy + var nextNode = LazyConfig.Instance.GetProfileItemViaRemarks(subItem.nextProfile!); + if (nextNode is not null + && nextNode.configType != EConfigType.Custom + && nextNode.configType != EConfigType.Hysteria2 + && nextNode.configType != EConfigType.Tuic + && nextNode.configType != EConfigType.Wireguard) + { + var nextOutbound = JsonUtils.Deserialize(txtOutbound); + GenOutbound(nextNode, nextOutbound); + nextOutbound.tag = Global.ProxyTag; + v2rayConfig.outbounds.Insert(0, nextOutbound); + + outbound.tag = $"{Global.ProxyTag}1"; + nextOutbound.streamSettings.sockopt = new() + { + dialerProxy = outbound.tag + }; + } + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + + return 0; + } + + #endregion private gen function + #region Gen speedtest config - public string GenerateClientSpeedtestConfigString(List selecteds, out string msg) + public int GenerateClientSpeedtestConfig(List selecteds, out V2rayConfig? v2rayConfig, out string msg) { + v2rayConfig = null; try { if (_config == null) { msg = ResUI.CheckServerSettings; - return ""; + return -1; } msg = ResUI.InitialConfiguration; - + string result = Utils.GetEmbedText(Global.V2raySampleClient); string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound); if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) { msg = ResUI.FailedGetDefaultConfiguration; - return ""; + return -1; } - var v2rayConfig = Utils.FromJson(result); + v2rayConfig = JsonUtils.Deserialize(result); if (v2rayConfig == null) { msg = ResUI.FailedGenDefaultConfiguration; - return ""; + return -1; } List lstIpEndPoints = new(); List lstTcpConns = new(); @@ -858,11 +916,12 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } GenLog(v2rayConfig); v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts. + v2rayConfig.outbounds.RemoveAt(0); int httpPort = LazyConfig.Instance.GetLocalPort("speedtest"); @@ -938,7 +997,7 @@ namespace v2rayN.Handler continue; } - var outbound = Utils.FromJson(txtOutbound); + var outbound = JsonUtils.Deserialize(txtOutbound); GenOutbound(item, outbound); outbound.tag = Global.ProxyTag + inbound.port.ToString(); v2rayConfig.outbounds.Add(outbound); @@ -954,13 +1013,13 @@ namespace v2rayN.Handler } //msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary()); - return Utils.ToJson(v2rayConfig); + return 0; } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); msg = ResUI.FailedGenDefaultConfiguration; - return ""; + return -1; } } diff --git a/v2rayN/v2rayN/Handler/CoreHandler.cs b/v2rayN/v2rayN/Handler/CoreHandler.cs index 95729e63..f352def5 100644 --- a/v2rayN/v2rayN/Handler/CoreHandler.cs +++ b/v2rayN/v2rayN/Handler/CoreHandler.cs @@ -45,6 +45,12 @@ namespace v2rayN.Handler ShowMsg(false, msg); ShowMsg(true, $"{node.GetSummary()}"); CoreStop(); + if (_config.tunModeItem.enableTun) + { + Thread.Sleep(1000); + Utils.RemoveTunDevice(); + } + CoreStart(node); //In tun mode, do a delay check and restart the core @@ -59,7 +65,7 @@ namespace v2rayN.Handler { CoreStart(node); ShowMsg(false, "Tun mode restart the core once"); - Utils.SaveLog("Tun mode restart the core once"); + Logging.SaveLog("Tun mode restart the core once"); } } }); @@ -67,18 +73,19 @@ namespace v2rayN.Handler } } - public int LoadCoreConfigString(List _selecteds) + public int LoadCoreConfigSpeedtest(List selecteds) { int pid = -1; - string configStr = CoreConfigHandler.GenerateClientSpeedtestConfigString(_config, _selecteds, out string msg); - if (configStr == "") + var coreType = selecteds.Exists(t => t.configType == EConfigType.Hysteria2 || t.configType == EConfigType.Tuic || t.configType == EConfigType.Wireguard) ? ECoreType.sing_box : ECoreType.Xray; + string configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName); + if (CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType, out string msg) != 0) { ShowMsg(false, msg); } else { ShowMsg(false, msg); - pid = CoreStartViaString(configStr); + pid = CoreStartSpeedtest(configPath, coreType); } return pid; } @@ -115,11 +122,11 @@ namespace v2rayN.Handler } foreach (string vName in it.coreExes) { - Process[] existing = Process.GetProcessesByName(vName); + var existing = Process.GetProcessesByName(vName); foreach (Process p in existing) { string? path = p.MainModule?.FileName; - if (path == $"{Utils.GetBinPath(vName, it.coreType)}.exe") + if (path == $"{Utils.GetBinPath(vName, it.coreType.ToString())}.exe") { KillProcess(p); } @@ -130,7 +137,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } @@ -138,22 +145,22 @@ namespace v2rayN.Handler { try { - Process _p = Process.GetProcessById(pid); + var _p = Process.GetProcessById(pid); KillProcess(_p); } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } - private string CoreFindExe(CoreInfo coreInfo) + private string CoreFindexe(CoreInfo coreInfo) { string fileName = string.Empty; foreach (string name in coreInfo.coreExes) { string vName = $"{name}.exe"; - vName = Utils.GetBinPath(vName, coreInfo.coreType); + vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString()); if (File.Exists(vName)) { fileName = vName; @@ -162,8 +169,8 @@ namespace v2rayN.Handler } if (Utils.IsNullOrEmpty(fileName)) { - string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl); - Utils.SaveLog(msg); + string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType.ToString()), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl); + Logging.SaveLog(msg); ShowMsg(false, msg); } return fileName; @@ -171,6 +178,7 @@ namespace v2rayN.Handler private void CoreStart(ProfileItem node) { + ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}"); ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))); ECoreType coreType; @@ -218,14 +226,15 @@ namespace v2rayN.Handler } } - private int CoreStartViaString(string configStr) + private 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 = LazyConfig.Instance.GetCoreInfo(ECoreType.Xray); - string fileName = CoreFindExe(coreInfo); + string fileName = CoreFindexe(coreInfo); if (fileName == "") return -1; Process p = new() @@ -269,16 +278,14 @@ namespace v2rayN.Handler if (p.WaitForExit(1000)) { - p.CancelErrorRead(); throw new Exception(p.StandardError.ReadToEnd()); } - Global.ProcessJob.AddProcess(p.Handle); - return p.Id; + return proc.Id; } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); string msg = ex.Message; ShowMsg(false, msg); return -1; @@ -290,6 +297,8 @@ namespace v2rayN.Handler _updateFunc(updateToTrayTooltip, msg); } + #endregion Private + #region Process private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog, Action update) @@ -303,7 +312,7 @@ namespace v2rayN.Handler } Process proc = new() { - StartInfo = new ProcessStartInfo + StartInfo = new() { FileName = fileName, Arguments = string.Format(coreInfo.arguments, configPath), @@ -348,33 +357,37 @@ namespace v2rayN.Handler throw new Exception(displayLog ? proc.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)"); } - Global.ProcessJob.AddProcess(proc.Handle); + LazyConfig.Instance.AddProcess(proc.Handle); return proc; } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); string msg = ex.Message; update(true, msg); return null; } } - private void KillProcess(Process p) + private void KillProcess(Process? proc) { + if (proc is null) + { + return; + } try { - p.CloseMainWindow(); - p.WaitForExit(100); - if (!p.HasExited) + proc.CloseMainWindow(); + proc.WaitForExit(100); + if (!proc.HasExited) { - p.Kill(); - p.WaitForExit(100); + proc.Kill(); + proc.WaitForExit(100); } } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } diff --git a/v2rayN/v2rayN/Handler/DownloadHandle.cs b/v2rayN/v2rayN/Handler/DownloadHandle.cs index 54edadf7..62bb2d62 100644 --- a/v2rayN/v2rayN/Handler/DownloadHandle.cs +++ b/v2rayN/v2rayN/Handler/DownloadHandle.cs @@ -4,7 +4,6 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Sockets; -using v2rayN.Base; using v2rayN.Resx; namespace v2rayN.Handler @@ -84,7 +83,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) @@ -111,7 +110,7 @@ namespace v2rayN.Handler } else { - Utils.SaveLog("StatusCode error: " + url); + Logging.SaveLog("StatusCode error: " + url); return null; } } @@ -128,7 +127,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { @@ -146,7 +145,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { @@ -166,7 +165,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { @@ -212,7 +211,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { @@ -243,7 +242,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); Error?.Invoke(this, new ErrorEventArgs(ex)); if (ex.InnerException != null) { @@ -270,13 +269,13 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return -1; } } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return -1; } } @@ -299,7 +298,7 @@ namespace v2rayN.Handler responseTime = timer.Elapsed.Milliseconds; } - catch (Exception ex) + catch //(Exception ex) { //Utils.SaveLog(ex.Message, ex); } diff --git a/v2rayN/v2rayN/Handler/LazyConfig.cs b/v2rayN/v2rayN/Handler/LazyConfig.cs index b9f259de..51231eba 100644 --- a/v2rayN/v2rayN/Handler/LazyConfig.cs +++ b/v2rayN/v2rayN/Handler/LazyConfig.cs @@ -1,5 +1,4 @@ using System.Runtime.Intrinsics.X86; -using v2rayN.Base; using v2rayN.Mode; namespace v2rayN.Handler @@ -12,8 +11,14 @@ namespace v2rayN.Handler public static LazyConfig Instance => _instance.Value; + private int _statePort; + public int StatePort { get => _statePort; } + private Job _processJob = new(); + public LazyConfig() { + _statePort = Utils.GetFreePort(); + SqliteHelper.Instance.CreateTable(); SqliteHelper.Instance.CreateTable(); SqliteHelper.Instance.CreateTable(); @@ -63,6 +68,15 @@ namespace v2rayN.Handler } return localPort; } + + public void AddProcess(IntPtr processHandle) + { + _processJob.AddProcess(processHandle); + } + + #endregion Config + + #region SqliteHelper public List SubItems() { @@ -130,6 +144,15 @@ namespace v2rayN.Handler return SqliteHelper.Instance.Table().FirstOrDefault(it => it.indexId == indexId); } + public ProfileItem? GetProfileItemViaRemarks(string remarks) + { + if (Utils.IsNullOrEmpty(remarks)) + { + return null; + } + return SqliteHelper.Instance.Table().FirstOrDefault(it => it.remarks == remarks); + } + public List RoutingItems() { return SqliteHelper.Instance.Table().Where(it => it.locked == false).OrderBy(t => t.sort).ToList(); @@ -150,21 +173,24 @@ namespace v2rayN.Handler return SqliteHelper.Instance.Table().FirstOrDefault(it => it.coreType == eCoreType); } - #endregion Config + #endregion SqliteHelper #region Core Type public List GetShadowsocksSecuritys(ProfileItem profileItem) { - if (GetCoreType(profileItem, EConfigType.Shadowsocks) == ECoreType.v2fly) + var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks); + switch (coreType) { - return Global.SsSecuritys; - } - if (GetCoreType(profileItem, EConfigType.Shadowsocks) == ECoreType.Xray) - { - return Global.SsSecuritysInXray; - } + case ECoreType.v2fly: + return Global.SsSecuritys; + case ECoreType.Xray: + return Global.SsSecuritysInXray; + + case ECoreType.sing_box: + return Global.SsSecuritysInSingbox; + } return Global.SsSecuritysInSagerNet; } @@ -268,7 +294,7 @@ namespace v2rayN.Handler { coreType = ECoreType.Xray, coreExes = new List { "xray", "wxray" }, - arguments = "", + arguments = "run {0}", coreUrl = Global.XrayCoreUrl, coreReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), coreDownloadUrl32 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", @@ -355,7 +381,7 @@ namespace v2rayN.Handler { coreType = ECoreType.sing_box, coreExes = new List { "sing-box-client", "sing-box" }, - arguments = "run{0}", + arguments = "run {0} --disable-color", coreUrl = Global.SingboxCoreUrl, redirectInfo = true, coreReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), diff --git a/v2rayN/v2rayN/Handler/MainFormHandler.cs b/v2rayN/v2rayN/Handler/MainFormHandler.cs index 24989615..960c6ab9 100644 --- a/v2rayN/v2rayN/Handler/MainFormHandler.cs +++ b/v2rayN/v2rayN/Handler/MainFormHandler.cs @@ -42,7 +42,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return Properties.Resources.NotifyIcon1; } } @@ -112,7 +112,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return null; } } @@ -163,7 +163,7 @@ namespace v2rayN.Handler private async Task UpdateTaskRunSubscription(Config config, Action update) { await Task.Delay(60000); - Utils.SaveLog("UpdateTaskRunSubscription"); + Logging.SaveLog("UpdateTaskRunSubscription"); var updateHandle = new UpdateHandle(); while (true) @@ -180,7 +180,7 @@ namespace v2rayN.Handler { update(success, msg); if (success) - Utils.SaveLog("subscription" + msg); + Logging.SaveLog("subscription" + msg); }); item.updateTime = updateTime; ConfigHandler.AddSubItem(config, item); @@ -196,7 +196,7 @@ namespace v2rayN.Handler var autoUpdateGeoTime = DateTime.Now; await Task.Delay(1000 * 120); - Utils.SaveLog("UpdateTaskRunGeo"); + Logging.SaveLog("UpdateTaskRunGeo"); var updateHandle = new UpdateHandle(); while (true) diff --git a/v2rayN/v2rayN/Handler/ProfileExHandler.cs b/v2rayN/v2rayN/Handler/ProfileExHandler.cs index 0b755a06..13447e9e 100644 --- a/v2rayN/v2rayN/Handler/ProfileExHandler.cs +++ b/v2rayN/v2rayN/Handler/ProfileExHandler.cs @@ -1,6 +1,5 @@ using System.Collections.Concurrent; using System.Reactive.Linq; -using v2rayN.Base; using v2rayN.Mode; namespace v2rayN.Handler @@ -82,7 +81,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } diff --git a/v2rayN/v2rayN/Handler/ProxySetting.cs b/v2rayN/v2rayN/Handler/ProxySetting.cs index e728f3f4..9f01c31f 100644 --- a/v2rayN/v2rayN/Handler/ProxySetting.cs +++ b/v2rayN/v2rayN/Handler/ProxySetting.cs @@ -1,5 +1,4 @@ -using Microsoft.Win32; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using static v2rayN.Handler.ProxySetting.InternetConnectionOption; namespace v2rayN.Handler @@ -320,27 +319,5 @@ namespace v2rayN.Handler ref int lpcEntries // Number of entries written to the buffer ); } - - //判断是否使用代理 - public static bool UsedProxy() - { - using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); - if (rk?.GetValue("ProxyEnable")?.ToString() == "1") - { - return true; - } - else - { - return false; - } - } - - //获得代理的IP和端口 - public static string? GetProxyProxyServer() - { - using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); - string ProxyServer = rk.GetValue("ProxyServer").ToString(); - return ProxyServer; - } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Handler/ShareHandler.cs b/v2rayN/v2rayN/Handler/ShareHandler.cs index 9ac2ae05..aa66eb5a 100644 --- a/v2rayN/v2rayN/Handler/ShareHandler.cs +++ b/v2rayN/v2rayN/Handler/ShareHandler.cs @@ -1,7 +1,5 @@ using System.Collections.Specialized; using System.Text.RegularExpressions; -using System.Web; -using v2rayN.Base; using v2rayN.Mode; using v2rayN.Resx; @@ -31,6 +29,7 @@ namespace v2rayN.Handler EConfigType.VLESS => ShareVLESS(item), EConfigType.Hysteria2 => ShareHysteria2(item), EConfigType.Tuic => ShareTuic(item), + EConfigType.Wireguard => ShareWireguard(item), _ => null, }; @@ -38,7 +37,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); return ""; } } @@ -49,12 +48,12 @@ namespace v2rayN.Handler VmessQRCode vmessQRCode = new() { - v = item.configVersion.ToString(), + v = item.configVersion, ps = item.remarks.TrimEx(), add = item.address, - port = item.port.ToString(), + port = item.port, id = item.id, - aid = item.alterId.ToString(), + aid = item.alterId, scy = item.security, net = item.network, type = item.headerType, @@ -66,7 +65,7 @@ namespace v2rayN.Handler fp = item.fingerprint }; - url = Utils.ToJson(vmessQRCode); + url = JsonUtils.Serialize(vmessQRCode); url = Utils.Base64Encode(url); url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}"; @@ -181,6 +180,11 @@ namespace v2rayN.Handler { dicQuery.Add("alpn", Utils.UrlEncode(item.alpn)); } + if (!Utils.IsNullOrEmpty(item.path)) + { + dicQuery.Add("obfs", "salamander"); + dicQuery.Add("obfs-password", Utils.UrlEncode(item.path)); + } dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0"); string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); @@ -189,7 +193,7 @@ namespace v2rayN.Handler item.id, GetIpv6(item.address), item.port); - url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}{query}{remark}"; + url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}/{query}{remark}"; return url; } @@ -222,6 +226,42 @@ namespace v2rayN.Handler return url; } + private static string ShareWireguard(ProfileItem item) + { + string url = string.Empty; + string remark = string.Empty; + if (!Utils.IsNullOrEmpty(item.remarks)) + { + remark = "#" + Utils.UrlEncode(item.remarks); + } + + var dicQuery = new Dictionary(); + if (!Utils.IsNullOrEmpty(item.publicKey)) + { + dicQuery.Add("publickey", Utils.UrlEncode(item.publicKey)); + } + if (!Utils.IsNullOrEmpty(item.path)) + { + dicQuery.Add("reserved", Utils.UrlEncode(item.path)); + } + if (!Utils.IsNullOrEmpty(item.requestHost)) + { + dicQuery.Add("address", Utils.UrlEncode(item.requestHost)); + } + if (!Utils.IsNullOrEmpty(item.shortId)) + { + dicQuery.Add("mtu", Utils.UrlEncode(item.shortId)); + } + string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); + + url = string.Format("{0}@{1}:{2}", + Utils.UrlEncode(item.id), + GetIpv6(item.address), + item.port); + url = $"{Global.ProtocolShares[EConfigType.Wireguard]}{url}/{query}{remark}"; + return url; + } + private static string GetIpv6(string address) { return Utils.IsIpv6(address) ? $"[{address}]" : address; @@ -345,14 +385,12 @@ namespace v2rayN.Handler /// public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg) { - msg = string.Empty; - - ProfileItem profileItem = new(); + msg = ResUI.ConfigurationFormatIncorrect; + ProfileItem? profileItem; try { - //载入配置文件 - string result = clipboardData.TrimEx();// Utils.GetClipboardData(); + string result = clipboardData.TrimEx(); if (Utils.IsNullOrEmpty(result)) { msg = ResUI.FailedReadConfiguration; @@ -373,8 +411,6 @@ namespace v2rayN.Handler } else if (result.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks])) { - msg = ResUI.ConfigurationFormatIncorrect; - profileItem = ResolveSSLegacy(result) ?? ResolveSip002(result); if (profileItem == null) { @@ -389,8 +425,6 @@ namespace v2rayN.Handler } else if (result.StartsWith(Global.ProtocolShares[EConfigType.Socks])) { - msg = ResUI.ConfigurationFormatIncorrect; - profileItem = ResolveSocksNew(result) ?? ResolveSocks(result); if (profileItem == null) { @@ -405,8 +439,6 @@ namespace v2rayN.Handler } else if (result.StartsWith(Global.ProtocolShares[EConfigType.Trojan])) { - msg = ResUI.ConfigurationFormatIncorrect; - profileItem = ResolveTrojan(result); } else if (result.StartsWith(Global.ProtocolShares[EConfigType.VLESS])) @@ -415,14 +447,16 @@ namespace v2rayN.Handler } else if (result.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || result.StartsWith(Global.Hysteria2ProtocolShare)) { - msg = ResUI.ConfigurationFormatIncorrect; - profileItem = ResolveHysteria2(result); } else if (result.StartsWith(Global.ProtocolShares[EConfigType.Tuic])) { profileItem = ResolveTuic(result); } + else if (result.StartsWith(Global.ProtocolShares[EConfigType.Wireguard])) + { + profileItem = ResolveWireguard(result); + } else { msg = ResUI.NonvmessOrssProtocol; @@ -431,7 +465,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); msg = ResUI.Incorrectconfiguration; return null; } @@ -451,7 +485,7 @@ namespace v2rayN.Handler result = Utils.Base64Decode(result); //转成Json - VmessQRCode? vmessQRCode = Utils.FromJson(result); + VmessQRCode? vmessQRCode = JsonUtils.Deserialize(result); if (vmessQRCode == null) { msg = ResUI.FailedConversionConfiguration; @@ -540,7 +574,7 @@ namespace v2rayN.Handler i.address = u.IdnHost; i.port = u.Port; i.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); - var q = HttpUtility.ParseQueryString(u.Query); + var query = Utils.ParseQueryString(u.Query); var m = StdVmessUserInfo.Match(u.UserInfo); if (!m.Success) return null; @@ -566,17 +600,17 @@ namespace v2rayN.Handler switch (i.network) { case "tcp": - string t1 = q["type"] ?? "none"; + string t1 = query["type"] ?? "none"; i.headerType = t1; break; case "kcp": - i.headerType = q["type"] ?? "none"; + i.headerType = query["type"] ?? "none"; break; case "ws": - string p1 = q["path"] ?? "/"; - string h1 = q["host"] ?? ""; + string p1 = query["path"] ?? "/"; + string h1 = query["host"] ?? ""; i.requestHost = Utils.UrlDecode(h1); i.path = p1; break; @@ -584,16 +618,16 @@ namespace v2rayN.Handler case "http": case "h2": i.network = "h2"; - string p2 = q["path"] ?? "/"; - string h2 = q["host"] ?? ""; + string p2 = query["path"] ?? "/"; + string h2 = query["host"] ?? ""; i.requestHost = Utils.UrlDecode(h2); i.path = p2; break; case "quic": - string s = q["security"] ?? "none"; - string k = q["key"] ?? ""; - string t3 = q["type"] ?? "none"; + string s = query["security"] ?? "none"; + string k = query["key"] ?? ""; + string t3 = query["type"] ?? "none"; i.headerType = t3; i.requestHost = Utils.UrlDecode(s); i.path = k; @@ -648,7 +682,7 @@ namespace v2rayN.Handler server.id = userInfoParts[1]; } - NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query); + var queryParameters = Utils.ParseQueryString(parsedUrl.Query); if (queryParameters["plugin"] != null) { //obfs-host exists @@ -797,9 +831,9 @@ namespace v2rayN.Handler item.address = url.IdnHost; item.port = url.Port; item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); - item.id = url.UserInfo; + item.id = Utils.UrlDecode(url.UserInfo); - var query = HttpUtility.ParseQueryString(url.Query); + var query = Utils.ParseQueryString(url.Query); ResolveStdTransport(query, ref item); return item; @@ -818,9 +852,9 @@ namespace v2rayN.Handler item.address = url.IdnHost; item.port = url.Port; item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); - item.id = url.UserInfo; + item.id = Utils.UrlDecode(url.UserInfo); - var query = HttpUtility.ParseQueryString(url.Query); + var query = Utils.ParseQueryString(url.Query); item.security = query["encryption"] ?? "none"; item.streamSecurity = query["security"] ?? ""; ResolveStdTransport(query, ref item); @@ -840,10 +874,11 @@ namespace v2rayN.Handler item.address = url.IdnHost; item.port = url.Port; item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); - item.id = url.UserInfo; + item.id = Utils.UrlDecode(url.UserInfo); - var query = HttpUtility.ParseQueryString(url.Query); + var query = Utils.ParseQueryString(url.Query); ResolveStdTransport(query, ref item); + item.path = Utils.UrlDecode(query["obfs-password"] ?? ""); item.allowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false"; return item; @@ -868,13 +903,37 @@ namespace v2rayN.Handler item.security = userInfoParts[1]; } - var query = HttpUtility.ParseQueryString(url.Query); + var query = Utils.ParseQueryString(url.Query); ResolveStdTransport(query, ref item); item.headerType = query["congestion_control"] ?? ""; return item; } + private static ProfileItem ResolveWireguard(string result) + { + ProfileItem item = new() + { + configType = EConfigType.Wireguard + }; + + Uri url = new(result); + + item.address = url.IdnHost; + item.port = url.Port; + item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); + item.id = Utils.UrlDecode(url.UserInfo); + + var query = Utils.ParseQueryString(url.Query); + + item.publicKey = Utils.UrlDecode(query["publickey"] ?? ""); + item.path = Utils.UrlDecode(query["reserved"] ?? ""); + item.requestHost = Utils.UrlDecode(query["address"] ?? ""); + item.shortId = Utils.UrlDecode(query["mtu"] ?? ""); + + return item; + } + private static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item) { item.flow = query["flow"] ?? ""; diff --git a/v2rayN/v2rayN/Handler/SpeedtestHandler.cs b/v2rayN/v2rayN/Handler/SpeedtestHandler.cs index 0b828973..e4b660d0 100644 --- a/v2rayN/v2rayN/Handler/SpeedtestHandler.cs +++ b/v2rayN/v2rayN/Handler/SpeedtestHandler.cs @@ -1,6 +1,5 @@ using System.Diagnostics; using System.Net; -using System.Net.NetworkInformation; using System.Net.Sockets; using v2rayN.Mode; using v2rayN.Resx; @@ -9,7 +8,7 @@ namespace v2rayN.Handler { internal class SpeedtestHandler { - private Config _config; + private Config? _config; private CoreHandler _coreHandler; private List _selecteds; private ESpeedActionType _actionType; @@ -30,7 +29,7 @@ namespace v2rayN.Handler _selecteds = new List(); foreach (var it in selecteds) { - if (it.configType == EConfigType.Custom || it.configType == EConfigType.Hysteria2 || it.configType == EConfigType.Tuic) + if (it.configType == EConfigType.Custom) { continue; } @@ -51,7 +50,6 @@ namespace v2rayN.Handler { switch (actionType) { - case ESpeedActionType.Ping: case ESpeedActionType.Tcping: case ESpeedActionType.Realping: UpdateFunc(it.indexId, ResUI.Speedtesting, ""); @@ -73,10 +71,6 @@ namespace v2rayN.Handler switch (actionType) { - case ESpeedActionType.Ping: - Task.Run(RunPing); - break; - case ESpeedActionType.Tcping: Task.Run(RunTcping); break; @@ -95,52 +89,45 @@ namespace v2rayN.Handler } } - private async Task RunPingSubAsync(Action updateFun) + private Task RunTcping() { try { - foreach (var it in _selecteds.Where(it => it.configType != EConfigType.Custom)) + List tasks = []; + foreach (var it in _selecteds) { - try + if (it.configType == EConfigType.Custom) { - Task.Run(() => updateFun(it)); + continue; } - catch (Exception ex) + tasks.Add(Task.Run(() => { - Utils.SaveLog(ex.Message, ex); - } - } + try + { + int time = GetTcpingTime(it.address, it.port); + var output = FormatOut(time, Global.DelayUnit); - await Task.Delay(10); + ProfileExHandler.Instance.SetTestDelay(it.indexId, output); + UpdateFunc(it.indexId, output); + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } + })); + } + Task.WaitAll([.. tasks]); } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } - } - - private async void RunPing() - { - await RunPingSubAsync((ServerTestItem it) => - { - long time = Ping(it.address); - var output = FormatOut(time, Global.DelayUnit); - - ProfileExHandler.Instance.SetTestDelay(it.indexId, output); - UpdateFunc(it.indexId, output); - }); - } - - private async void RunTcping() - { - await RunPingSubAsync((ServerTestItem it) => + finally { - int time = GetTcpingTime(it.address, it.port); - var output = FormatOut(time, Global.DelayUnit); + ProfileExHandler.Instance.SaveTo(); + } - ProfileExHandler.Instance.SetTestDelay(it.indexId, output); - UpdateFunc(it.indexId, output); - }); + return Task.CompletedTask; } private Task RunRealPing() @@ -150,7 +137,7 @@ namespace v2rayN.Handler { string msg = string.Empty; - pid = _coreHandler.LoadCoreConfigString(_selecteds); + pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds); if (pid < 0) { UpdateFunc("", ResUI.FailedToRunCore); @@ -184,7 +171,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } })); } @@ -192,11 +179,14 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } finally { - if (pid > 0) _coreHandler.CoreStopPid(pid); + if (pid > 0) + { + _coreHandler.CoreStopPid(pid); + } ProfileExHandler.Instance.SaveTo(); } @@ -211,7 +201,7 @@ namespace v2rayN.Handler // _selecteds = _selecteds.OrderBy(t => t.delay).ToList(); //} - pid = _coreHandler.LoadCoreConfigString(_selecteds); + pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds); if (pid < 0) { UpdateFunc("", ResUI.FailedToRunCore); @@ -268,7 +258,7 @@ namespace v2rayN.Handler private async Task RunSpeedTestMulti() { int pid = -1; - pid = _coreHandler.LoadCoreConfigString(_selecteds); + pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds); if (pid < 0) { UpdateFunc("", ResUI.FailedToRunCore); @@ -333,7 +323,7 @@ namespace v2rayN.Handler await RunSpeedTestMulti(); } - public async Task GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy) + private async Task GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy) { int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10); //string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status; @@ -346,7 +336,7 @@ namespace v2rayN.Handler try { - if (!IPAddress.TryParse(url, out IPAddress ipAddress)) + if (!IPAddress.TryParse(url, out IPAddress? ipAddress)) { IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(url); ipAddress = ipHostInfo.AddressList[0]; @@ -368,48 +358,11 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return responseTime; } - /// - /// Ping - /// - /// - /// - public long Ping(string host) - { - long roundtripTime = -1; - try - { - int timeout = 30; - int echoNum = 2; - using Ping pingSender = new(); - for (int i = 0; i < echoNum; i++) - { - PingReply reply = pingSender.Send(host, timeout); - if (reply.Status == IPStatus.Success) - { - if (reply.RoundtripTime < 0) - { - continue; - } - if (roundtripTime < 0 || reply.RoundtripTime < roundtripTime) - { - roundtripTime = reply.RoundtripTime; - } - } - } - } - catch (Exception ex) - { - Utils.SaveLog(ex.Message, ex); - return -1; - } - return roundtripTime; - } - private string FormatOut(object time, string unit) { //if (time.ToString().Equals("-1")) diff --git a/v2rayN/v2rayN/Handler/StatisticsHandler.cs b/v2rayN/v2rayN/Handler/StatisticsHandler.cs index 7e3f9dc0..27071f01 100644 --- a/v2rayN/v2rayN/Handler/StatisticsHandler.cs +++ b/v2rayN/v2rayN/Handler/StatisticsHandler.cs @@ -1,6 +1,5 @@ using System.Net; using System.Net.Sockets; -using v2rayN.Base; using v2rayN.Mode; namespace v2rayN.Handler @@ -29,7 +28,6 @@ namespace v2rayN.Handler _updateFunc = update; Init(); - Global.StatePort = GetFreePort(); _statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat); _statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat); @@ -44,7 +42,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } @@ -63,7 +61,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } @@ -81,6 +79,10 @@ namespace v2rayN.Handler { GetServerStatItem(_config.indexId); + if (_serverStatItem is null) + { + return; + } if (server.proxyUp != 0 || server.proxyDown != 0) { _serverStatItem.todayUp += server.proxyUp; @@ -88,15 +90,13 @@ namespace v2rayN.Handler _serverStatItem.totalUp += server.proxyUp; _serverStatItem.totalDown += server.proxyDown; } - if (Global.ShowInTaskbar) - { - server.indexId = _config.indexId; - server.todayUp = _serverStatItem.todayUp; - server.todayDown = _serverStatItem.todayDown; - server.totalUp = _serverStatItem.totalUp; - server.totalDown = _serverStatItem.totalDown; - _updateFunc(server); - } + + server.indexId = _config.indexId; + server.todayUp = _serverStatItem.todayUp; + server.todayDown = _serverStatItem.todayDown; + server.totalUp = _serverStatItem.totalUp; + server.totalDown = _serverStatItem.totalDown; + _updateFunc(server); } private void GetServerStatItem(string indexId) @@ -143,14 +143,12 @@ namespace v2rayN.Handler { return defaultPort; } - for (int i = 0; i < 3; i++) - { - TcpListener l = new(IPAddress.Loopback, 0); - l.Start(); - int port = ((IPEndPoint)l.LocalEndpoint).Port; - l.Stop(); - return port; - } + + TcpListener l = new(IPAddress.Loopback, 0); + l.Start(); + int port = ((IPEndPoint)l.LocalEndpoint).Port; + l.Stop(); + return port; } catch { diff --git a/v2rayN/v2rayN/Handler/StatisticsSingbox.cs b/v2rayN/v2rayN/Handler/StatisticsSingbox.cs index 14ee1c62..fc559e54 100644 --- a/v2rayN/v2rayN/Handler/StatisticsSingbox.cs +++ b/v2rayN/v2rayN/Handler/StatisticsSingbox.cs @@ -27,7 +27,7 @@ namespace v2rayN.Handler try { - url = $"ws://{Global.Loopback}:{Global.StatePort}/traffic"; + url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort}/traffic"; if (webSocket == null) { @@ -51,7 +51,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } @@ -113,7 +113,7 @@ namespace v2rayN.Handler up = 0; down = 0; try { - var trafficItem = Utils.FromJson(source); + var trafficItem = JsonUtils.Deserialize(source); if (trafficItem != null) { up = trafficItem.up; diff --git a/v2rayN/v2rayN/Handler/StatisticsV2ray.cs b/v2rayN/v2rayN/Handler/StatisticsV2ray.cs index d2af9f2b..128895fc 100644 --- a/v2rayN/v2rayN/Handler/StatisticsV2ray.cs +++ b/v2rayN/v2rayN/Handler/StatisticsV2ray.cs @@ -8,8 +8,8 @@ namespace v2rayN.Handler internal class StatisticsV2ray { private Mode.Config _config; - private GrpcChannel _channel; - private StatsService.StatsServiceClient _client; + private GrpcChannel? _channel; + private StatsService.StatsServiceClient? _client; private bool _exitFlag; private Action _updateFunc; @@ -26,10 +26,17 @@ namespace v2rayN.Handler private void GrpcInit() { - if (_channel == null) + if (_channel is null) { - _channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{Global.StatePort}"); - _client = new StatsService.StatsServiceClient(_channel); + try + { + _channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort}"); + _client = new StatsService.StatsServiceClient(_channel); + } + catch (Exception ex) + { + Logging.SaveLog(ex.Message, ex); + } } } @@ -44,7 +51,7 @@ namespace v2rayN.Handler { try { - if (_channel.State == ConnectivityState.Ready) + if (_channel?.State == ConnectivityState.Ready) { QueryStatsResponse? res = null; try diff --git a/v2rayN/v2rayN/Handler/SysProxyHandle.cs b/v2rayN/v2rayN/Handler/SysProxyHandle.cs index ae1b66cf..a840d011 100644 --- a/v2rayN/v2rayN/Handler/SysProxyHandle.cs +++ b/v2rayN/v2rayN/Handler/SysProxyHandle.cs @@ -50,7 +50,7 @@ namespace v2rayN.Handler } if (type == ESysProxyType.ForcedChange) { - var strExceptions = $"{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}"; + var strExceptions = $";{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}"; var strProxy = string.Empty; if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol)) @@ -87,7 +87,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } return true; } diff --git a/v2rayN/v2rayN/Handler/UpdateHandle.cs b/v2rayN/v2rayN/Handler/UpdateHandle.cs index 0b677cde..bf541c0b 100644 --- a/v2rayN/v2rayN/Handler/UpdateHandle.cs +++ b/v2rayN/v2rayN/Handler/UpdateHandle.cs @@ -6,10 +6,8 @@ using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Windows; -using v2rayN.Base; using v2rayN.Mode; using v2rayN.Resx; -using v2rayN.Tool; namespace v2rayN.Handler { @@ -56,7 +54,7 @@ namespace v2rayN.Handler StartInfo = new ProcessStartInfo { FileName = "v2rayUpgrade.exe", - Arguments = $"\"{fileName}\"", + Arguments = fileName.AppendQuotes(), WorkingDirectory = Utils.StartupPath() } }; @@ -88,7 +86,10 @@ namespace v2rayN.Handler _updateFunc(false, args.Msg); url = args.Url; - _ = askToDownload(downloadHandle, url, true); + AskToDownload(downloadHandle, url, true).ContinueWith(task => + { + _updateFunc(false, url); + }); } else { @@ -141,7 +142,10 @@ namespace v2rayN.Handler _updateFunc(false, args.Msg); url = args.Url; - _ = askToDownload(downloadHandle, url, true); + AskToDownload(downloadHandle, url, true).ContinueWith(task => + { + _updateFunc(false, url); + }); } else { @@ -223,7 +227,7 @@ namespace v2rayN.Handler //more url if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx())) { - if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result)) + if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result!)) { result = Utils.Base64Decode(result); } @@ -247,7 +251,7 @@ namespace v2rayN.Handler } if (!Utils.IsNullOrEmpty(result2)) { - if (Utils.IsBase64String(result2)) + if (Utils.IsBase64String(result2!)) { result += Utils.Base64Decode(result2); } @@ -274,8 +278,8 @@ namespace v2rayN.Handler int ret = ConfigHandler.AddBatchServers(config, result, id, true); if (ret <= 0) { - Utils.SaveLog("FailedImportSubscription"); - Utils.SaveLog(result); + Logging.SaveLog("FailedImportSubscription"); + Logging.SaveLog(result); } _updateFunc(false, ret > 0 @@ -327,13 +331,13 @@ namespace v2rayN.Handler } else { - Utils.SaveLog("StatusCode error: " + url); + Logging.SaveLog("StatusCode error: " + url); return; } } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); _updateFunc(false, ex.Message); } } @@ -350,7 +354,7 @@ namespace v2rayN.Handler foreach (string name in coreInfo.coreExes) { string vName = $"{name}.exe"; - vName = Utils.GetBinPath(vName, coreInfo.coreType); + vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString()); if (File.Exists(vName)) { filePath = vName; @@ -366,7 +370,7 @@ namespace v2rayN.Handler } using Process p = new(); - p.StartInfo.FileName = filePath; + p.StartInfo.FileName = filePath.AppendQuotes(); p.StartInfo.Arguments = coreInfo.versionArg; p.StartInfo.WorkingDirectory = Utils.StartupPath(); p.StartInfo.UseShellExecute = false; @@ -399,7 +403,7 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); _updateFunc(false, ex.Message); return new SemanticVersion(""); } @@ -409,7 +413,7 @@ namespace v2rayN.Handler { try { - var gitHubReleases = Utils.FromJson>(gitHubReleaseApi); + var gitHubReleases = JsonUtils.Deserialize>(gitHubReleaseApi); var gitHubRelease = preRelease ? gitHubReleases!.First() : gitHubReleases!.First(r => r.Prerelease == false); var version = new SemanticVersion(gitHubRelease!.TagName); var body = gitHubRelease!.Body; @@ -524,12 +528,12 @@ namespace v2rayN.Handler } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); _updateFunc(false, ex.Message); } } - private async Task askToDownload(DownloadHandle downloadHandle, string url, bool blAsk) + private async Task AskToDownload(DownloadHandle downloadHandle, string url, bool blAsk) { bool blDownload = false; if (blAsk) @@ -593,7 +597,7 @@ namespace v2rayN.Handler { _updateFunc(false, args.GetException().Message); }; - await askToDownload(downloadHandle, url, false); + await AskToDownload(downloadHandle, url, false); } private async Task UpdateGeoFile4Singbox(string geoName, Config config, bool needStop, Action update) @@ -641,7 +645,7 @@ namespace v2rayN.Handler { _updateFunc(false, args.GetException().Message); }; - await askToDownload(downloadHandle, url, false); + await AskToDownload(downloadHandle, url, false); } #endregion private diff --git a/v2rayN/v2rayN/Mode/ConfigItems.cs b/v2rayN/v2rayN/Mode/ConfigItems.cs index ef83051b..dbe062ca 100644 --- a/v2rayN/v2rayN/Mode/ConfigItems.cs +++ b/v2rayN/v2rayN/Mode/ConfigItems.cs @@ -109,6 +109,7 @@ namespace v2rayN.Mode public class UIItem { public bool enableAutoAdjustMainLvColWidth { get; set; } + public bool enableUpdateSubOnlyRemarksExist { get; set; } public double mainWidth { get; set; } public double mainHeight { get; set; } public double mainGirdHeight1 { get; set; } @@ -123,7 +124,6 @@ namespace v2rayN.Mode public bool doubleClick2Activate { get; set; } public bool autoHideStartup { get; set; } = true; public string mainMsgFilter { get; set; } - public bool showTrayTip { get; set; } public List mainColumnItem { get; set; } } @@ -164,6 +164,7 @@ namespace v2rayN.Mode public string stack { get; set; } public int mtu { get; set; } public bool enableExInbound { get; set; } + public bool enableIPv6Address { get; set; } = true; } [Serializable] diff --git a/v2rayN/v2rayN/Mode/EConfigType.cs b/v2rayN/v2rayN/Mode/EConfigType.cs index 090250ab..aff401aa 100644 --- a/v2rayN/v2rayN/Mode/EConfigType.cs +++ b/v2rayN/v2rayN/Mode/EConfigType.cs @@ -9,6 +9,7 @@ VLESS = 5, Trojan = 6, Hysteria2 = 7, - Tuic = 8 + Tuic = 8, + Wireguard = 9 } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Mode/EServerColName.cs b/v2rayN/v2rayN/Mode/EServerColName.cs index be49c2cb..0323df30 100644 --- a/v2rayN/v2rayN/Mode/EServerColName.cs +++ b/v2rayN/v2rayN/Mode/EServerColName.cs @@ -7,7 +7,6 @@ remarks, address, port, - security, network, streamSecurity, subRemarks, diff --git a/v2rayN/v2rayN/Mode/ESpeedActionType.cs b/v2rayN/v2rayN/Mode/ESpeedActionType.cs index 4864061b..c8068f78 100644 --- a/v2rayN/v2rayN/Mode/ESpeedActionType.cs +++ b/v2rayN/v2rayN/Mode/ESpeedActionType.cs @@ -2,7 +2,6 @@ { public enum ESpeedActionType { - Ping, Tcping, Realping, Speedtest, diff --git a/v2rayN/v2rayN/Mode/GitHubRelease.cs b/v2rayN/v2rayN/Mode/GitHubRelease.cs index e509b10f..ddcb2582 100644 --- a/v2rayN/v2rayN/Mode/GitHubRelease.cs +++ b/v2rayN/v2rayN/Mode/GitHubRelease.cs @@ -1,68 +1,68 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace v2rayN.Mode { public class GitHubReleaseAsset { - [JsonProperty("url")] public string Url { get; set; } + [JsonPropertyName("url")] public string Url { get; set; } - [JsonProperty("id")] public int Id { get; set; } + [JsonPropertyName("id")] public int Id { get; set; } - [JsonProperty("node_id")] public string NodeId { get; set; } + [JsonPropertyName("node_id")] public string NodeId { get; set; } - [JsonProperty("name")] public string Name { get; set; } + [JsonPropertyName("name")] public string Name { get; set; } - [JsonProperty("label")] public object Label { get; set; } + [JsonPropertyName("label")] public object Label { get; set; } - [JsonProperty("content_type")] public string ContentType { get; set; } + [JsonPropertyName("content_type")] public string ContentType { get; set; } - [JsonProperty("state")] public string State { get; set; } + [JsonPropertyName("state")] public string State { get; set; } - [JsonProperty("size")] public int Size { get; set; } + [JsonPropertyName("size")] public int Size { get; set; } - [JsonProperty("download_count")] public int DownloadCount { get; set; } + [JsonPropertyName("download_count")] public int DownloadCount { get; set; } - [JsonProperty("created_at")] public DateTime CreatedAt { get; set; } + [JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; } - [JsonProperty("updated_at")] public DateTime UpdatedAt { get; set; } + [JsonPropertyName("updated_at")] public DateTime UpdatedAt { get; set; } - [JsonProperty("browser_download_url")] public string BrowserDownloadUrl { get; set; } + [JsonPropertyName("browser_download_url")] public string BrowserDownloadUrl { get; set; } } public class GitHubRelease { - [JsonProperty("url")] public string Url { get; set; } + [JsonPropertyName("url")] public string Url { get; set; } - [JsonProperty("assets_url")] public string AssetsUrl { get; set; } + [JsonPropertyName("assets_url")] public string AssetsUrl { get; set; } - [JsonProperty("upload_url")] public string UploadUrl { get; set; } + [JsonPropertyName("upload_url")] public string UploadUrl { get; set; } - [JsonProperty("html_url")] public string HtmlUrl { get; set; } + [JsonPropertyName("html_url")] public string HtmlUrl { get; set; } - [JsonProperty("id")] public int Id { get; set; } + [JsonPropertyName("id")] public int Id { get; set; } - [JsonProperty("node_id")] public string NodeId { get; set; } + [JsonPropertyName("node_id")] public string NodeId { get; set; } - [JsonProperty("tag_name")] public string TagName { get; set; } + [JsonPropertyName("tag_name")] public string TagName { get; set; } - [JsonProperty("target_commitish")] public string TargetCommitish { get; set; } + [JsonPropertyName("target_commitish")] public string TargetCommitish { get; set; } - [JsonProperty("name")] public string Name { get; set; } + [JsonPropertyName("name")] public string Name { get; set; } - [JsonProperty("draft")] public bool Draft { get; set; } + [JsonPropertyName("draft")] public bool Draft { get; set; } - [JsonProperty("prerelease")] public bool Prerelease { get; set; } + [JsonPropertyName("prerelease")] public bool Prerelease { get; set; } - [JsonProperty("created_at")] public DateTime CreatedAt { get; set; } + [JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; } - [JsonProperty("published_at")] public DateTime PublishedAt { get; set; } + [JsonPropertyName("published_at")] public DateTime PublishedAt { get; set; } - [JsonProperty("assets")] public List Assets { get; set; } + [JsonPropertyName("assets")] public List Assets { get; set; } - [JsonProperty("tarball_url")] public string TarballUrl { get; set; } + [JsonPropertyName("tarball_url")] public string TarballUrl { get; set; } - [JsonProperty("zipball_url")] public string ZipballUrl { get; set; } + [JsonPropertyName("zipball_url")] public string ZipballUrl { get; set; } - [JsonProperty("body")] public string Body { get; set; } + [JsonPropertyName("body")] public string Body { get; set; } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Mode/ProfileItem.cs b/v2rayN/v2rayN/Mode/ProfileItem.cs index 3e1a4e8e..797587e5 100644 --- a/v2rayN/v2rayN/Mode/ProfileItem.cs +++ b/v2rayN/v2rayN/Mode/ProfileItem.cs @@ -1,5 +1,4 @@ using SQLite; -using v2rayN.Base; namespace v2rayN.Mode { @@ -48,18 +47,12 @@ namespace v2rayN.Mode } switch (configType) { - case EConfigType.VMess: - case EConfigType.Shadowsocks: - case EConfigType.Socks: - case EConfigType.VLESS: - case EConfigType.Trojan: - case EConfigType.Hysteria2: - case EConfigType.Tuic: - summary += string.Format("{0}({1}:{2})", remarks, addr, port); + case EConfigType.Custom: + summary += string.Format("{0}", remarks); break; default: - summary += string.Format("{0}", remarks); + summary += string.Format("{0}({1}:{2})", remarks, addr, port); break; } return summary; diff --git a/v2rayN/v2rayN/Mode/SingboxConfig.cs b/v2rayN/v2rayN/Mode/SingboxConfig.cs index 99a914a1..ecde1b68 100644 --- a/v2rayN/v2rayN/Mode/SingboxConfig.cs +++ b/v2rayN/v2rayN/Mode/SingboxConfig.cs @@ -72,7 +72,7 @@ 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 string? inet6_address { get; set; } public int? mtu { get; set; } public bool? auto_route { get; set; } public bool? strict_route { get; set; } @@ -105,17 +105,23 @@ public int? recv_window_conn { get; set; } public int? recv_window { get; set; } public bool? disable_mtu_discovery { get; set; } - public string detour { get; set; } + public string? detour { get; set; } public string method { get; set; } public string username { get; set; } public string password { get; set; } public string congestion_control { get; set; } public string? version { get; set; } public string? network { get; set; } - public string packet_encoding { get; set; } + public string? packet_encoding { get; set; } + public string[]? local_address { get; set; } + public string? private_key { get; set; } + public string? peer_public_key { get; set; } + public int[]? reserved { get; set; } + public int? mtu { get; set; } public Tls4Sbox tls { get; set; } public Multiplex4Sbox multiplex { get; set; } public Transport4Sbox transport { get; set; } + public HyObfs4Sbox obfs { get; set; } } public class Tls4Sbox @@ -169,6 +175,12 @@ public string? Host { get; set; } } + public class HyObfs4Sbox + { + public string? type { get; set; } + public string? password { get; set; } + } + public class Server4Sbox { public string tag { get; set; } @@ -180,8 +192,9 @@ public class Experimental4Sbox { - public V2ray_Api4Sbox v2ray_api { get; set; } - public Clash_Api4Sbox clash_api { get; set; } + public CacheFile4Sbox? cache_file { get; set; } + public V2ray_Api4Sbox? v2ray_api { get; set; } + public Clash_Api4Sbox? clash_api { get; set; } } public class V2ray_Api4Sbox @@ -192,8 +205,8 @@ public class Clash_Api4Sbox { - public string external_controller { get; set; } - public bool store_selected { get; set; } + public string? external_controller { get; set; } + public bool? store_selected { get; set; } } public class Stats4Sbox @@ -210,4 +223,12 @@ public string inet4_range { get; set; } public string inet6_range { get; set; } } + + public class CacheFile4Sbox + { + public bool enabled { get; set; } + public string? path { get; set; } + public string? cache_id { get; set; } + public bool? store_fakeip { get; set; } + } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Mode/SubItem.cs b/v2rayN/v2rayN/Mode/SubItem.cs index 3221e914..c3fe2c21 100644 --- a/v2rayN/v2rayN/Mode/SubItem.cs +++ b/v2rayN/v2rayN/Mode/SubItem.cs @@ -27,5 +27,9 @@ namespace v2rayN.Mode public long updateTime { get; set; } public string? convertTarget { get; set; } + + public string? prevProfile { get; set; } + + public string? nextProfile { get; set; } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Mode/V2rayConfig.cs b/v2rayN/v2rayN/Mode/V2rayConfig.cs index d19040ad..9f1d7050 100644 --- a/v2rayN/v2rayN/Mode/V2rayConfig.cs +++ b/v2rayN/v2rayN/Mode/V2rayConfig.cs @@ -1,10 +1,9 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace v2rayN.Mode { /// - /// v2ray配置文件实体类 - /// 例子SampleConfig.txt + /// v2ray配置文件实体类 例子SampleConfig.txt /// public class V2rayConfig { @@ -32,7 +31,7 @@ namespace v2rayN.Mode public API4Ray api { get; set; } /// - public Policy4Ray policy; + public Policy4Ray policy { get; set; } /// /// DNS 配置 @@ -56,13 +55,13 @@ namespace v2rayN.Mode public class Policy4Ray { - public SystemPolicy4Ray system; + public SystemPolicy4Ray system { get; set; } } public class SystemPolicy4Ray { - public bool statsOutboundUplink; - public bool statsOutboundDownlink; + public bool statsOutboundUplink { get; set; } + public bool statsOutboundDownlink { get; set; } } public class Log4Ray @@ -580,7 +579,7 @@ namespace v2rayN.Mode /// /// 用户代理 /// - [JsonProperty("User-Agent")] + [JsonPropertyName("User-Agent")] public string UserAgent { get; set; } } diff --git a/v2rayN/v2rayN/Mode/VmessQRCode.cs b/v2rayN/v2rayN/Mode/VmessQRCode.cs index fec376d9..89697b59 100644 --- a/v2rayN/v2rayN/Mode/VmessQRCode.cs +++ b/v2rayN/v2rayN/Mode/VmessQRCode.cs @@ -1,4 +1,6 @@ -namespace v2rayN.Mode +using System.Text.Json.Serialization; + +namespace v2rayN.Mode { /// /// https://github.com/2dust/v2rayN/wiki/ @@ -6,79 +8,37 @@ [Serializable] internal class VmessQRCode { - /// - /// - /// - public string v { get; set; } = string.Empty; + [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] + public int v { get; set; } = 2; - /// - /// - /// public string ps { get; set; } = string.Empty; - /// - /// - /// public string add { get; set; } = string.Empty; - /// - /// - /// - public string port { get; set; } = string.Empty; + [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] + public int port { get; set; } = 0; - /// - /// - /// public string id { get; set; } = string.Empty; - /// - /// - /// - public string aid { get; set; } = string.Empty; + [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] + public int aid { get; set; } = 0; - /// - /// - /// public string scy { get; set; } = string.Empty; - /// - /// - /// public string net { get; set; } = string.Empty; - /// - /// - /// public string type { get; set; } = string.Empty; - /// - /// - /// public string host { get; set; } = string.Empty; - /// - /// - /// public string path { get; set; } = string.Empty; - /// - /// TLS - /// public string tls { get; set; } = string.Empty; - /// - /// TLS SNI - /// public string sni { get; set; } = string.Empty; - /// - /// TLS alpn - /// public string alpn { get; set; } = string.Empty; - /// - /// TLS fingerprint - /// public string fp { get; set; } = string.Empty; } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.Designer.cs b/v2rayN/v2rayN/Resx/ResUI.Designer.cs index ef2bb980..0ef7edd9 100644 --- a/v2rayN/v2rayN/Resx/ResUI.Designer.cs +++ b/v2rayN/v2rayN/Resx/ResUI.Designer.cs @@ -447,6 +447,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Next proxy remarks 的本地化字符串。 + /// + public static string LvNextProfile { + get { + return ResourceManager.GetString("LvNextProfile", resourceCulture); + } + } + /// /// 查找类似 Port 的本地化字符串。 /// @@ -456,6 +465,24 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Previous proxy remakrs 的本地化字符串。 + /// + public static string LvPrevProfile { + get { + return ResourceManager.GetString("LvPrevProfile", resourceCulture); + } + } + + /// + /// 查找类似 Please make sure the remarks exists and is unique 的本地化字符串。 + /// + public static string LvPrevProfileTip { + get { + return ResourceManager.GetString("LvPrevProfileTip", resourceCulture); + } + } + /// /// 查找类似 Remarks 的本地化字符串。 /// @@ -592,7 +619,7 @@ namespace v2rayN.Resx { } /// - /// 查找类似 Add [Trojan] server 的本地化字符串。 + /// 查找类似 Add [Hysteria2] server 的本地化字符串。 /// public static string menuAddHysteria2Server { get { @@ -672,6 +699,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Add [Wireguard] server 的本地化字符串。 + /// + public static string menuAddWireguardServer { + get { + return ResourceManager.GetString("menuAddWireguardServer", resourceCulture); + } + } + /// /// 查找类似 Check Update 的本地化字符串。 /// @@ -933,15 +969,6 @@ namespace v2rayN.Resx { } } - /// - /// 查找类似 Test servers ping (Ctrl+P) 的本地化字符串。 - /// - public static string menuPingServer { - get { - return ResourceManager.GetString("menuPingServer", resourceCulture); - } - } - /// /// 查找类似 Promotion 的本地化字符串。 /// @@ -1717,7 +1744,7 @@ namespace v2rayN.Resx { } /// - /// 查找类似 {0}:{1}/s↑ | {2}/s↓ 的本地化字符串。 + /// 查找类似 {0} : {1}/s↑ | {2}/s↓ 的本地化字符串。 /// public static string SpeedDisplayText { get { @@ -1870,6 +1897,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Auto ScrollToEnd 的本地化字符串。 + /// + public static string TbAutoScrollToEnd { + get { + return ResourceManager.GetString("TbAutoScrollToEnd", resourceCulture); + } + } + /// /// 查找类似 Domain, ip, process are auto sorted when saving 的本地化字符串。 /// @@ -2113,6 +2149,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Address(Ip,Ipv6) 的本地化字符串。 + /// + public static string TbLocalAddress { + get { + return ResourceManager.GetString("TbLocalAddress", resourceCulture); + } + } + /// /// 查找类似 Transport protocol(network) 的本地化字符串。 /// @@ -2140,6 +2185,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 obfs password 的本地化字符串。 + /// + public static string TbPath7 { + get { + return ResourceManager.GetString("TbPath7", resourceCulture); + } + } + /// /// 查找类似 Port 的本地化字符串。 /// @@ -2158,6 +2212,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 PrivateKey 的本地化字符串。 + /// + public static string TbPrivateKey { + get { + return ResourceManager.GetString("TbPrivateKey", resourceCulture); + } + } + /// /// 查找类似 PublicKey 的本地化字符串。 /// @@ -2185,6 +2248,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Reserved(2,3,4) 的本地化字符串。 + /// + public static string TbReserved { + get { + return ResourceManager.GetString("TbReserved", resourceCulture); + } + } + /// /// 查找类似 Reset 的本地化字符串。 /// @@ -2266,6 +2338,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 (Domain or IP or ProcName) and Port and Protocol and InboundTag => OutboundTag 的本地化字符串。 + /// + public static string TbRuleMatchingTips { + get { + return ResourceManager.GetString("TbRuleMatchingTips", resourceCulture); + } + } + /// /// 查找类似 Ruleobject Doc 的本地化字符串。 /// @@ -2527,6 +2608,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Enable additional Inbound 的本地化字符串。 + /// + public static string TbSettingsEnableExInbound { + get { + return ResourceManager.GetString("TbSettingsEnableExInbound", resourceCulture); + } + } + /// /// 查找类似 Enable hardware acceleration(Require restart) 的本地化字符串。 /// @@ -2536,6 +2626,24 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Enable IPv6 Address 的本地化字符串。 + /// + public static string TbSettingsEnableIPv6Address { + get { + return ResourceManager.GetString("TbSettingsEnableIPv6Address", resourceCulture); + } + } + + /// + /// 查找类似 Updating subscription, only determine remarks exists 的本地化字符串。 + /// + public static string TbSettingsEnableUpdateSubOnlyRemarksExist { + get { + return ResourceManager.GetString("TbSettingsEnableUpdateSubOnlyRemarksExist", resourceCulture); + } + } + /// /// 查找类似 Exception 的本地化字符串。 /// @@ -2743,6 +2851,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Speed Ping Test Url 的本地化字符串。 + /// + public static string TbSettingsSpeedPingTestUrl { + get { + return ResourceManager.GetString("TbSettingsSpeedPingTestUrl", resourceCulture); + } + } + /// /// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。 /// diff --git a/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx b/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx index e0d7993c..4f4202d8 100644 --- a/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx @@ -529,9 +529,6 @@ تمام آمار خدمات را پاک کنید - - تست پینگ سرورها (Ctrl+P) - آزمایش سرورها با تاخیر واقعی (Ctrl+R) diff --git a/v2rayN/v2rayN/Resx/ResUI.resx b/v2rayN/v2rayN/Resx/ResUI.resx index b99e2368..cfad9b06 100644 --- a/v2rayN/v2rayN/Resx/ResUI.resx +++ b/v2rayN/v2rayN/Resx/ResUI.resx @@ -532,9 +532,6 @@ Clear all service statistics - - Test servers ping (Ctrl+P) - Test servers real delay (Ctrl+R) @@ -1097,7 +1094,7 @@ More urls, separated by commas;Subscription conversion will be invalid - {0}:{1}/s↑ | {2}/s↓ + {0} : {1}/s↑ | {2}/s↓ Automatic update interval(minutes) @@ -1139,7 +1136,7 @@ Domain - Add [Trojan] server + Add [Hysteria2] server Hysteria Max bandwidth (Up/Dw) @@ -1153,4 +1150,46 @@ Congestion control + + Previous proxy remakrs + + + Next proxy remarks + + + Please make sure the remarks exists and is unique + + + Enable additional Inbound + + + Enable IPv6 Address + + + Add [Wireguard] server + + + PrivateKey + + + Reserved(2,3,4) + + + Address(Ip,Ipv6) + + + obfs password + + + (Domain or IP or ProcName) and Port and Protocol and InboundTag => OutboundTag + + + Auto ScrollToEnd + + + Speed Ping Test Url + + + Updating subscription, only determine remarks exists + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.ru.resx b/v2rayN/v2rayN/Resx/ResUI.ru.resx index c1b3c928..1dcfded4 100644 --- a/v2rayN/v2rayN/Resx/ResUI.ru.resx +++ b/v2rayN/v2rayN/Resx/ResUI.ru.resx @@ -532,9 +532,6 @@ Очистить всю статистику - - Тест на задержку сервера (Ctrl+P) - Тест на реальную задержку сервера (Ctrl+R) @@ -1072,4 +1069,4 @@ URL спидтеста - + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx index 0432350d..f1a1fb7f 100644 --- a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx @@ -532,9 +532,6 @@ 清除所有服务统计数据 - - 测试服务器延迟Ping(多选) (Ctrl+P) - 测试服务器真连接延迟(多选) (Ctrl+R) @@ -1150,4 +1147,46 @@ 拥塞控制算法 + + 前置代理别名 + + + 落地代理別名 + + + 请确保别名存在并唯一 + + + 启用额外监听端口 + + + 启用IPv6 + + + 添加[Wireguard]服务器 + + + PrivateKey + + + Reserved(2,3,4) + + + Address(Ip,Ipv6) + + + 混淆密码(obfs password) + + + (Domain 或 IP 或 进程名) 与 Port 与 Protocol 与 InboundTag => OutboundTag + + + 自动滚动到末尾 + + + 真连接测试地址 + + + 更新订阅时只判断别名已存在否 + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.zh-Hant.resx b/v2rayN/v2rayN/Resx/ResUI.zh-Hant.resx index 06120c4f..95c6adbc 100644 --- a/v2rayN/v2rayN/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/v2rayN/Resx/ResUI.zh-Hant.resx @@ -531,9 +531,6 @@ 清除所有服務統計資料 - - 測試伺服器延遲Ping(多選) (Ctrl+P) - 測試伺服器真連接延遲(多選) (Ctrl+R) @@ -929,7 +926,7 @@ 新增規則 - 到處所選規則至剪貼簿 + 匯出所選規則至剪貼簿 規則列表 @@ -1138,4 +1135,31 @@ 新增[Tuic]伺服器 + + 前置代理別名 + + + 落地代理別名 + + + 請確保別名存在並且唯一 + + + 啟用額外監聽端口 + + + 啟用IPv6 + + + (Domain 或 IP 或 进程名) 与 Port 与 Protocol 与 InboundTag => OutboundTag + + + 自动滚动到末尾 + + + 真連接測試地址 + + + 更新订阅时只判断别名已存在否 + \ No newline at end of file diff --git a/v2rayN/v2rayN/Sample/SingboxSampleClientConfig b/v2rayN/v2rayN/Sample/SingboxSampleClientConfig index ce3d9305..8e34738f 100644 --- a/v2rayN/v2rayN/Sample/SingboxSampleClientConfig +++ b/v2rayN/v2rayN/Sample/SingboxSampleClientConfig @@ -25,9 +25,18 @@ { "type": "block", "tag": "block" + }, + { + "tag": "dns_out", + "type": "dns" } ], "route": { - "rules": [] + "rules": [ + { + "protocol": [ "dns" ], + "outbound": "dns_out" + } + ] } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Sample/SingboxSampleOutbound b/v2rayN/v2rayN/Sample/SingboxSampleOutbound new file mode 100644 index 00000000..9c87194f --- /dev/null +++ b/v2rayN/v2rayN/Sample/SingboxSampleOutbound @@ -0,0 +1,6 @@ +{ + "type": "vless", + "tag": "proxy", + "server": "", + "server_port": 443 +} \ No newline at end of file diff --git a/v2rayN/v2rayN/Sample/custom_routing_white b/v2rayN/v2rayN/Sample/custom_routing_white index 7a139e31..a708ae0d 100644 --- a/v2rayN/v2rayN/Sample/custom_routing_white +++ b/v2rayN/v2rayN/Sample/custom_routing_white @@ -24,5 +24,9 @@ "geoip:private", "geoip:cn" ] + }, + { + "port": "0-65535", + "outboundTag": "proxy" } ] \ No newline at end of file diff --git a/v2rayN/v2rayN/Sample/tun_singbox_rules b/v2rayN/v2rayN/Sample/tun_singbox_rules index 93762e27..df1dc4ec 100644 --- a/v2rayN/v2rayN/Sample/tun_singbox_rules +++ b/v2rayN/v2rayN/Sample/tun_singbox_rules @@ -1,12 +1,4 @@ [ - { - "inbound": [ "dns_in" ], - "outbound": "dns_out" - }, - { - "protocol": [ "dns" ], - "outbound": "dns_out" - }, { "network": "udp", "port": [ @@ -24,12 +16,5 @@ "ff00::/8" ], "outbound": "block" - }, - { - "source_ip_cidr": [ - "224.0.0.0/3", - "ff00::/8" - ], - "outbound": "block" } ] \ No newline at end of file diff --git a/v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs b/v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs index 137db406..ffe448d9 100644 --- a/v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs @@ -1,4 +1,3 @@ -using Microsoft.Win32; using ReactiveUI; using ReactiveUI.Fody.Helpers; using ReactiveUI.Validation.Helpers; @@ -6,7 +5,6 @@ using Splat; using System.IO; using System.Reactive; using System.Windows; -using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; @@ -38,7 +36,7 @@ namespace v2rayN.ViewModels } else { - SelectedSource = Utils.DeepCopy(profileItem); + SelectedSource = JsonUtils.DeepCopy(profileItem); } _view = view; @@ -103,22 +101,18 @@ namespace v2rayN.ViewModels private void BrowseServer() { - UI.Show(ResUI.CustomServerTips); + //UI.Show(ResUI.CustomServerTips); - OpenFileDialog fileDialog = new() - { - Multiselect = false, - Filter = "Config|*.json|YAML|*.yaml;*.yml|All|*.*" - }; - if (fileDialog.ShowDialog() != true) + if (UI.OpenFileDialog(out string fileName, + "Config|*.json|YAML|*.yaml;*.yml|All|*.*") != true) { return; } - string fileName = fileDialog.FileName; if (Utils.IsNullOrEmpty(fileName)) { return; } + var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId); item ??= SelectedSource; item.address = fileName; @@ -127,7 +121,7 @@ namespace v2rayN.ViewModels _noticeHandler?.Enqueue(ResUI.SuccessfullyImportedCustomServer); if (!Utils.IsNullOrEmpty(item.indexId)) { - SelectedSource = Utils.DeepCopy(item); + SelectedSource = JsonUtils.DeepCopy(item); } IsModified = true; } diff --git a/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs b/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs index a36b0733..a81a2dc0 100644 --- a/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs @@ -3,7 +3,6 @@ using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; -using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; @@ -37,7 +36,7 @@ namespace v2rayN.ViewModels } else { - SelectedSource = Utils.DeepCopy(profileItem); + SelectedSource = JsonUtils.DeepCopy(profileItem); } SaveCmd = ReactiveCommand.Create(() => @@ -123,37 +122,18 @@ namespace v2rayN.ViewModels item.spiderX = SelectedSource.spiderX; } - int ret = -1; - switch (item.configType) + var ret = item.configType switch { - case EConfigType.VMess: - ret = ConfigHandler.AddServer(_config, item); - break; - - case EConfigType.Shadowsocks: - ret = ConfigHandler.AddShadowsocksServer(_config, item); - break; - - case EConfigType.Socks: - ret = ConfigHandler.AddSocksServer(_config, item); - break; - - case EConfigType.VLESS: - ret = ConfigHandler.AddVlessServer(_config, item); - break; - - case EConfigType.Trojan: - ret = ConfigHandler.AddTrojanServer(_config, item); - break; - - case EConfigType.Hysteria2: - ret = ConfigHandler.AddHysteria2Server(_config, item); - break; - - case EConfigType.Tuic: - ret = ConfigHandler.AddTuicServer(_config, item); - break; - } + EConfigType.VMess => ConfigHandler.AddServer(_config, item), + EConfigType.Shadowsocks => ConfigHandler.AddShadowsocksServer(_config, item), + EConfigType.Socks => ConfigHandler.AddSocksServer(_config, item), + EConfigType.Trojan => ConfigHandler.AddTrojanServer(_config, item), + EConfigType.VLESS => ConfigHandler.AddVlessServer(_config, item), + EConfigType.Hysteria2 => ConfigHandler.AddHysteria2Server(_config, item), + EConfigType.Tuic => ConfigHandler.AddTuicServer(_config, item), + EConfigType.Wireguard => ConfigHandler.AddWireguardServer(_config, item), + _ => -1, + }; if (ret == 0) { diff --git a/v2rayN/v2rayN/ViewModels/DNSSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/DNSSettingViewModel.cs index 56c5ee45..8eb7df1b 100644 --- a/v2rayN/v2rayN/ViewModels/DNSSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/DNSSettingViewModel.cs @@ -63,8 +63,8 @@ namespace v2rayN.ViewModels { if (!Utils.IsNullOrEmpty(normalDNS)) { - var obj = Utils.ParseJson(normalDNS); - if (obj != null && obj.ContainsKey("servers") == true) + var obj = JsonUtils.ParseJson(normalDNS); + if (obj != null && obj["servers"] != null) { } else @@ -78,7 +78,7 @@ namespace v2rayN.ViewModels } if (!Utils.IsNullOrEmpty(normalDNS2)) { - var obj2 = Utils.FromJson(normalDNS2); + var obj2 = JsonUtils.Deserialize(normalDNS2); if (obj2 == null) { UI.Show(ResUI.FillCorrectDNSText); @@ -87,7 +87,7 @@ namespace v2rayN.ViewModels } if (!Utils.IsNullOrEmpty(tunDNS2)) { - var obj2 = Utils.FromJson(tunDNS2); + var obj2 = JsonUtils.Deserialize(tunDNS2); if (obj2 == null) { UI.Show(ResUI.FillCorrectDNSText); @@ -102,8 +102,8 @@ namespace v2rayN.ViewModels ConfigHandler.SaveDNSItems(_config, item); var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box); - item2.normalDNS = Utils.ToJson(Utils.ParseJson(normalDNS2)); - item2.tunDNS = Utils.ToJson(Utils.ParseJson(tunDNS2)); + item2.normalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(normalDNS2)); + item2.tunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2)); ConfigHandler.SaveDNSItems(_config, item2); _noticeHandler?.Enqueue(ResUI.OperationSuccess); diff --git a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs index 0902d880..2168b316 100644 --- a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs @@ -3,7 +3,6 @@ using DynamicData.Binding; using MaterialDesignColors; using MaterialDesignColors.ColorManipulation; using MaterialDesignThemes.Wpf; -using Microsoft.Win32; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; @@ -15,11 +14,9 @@ using System.Reactive.Linq; using System.Text; using System.Windows; using System.Windows.Media; -using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; -using v2rayN.Tool; using v2rayN.Views; namespace v2rayN.ViewModels @@ -38,6 +35,7 @@ namespace v2rayN.ViewModels private readonly PaletteHelper _paletteHelper = new(); private Dictionary _dicHeaderSort = new(); private Action _updateView; + private bool _showInTaskbar; #endregion private prop @@ -91,6 +89,7 @@ namespace v2rayN.ViewModels public ReactiveCommand AddTrojanServerCmd { get; } public ReactiveCommand AddHysteria2ServerCmd { get; } public ReactiveCommand AddTuicServerCmd { get; } + public ReactiveCommand AddWireguardServerCmd { get; } public ReactiveCommand AddCustomServerCmd { get; } public ReactiveCommand AddServerViaClipboardCmd { get; } public ReactiveCommand AddServerViaScanCmd { get; } @@ -114,7 +113,6 @@ namespace v2rayN.ViewModels //servers ping public ReactiveCommand MixedTestServerCmd { get; } - public ReactiveCommand PingServerCmd { get; } public ReactiveCommand TcpingServerCmd { get; } public ReactiveCommand RealPingServerCmd { get; } public ReactiveCommand SpeedServerCmd { get; } @@ -130,6 +128,7 @@ namespace v2rayN.ViewModels public ReactiveCommand SubSettingCmd { get; } public ReactiveCommand AddSubCmd { get; } + public ReactiveCommand EditSubCmd { get; } public ReactiveCommand SubUpdateCmd { get; } public ReactiveCommand SubUpdateViaProxyCmd { get; } public ReactiveCommand SubGroupUpdateCmd { get; } @@ -260,8 +259,6 @@ namespace v2rayN.ViewModels Locator.CurrentMutable.RegisterLazySingleton(() => new NoticeHandler(snackbarMessageQueue), typeof(NoticeHandler)); _noticeHandler = Locator.Current.GetService(); _config = LazyConfig.Instance.GetConfig(); - //ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false); - Init(); SelectedProfile = new(); SelectedSub = new(); @@ -274,9 +271,11 @@ namespace v2rayN.ViewModels } _subId = _config.subIndexId; - InitSubscriptionView(); - RefreshRoutingsMenu(); - RefreshServers(); + Init(); + BindingUI(); + RestoreUI(); + + #region WhenAnyValue && ReactiveCommand var canEditRemove = this.WhenAnyValue( x => x.SelectedProfile, @@ -317,10 +316,6 @@ namespace v2rayN.ViewModels y => y == true) .Subscribe(c => DoEnableTun(c)); - BindingUI(); - RestoreUI(); - AutoHideStartup(); - //servers AddVmessServerCmd = ReactiveCommand.Create(() => { @@ -350,6 +345,10 @@ namespace v2rayN.ViewModels { EditServer(true, EConfigType.Tuic); }); + AddWireguardServerCmd = ReactiveCommand.Create(() => + { + EditServer(true, EConfigType.Wireguard); + }); AddCustomServerCmd = ReactiveCommand.Create(() => { EditServer(true, EConfigType.Custom); @@ -410,10 +409,6 @@ namespace v2rayN.ViewModels { ServerSpeedtest(ESpeedActionType.Mixedtest); }); - PingServerCmd = ReactiveCommand.Create(() => - { - ServerSpeedtest(ESpeedActionType.Ping); - }, canEditRemove); TcpingServerCmd = ReactiveCommand.Create(() => { ServerSpeedtest(ESpeedActionType.Tcping); @@ -451,7 +446,11 @@ namespace v2rayN.ViewModels }); AddSubCmd = ReactiveCommand.Create(() => { - AddSub(); + EditSub(true); + }); + EditSubCmd = ReactiveCommand.Create(() => + { + EditSub(false); }); SubUpdateCmd = ReactiveCommand.Create(() => { @@ -566,7 +565,11 @@ namespace v2rayN.ViewModels SetListenerType(ESysProxyType.Pac); }); - Global.ShowInTaskbar = true; + #endregion WhenAnyValue && ReactiveCommand + + AutoHideStartup(); + + _showInTaskbar = true; } private void Init() @@ -584,6 +587,10 @@ namespace v2rayN.ViewModels MainFormHandler.Instance.UpdateTask(_config, UpdateTaskHandler); MainFormHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, UpdateTaskHandler); + InitSubscriptionView(); + RefreshRoutingsMenu(); + RefreshServers(); + Reload(); ChangeSystemProxyStatus(_config.sysProxyType, true); } @@ -629,7 +636,7 @@ namespace v2rayN.ViewModels { Application.Current.Dispatcher.Invoke((Action)(() => { - if (!Global.ShowInTaskbar) + if (!_showInTaskbar) { return; } @@ -652,13 +659,13 @@ namespace v2rayN.ViewModels if (SelectedProfile?.indexId == item.indexId) { - var temp = Utils.DeepCopy(item); + var temp = JsonUtils.DeepCopy(item); _profileItems.Replace(item, temp); SelectedProfile = temp; } else { - _profileItems.Replace(item, Utils.DeepCopy(item)); + _profileItems.Replace(item, JsonUtils.DeepCopy(item)); } } } @@ -667,7 +674,7 @@ namespace v2rayN.ViewModels } catch (Exception ex) { - Utils.SaveLog(ex.Message, ex); + Logging.SaveLog(ex.Message, ex); } } @@ -700,7 +707,7 @@ namespace v2rayN.ViewModels { item.speedVal = $"{speed} {Global.SpeedUnit}"; } - _profileItems.Replace(item, Utils.DeepCopy(item)); + _profileItems.Replace(item, JsonUtils.DeepCopy(item)); } } @@ -734,7 +741,7 @@ namespace v2rayN.ViewModels { try { - Utils.SaveLog("MyAppExit Begin"); + Logging.SaveLog("MyAppExit Begin"); StorageUI(); ConfigHandler.SaveConfig(_config); @@ -755,7 +762,7 @@ namespace v2rayN.ViewModels _statistics?.Close(); _coreHandler.CoreStop(); - Utils.SaveLog("MyAppExit End"); + Logging.SaveLog("MyAppExit End"); } catch { } finally @@ -835,7 +842,7 @@ namespace v2rayN.ViewModels totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown), totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp) }).OrderBy(t => t.sort).ToList(); - _lstProfile = Utils.FromJson>(Utils.ToJson(lstModel)); + _lstProfile = JsonUtils.Deserialize>(JsonUtils.Serialize(lstModel)); Application.Current.Dispatcher.Invoke((Action)(() => { @@ -860,13 +867,12 @@ namespace v2rayN.ViewModels var running = ConfigHandler.GetDefaultServer(_config); if (running != null) { - var runningSummary = running.GetSummary(); - RunningServerDisplay = $"{ResUI.menuServers}:{runningSummary}"; - RunningServerToolTipText = runningSummary; + RunningServerDisplay = + RunningServerToolTipText = running.GetSummary(); } else { - RunningServerDisplay = ResUI.CheckServerSettings; + RunningServerDisplay = RunningServerToolTipText = ResUI.CheckServerSettings; } })); @@ -941,7 +947,7 @@ namespace v2rayN.ViewModels } else { - lstSelecteds = Utils.FromJson>(Utils.ToJson(orderProfiles)); + lstSelecteds = JsonUtils.Deserialize>(JsonUtils.Serialize(orderProfiles)); } return 0; @@ -1134,7 +1140,7 @@ namespace v2rayN.ViewModels _noticeHandler?.Enqueue(ResUI.PleaseSelectServer); return; } - string url = ShareHandler.GetShareUrl(item); + var url = ShareHandler.GetShareUrl(item); if (Utils.IsNullOrEmpty(url)) { return; @@ -1178,7 +1184,7 @@ namespace v2rayN.ViewModels _noticeHandler?.SendMessage(msg, true); Application.Current.Dispatcher.Invoke((Action)(() => { - if (!Global.ShowInTaskbar) + if (!_showInTaskbar) { return; } @@ -1328,9 +1334,21 @@ namespace v2rayN.ViewModels } } - private void AddSub() + private void EditSub(bool blNew) { - SubItem item = new(); + SubItem item; + if (blNew) + { + item = new(); + } + else + { + item = LazyConfig.Instance.GetSubItem(_subId); + if (item is null) + { + return; + } + } var ret = (new SubEditWindow(item)).ShowDialog(); if (ret == true) { @@ -1386,7 +1404,7 @@ namespace v2rayN.ViewModels UseShellExecute = true, Arguments = Global.RebootAs, WorkingDirectory = Utils.StartupPath(), - FileName = Utils.GetExePath(), + FileName = Utils.GetExePath().AppendQuotes(), Verb = "runas", }; try @@ -1399,16 +1417,11 @@ namespace v2rayN.ViewModels private void ImportOldGuiConfig() { - OpenFileDialog fileDialog = new() - { - Multiselect = false, - Filter = "guiNConfig|*.json|All|*.*" - }; - if (fileDialog.ShowDialog() != true) + if (UI.OpenFileDialog(out string fileName, + "guiNConfig|*.json|All|*.*") != true) { return; } - string fileName = fileDialog.FileName; if (Utils.IsNullOrEmpty(fileName)) { return; @@ -1456,7 +1469,7 @@ namespace v2rayN.ViewModels CloseV2ray(); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(msg)); - string toPath = Utils.GetBinPath("", type); + string toPath = Utils.GetBinPath("", type.ToString()); FileManager.ZipExtractToFile(fileName, toPath, _config.guiItem.ignoreGeoUpdateCore ? "geo" : ""); @@ -1486,16 +1499,21 @@ namespace v2rayN.ViewModels public void Reload() { - _ = LoadV2ray(); + BlReloadEnabled = false; + + LoadV2ray().ContinueWith(task => + { + TestServerAvailability(); + + Application.Current.Dispatcher.Invoke((Action)(() => + { + BlReloadEnabled = true; + })); + }); } private async Task LoadV2ray() { - Application.Current.Dispatcher.Invoke((Action)(() => - { - BlReloadEnabled = false; - })); - await Task.Run(() => { _coreHandler.LoadCore(); @@ -1504,13 +1522,6 @@ namespace v2rayN.ViewModels ChangeSystemProxyStatus(_config.sysProxyType, false); }); - - TestServerAvailability(); - - Application.Current.Dispatcher.Invoke((Action)(() => - { - BlReloadEnabled = true; - })); } private void CloseV2ray() @@ -1608,6 +1619,8 @@ namespace v2rayN.ViewModels { _noticeHandler?.SendMessage(ResUI.TipChangeRouting, true); Reload(); + NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config); + AppIcon = MainFormHandler.Instance.GetAppIcon(_config); } } @@ -1629,6 +1642,13 @@ namespace v2rayN.ViewModels if (_config.tunModeItem.enableTun != EnableTun) { _config.tunModeItem.enableTun = EnableTun; + // When running as a non-administrator, reboot to administrator mode + if (EnableTun && !Utils.IsAdministrator()) + { + _config.tunModeItem.enableTun = false; + RebootAsAdmin(); + return; + } Reload(); } } @@ -1639,7 +1659,7 @@ namespace v2rayN.ViewModels public void ShowHideWindow(bool? blShow) { - var bl = blShow ?? !Global.ShowInTaskbar; + var bl = blShow ?? !_showInTaskbar; if (bl) { //Application.Current.MainWindow.ShowInTaskbar = true; @@ -1658,7 +1678,7 @@ namespace v2rayN.ViewModels //IntPtr windowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle; //Utils.RegWriteValue(Global.MyRegPath, Utils.WindowHwndKey, Convert.ToString((long)windowHandle)); } - Global.ShowInTaskbar = bl; + _showInTaskbar = bl; } private void RestoreUI() @@ -1699,7 +1719,6 @@ namespace v2rayN.ViewModels } CurrentFontSize = _config.uiItem.currentFontSize; CurrentLanguage = _config.uiItem.currentLanguage; - //BlShowTrayTip = _config.uiItem.showTrayTip; this.WhenAnyValue( x => x.ColorModeDark, @@ -1726,6 +1745,10 @@ namespace v2rayN.ViewModels { ModifyTheme(!Utils.IsLightTheme()); } + else + { + ModifyTheme(ColorModeDark); + } } }); @@ -1843,7 +1866,7 @@ namespace v2rayN.ViewModels if (_config.uiItem.autoHideStartup) { Observable.Range(1, 1) - .Delay(TimeSpan.FromSeconds(2)) + .Delay(TimeSpan.FromSeconds(1)) .Subscribe(x => { Application.Current.Dispatcher.Invoke(() => diff --git a/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs index afb33fdb..0fb17877 100644 --- a/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs @@ -56,6 +56,7 @@ namespace v2rayN.ViewModels [Reactive] public bool KeepOlderDedupl { get; set; } [Reactive] public bool IgnoreGeoUpdateCore { get; set; } [Reactive] public bool EnableAutoAdjustMainLvColWidth { get; set; } + [Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; } [Reactive] public bool EnableSecurityProtocolTls13 { get; set; } [Reactive] public bool AutoHideStartup { get; set; } [Reactive] public bool EnableCheckPreReleaseUpdate { get; set; } @@ -66,6 +67,7 @@ namespace v2rayN.ViewModels [Reactive] public string currentFontFamily { get; set; } [Reactive] public int SpeedTestTimeout { get; set; } [Reactive] public string SpeedTestUrl { get; set; } + [Reactive] public string SpeedPingTestUrl { get; set; } [Reactive] public bool EnableHWA { get; set; } [Reactive] public string SubConvertUrl { get; set; } @@ -83,6 +85,8 @@ namespace v2rayN.ViewModels [Reactive] public bool TunStrictRoute { get; set; } [Reactive] public string TunStack { get; set; } [Reactive] public int TunMtu { get; set; } + [Reactive] public bool TunEnableExInbound { get; set; } + [Reactive] public bool TunEnableIPv6Address { get; set; } #endregion Tun mode @@ -147,6 +151,7 @@ namespace v2rayN.ViewModels KeepOlderDedupl = _config.guiItem.keepOlderDedupl; IgnoreGeoUpdateCore = _config.guiItem.ignoreGeoUpdateCore; EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth; + EnableUpdateSubOnlyRemarksExist = _config.uiItem.enableUpdateSubOnlyRemarksExist; EnableSecurityProtocolTls13 = _config.guiItem.enableSecurityProtocolTls13; AutoHideStartup = _config.uiItem.autoHideStartup; EnableCheckPreReleaseUpdate = _config.guiItem.checkPreReleaseUpdate; @@ -157,6 +162,7 @@ namespace v2rayN.ViewModels currentFontFamily = _config.uiItem.currentFontFamily; SpeedTestTimeout = _config.speedTestItem.speedTestTimeout; SpeedTestUrl = _config.speedTestItem.speedTestUrl; + SpeedPingTestUrl = _config.speedTestItem.speedPingTestUrl; EnableHWA = _config.guiItem.enableHWA; SubConvertUrl = _config.constItem.subConvertUrl; @@ -174,6 +180,8 @@ namespace v2rayN.ViewModels TunStrictRoute = _config.tunModeItem.strictRoute; TunStack = _config.tunModeItem.stack; TunMtu = _config.tunModeItem.mtu; + TunEnableExInbound = _config.tunModeItem.enableExInbound; + TunEnableIPv6Address = _config.tunModeItem.enableIPv6Address; #endregion Tun mode @@ -292,12 +300,13 @@ namespace v2rayN.ViewModels //_config.kcpItem.congestion = Kcpcongestion; //UI - Utils.SetAutoRun(AutoRun); + Utils.SetAutoRun(Global.AutoRunRegPath, Global.AutoRunName, AutoRun); _config.guiItem.autoRun = AutoRun; _config.guiItem.enableStatistics = EnableStatistics; _config.guiItem.keepOlderDedupl = KeepOlderDedupl; _config.guiItem.ignoreGeoUpdateCore = IgnoreGeoUpdateCore; _config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth; + _config.uiItem.enableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist; _config.guiItem.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13; _config.uiItem.autoHideStartup = AutoHideStartup; _config.guiItem.autoUpdateInterval = autoUpdateInterval; @@ -308,6 +317,7 @@ namespace v2rayN.ViewModels _config.uiItem.currentFontFamily = currentFontFamily; _config.speedTestItem.speedTestTimeout = SpeedTestTimeout; _config.speedTestItem.speedTestUrl = SpeedTestUrl; + _config.speedTestItem.speedPingTestUrl = SpeedPingTestUrl; _config.guiItem.enableHWA = EnableHWA; _config.constItem.subConvertUrl = SubConvertUrl; @@ -319,6 +329,8 @@ namespace v2rayN.ViewModels _config.tunModeItem.strictRoute = TunStrictRoute; _config.tunModeItem.stack = TunStack; _config.tunModeItem.mtu = TunMtu; + _config.tunModeItem.enableExInbound = TunEnableExInbound; + _config.tunModeItem.enableIPv6Address = TunEnableIPv6Address; //coreType SaveCoreType(); @@ -366,8 +378,7 @@ namespace v2rayN.ViewModels type = CoreType6; break; - case 7: - case 8: + default: continue; } item.coreType = (ECoreType)Enum.Parse(typeof(ECoreType), type); diff --git a/v2rayN/v2rayN/ViewModels/RoutingRuleDetailsViewModel.cs b/v2rayN/v2rayN/ViewModels/RoutingRuleDetailsViewModel.cs index aa6663da..c6c9e5f1 100644 --- a/v2rayN/v2rayN/ViewModels/RoutingRuleDetailsViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/RoutingRuleDetailsViewModel.cs @@ -3,7 +3,6 @@ using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; -using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; diff --git a/v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs index c545ef9c..a35dafb2 100644 --- a/v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs @@ -1,11 +1,9 @@ using DynamicData.Binding; -using Microsoft.Win32; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; -using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; @@ -60,7 +58,7 @@ namespace v2rayN.ViewModels else { SelectedRouting = routingItem; - _rules = Utils.FromJson>(SelectedRouting.ruleSet); + _rules = JsonUtils.Deserialize>(SelectedRouting.ruleSet); } RefreshRulesItems(); @@ -81,9 +79,9 @@ namespace v2rayN.ViewModels { ImportRulesFromClipboard(); }); - ImportRulesFromUrlCmd = ReactiveCommand.Create(() => + ImportRulesFromUrlCmd = ReactiveCommand.CreateFromTask(() => { - ImportRulesFromUrl(); + return ImportRulesFromUrl(); }); RuleRemoveCmd = ReactiveCommand.Create(() => @@ -143,7 +141,7 @@ namespace v2rayN.ViewModels public void RuleEdit(bool blNew) { - RulesItem item; + RulesItem? item; if (blNew) { item = new(); @@ -209,7 +207,7 @@ namespace v2rayN.ViewModels } if (lst.Count > 0) { - Utils.SetClipboardData(Utils.ToJson(lst)); + Utils.SetClipboardData(JsonUtils.Serialize(lst)); //UI.Show(ResUI.OperationSuccess")); } } @@ -248,7 +246,7 @@ namespace v2rayN.ViewModels it.id = Utils.GetGUID(false); } item.ruleNum = _rules.Count; - item.ruleSet = Utils.ToJson(_rules, false); + item.ruleSet = JsonUtils.Serialize(_rules, false); if (ConfigHandler.SaveRoutingItem(_config, item) == 0) { @@ -265,20 +263,16 @@ namespace v2rayN.ViewModels private void ImportRulesFromFile() { - OpenFileDialog fileDialog = new OpenFileDialog - { - Multiselect = false, - Filter = "Rules|*.json|All|*.*" - }; - if (fileDialog.ShowDialog() != true) + if (UI.OpenFileDialog(out string fileName, + "Rules|*.json|All|*.*") != true) { return; } - string fileName = fileDialog.FileName; if (Utils.IsNullOrEmpty(fileName)) { return; } + string result = Utils.LoadResource(fileName); if (Utils.IsNullOrEmpty(result)) { @@ -312,7 +306,7 @@ namespace v2rayN.ViewModels } DownloadHandle downloadHandle = new DownloadHandle(); - string result = await downloadHandle.TryDownloadString(url, true, ""); + var result = await downloadHandle.TryDownloadString(url, true, ""); if (AddBatchRoutingRules(SelectedRouting, result) == 0) { Application.Current.Dispatcher.Invoke((Action)(() => @@ -323,7 +317,7 @@ namespace v2rayN.ViewModels } } - private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData) + private int AddBatchRoutingRules(RoutingItem routingItem, string? clipboardData) { bool blReplace = false; if (UI.ShowYesNo(ResUI.AddBatchRoutingRulesYesNo) == MessageBoxResult.No) @@ -334,7 +328,7 @@ namespace v2rayN.ViewModels { return -1; } - var lstRules = Utils.FromJson>(clipboardData); + var lstRules = JsonUtils.Deserialize>(clipboardData); if (lstRules == null) { return -1; diff --git a/v2rayN/v2rayN/ViewModels/RoutingSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/RoutingSettingViewModel.cs index 7b38712d..dfcfddc4 100644 --- a/v2rayN/v2rayN/ViewModels/RoutingSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/RoutingSettingViewModel.cs @@ -4,7 +4,6 @@ using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; -using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; @@ -137,7 +136,7 @@ namespace v2rayN.ViewModels _lockedItem = ConfigHandler.GetLockedRoutingItem(_config); if (_lockedItem != null) { - _lockedRules = Utils.FromJson>(_lockedItem.ruleSet); + _lockedRules = JsonUtils.Deserialize>(_lockedItem.ruleSet); ProxyDomain = Utils.List2String(_lockedRules[0].domain, true); ProxyIP = Utils.List2String(_lockedRules[0].ip, true); @@ -162,7 +161,7 @@ namespace v2rayN.ViewModels _lockedRules[2].domain = Utils.String2List(Utils.Convert2Comma(BlockDomain.TrimEx())); _lockedRules[2].ip = Utils.String2List(Utils.Convert2Comma(BlockIP.TrimEx())); - _lockedItem.ruleSet = Utils.ToJson(_lockedRules, false); + _lockedItem.ruleSet = JsonUtils.Serialize(_lockedRules, false); ConfigHandler.SaveRoutingItem(_config, _lockedItem); } diff --git a/v2rayN/v2rayN/ViewModels/SubEditViewModel.cs b/v2rayN/v2rayN/ViewModels/SubEditViewModel.cs index dcc30d50..c6ad0a17 100644 --- a/v2rayN/v2rayN/ViewModels/SubEditViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/SubEditViewModel.cs @@ -3,7 +3,6 @@ using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; -using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; @@ -33,7 +32,7 @@ namespace v2rayN.ViewModels } else { - SelectedSource = Utils.DeepCopy(subItem); + SelectedSource = JsonUtils.DeepCopy(subItem); } SaveCmd = ReactiveCommand.Create(() => @@ -69,6 +68,8 @@ namespace v2rayN.ViewModels item.sort = SelectedSource.sort; item.filter = SelectedSource.filter; item.convertTarget = SelectedSource.convertTarget; + item.prevProfile = SelectedSource.prevProfile; + item.nextProfile = SelectedSource.nextProfile; } if (ConfigHandler.AddSubItem(_config, item) == 0) diff --git a/v2rayN/v2rayN/ViewModels/SubSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/SubSettingViewModel.cs index cb9e6aea..0fdf36c2 100644 --- a/v2rayN/v2rayN/ViewModels/SubSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/SubSettingViewModel.cs @@ -6,7 +6,6 @@ using ReactiveUI.Fody.Helpers; using Splat; using System.Reactive; using System.Windows; -using v2rayN.Base; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; @@ -104,7 +103,7 @@ namespace v2rayN.ViewModels foreach (var it in SelectedSources) { - ConfigHandler.DeleteSubItem(_config, it?.id); + ConfigHandler.DeleteSubItem(_config, it.id); } RefreshSubItems(); _noticeHandler?.Enqueue(ResUI.OperationSuccess); diff --git a/v2rayN/v2rayN/Views/AddServer2Window.xaml b/v2rayN/v2rayN/Views/AddServer2Window.xaml index 9ef69639..7c522e11 100644 --- a/v2rayN/v2rayN/Views/AddServer2Window.xaml +++ b/v2rayN/v2rayN/Views/AddServer2Window.xaml @@ -2,10 +2,8 @@ x:Class="v2rayN.Views.AddServer2Window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:Views="clr-namespace:v2rayN.Views" xmlns:conv="clr-namespace:v2rayN.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:local="clr-namespace:v2rayN" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:reactiveui="http://reactiveui.net" @@ -25,183 +23,185 @@ TextOptions.TextRenderingMode="Auto" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - - - - - - - + + + + @@ -566,10 +581,6 @@ x:Name="menuMixedTestServer" Height="{StaticResource MenuItemHeight}" Header="{x:Static resx:ResUI.menuMixedTestServer}" /> - - vm.SelectedSub, v => v.lstGroup.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddSubCmd, v => v.btnAddSub).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.EditSubCmd, v => v.btnEditSub).DisposeWith(disposables); //servers this.BindCommand(ViewModel, vm => vm.AddVmessServerCmd, v => v.menuAddVmessServer).DisposeWith(disposables); @@ -88,6 +89,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.AddTrojanServerCmd, v => v.menuAddTrojanServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables); @@ -111,7 +113,6 @@ namespace v2rayN.Views //servers ping this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.PingServerCmd, v => v.menuPingServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables); @@ -212,8 +213,6 @@ namespace v2rayN.Views var IsAdministrator = Utils.IsAdministrator(); this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; - spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed; - //if (_config.uiItem.autoHideStartup) //{ // WindowState = WindowState.Minimized; @@ -276,7 +275,7 @@ namespace v2rayN.Views private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) { - Utils.SaveLog("Current_SessionEnding"); + Logging.SaveLog("Current_SessionEnding"); StorageUI(); ViewModel?.MyAppExit(true); } @@ -330,10 +329,6 @@ namespace v2rayN.Views ViewModel?.AddServerViaClipboard(); break; - case Key.P: - ViewModel?.ServerSpeedtest(ESpeedActionType.Ping); - break; - case Key.O: ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping); break; @@ -343,7 +338,7 @@ namespace v2rayN.Views break; case Key.S: - _ = ViewModel?.ScanScreenTaskAsync(); + ViewModel?.ScanScreenTaskAsync().ContinueWith(_ => { }); break; case Key.T: @@ -479,12 +474,11 @@ namespace v2rayN.Views } var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList(); - for (int i = 0; i < lvColumnItem.Count; i++) + var displayIndex = 0; + foreach(var item in lvColumnItem) { - var item = lvColumnItem[i]; - for (int k = 1; k < lstProfiles.Columns.Count; k++) - { - var item2 = (MyDGTextColumn)lstProfiles.Columns[k]; + foreach (MyDGTextColumn item2 in lstProfiles.Columns) + { if (item2.ExName == item.Name) { if (item.Width < 0) @@ -494,7 +488,7 @@ namespace v2rayN.Views else { item2.Width = item.Width; - item2.DisplayIndex = i; + item2.DisplayIndex = displayIndex++; } } } diff --git a/v2rayN/v2rayN/Views/MsgView.xaml b/v2rayN/v2rayN/Views/MsgView.xaml index eea12849..440b77ab 100644 --- a/v2rayN/v2rayN/Views/MsgView.xaml +++ b/v2rayN/v2rayN/Views/MsgView.xaml @@ -3,11 +3,9 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:local="clr-namespace:v2rayN.Views" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:resx="clr-namespace:v2rayN.Resx" - xmlns:vms="clr-namespace:v2rayN.ViewModels" d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d"> @@ -41,6 +39,16 @@ Margin="8,0" HorizontalAlignment="Left" IsChecked="True" /> + + - - - - - +