diff --git a/v2rayN/ServiceLib/Common/Utils.cs b/v2rayN/ServiceLib/Common/Utils.cs index fc273dbe..c482d149 100644 --- a/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayN/ServiceLib/Common/Utils.cs @@ -479,6 +479,12 @@ namespace ServiceLib.Common #region 杂项 + public static bool UpgradeAppExists(out string fileName) + { + fileName = Path.Combine(Utils.StartupPath(), GetExeName("AmazTool")); + return File.Exists(fileName); + } + /// /// 取得版本 /// diff --git a/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs index fc1bcda6..8f7c319f 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs @@ -201,5 +201,14 @@ namespace ServiceLib.Handler.Fmt File.WriteAllText(fileName, strData); return fileName; } + protected static string ToUri(EConfigType eConfigType, string address, object port, string userInfo, Dictionary? dicQuery, string? remark) + { + var query = dicQuery != null + ? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray())) + : string.Empty; + + var url = $"{Utils.UrlEncode(userInfo)}@{GetIpv6(address)}:{port}"; + return $"{Global.ProtocolShares[eConfigType]}{url}{query}{remark}"; + } } } \ No newline at end of file diff --git a/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs b/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs index 5f877858..146d2d74 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs @@ -51,14 +51,7 @@ } dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0"); - string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); - - url = string.Format("{0}@{1}:{2}", - item.id, - GetIpv6(item.address), - item.port); - url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}/{query}{remark}"; - return url; + return ToUri(EConfigType.Hysteria2, item.address, item.port, item.id, dicQuery, remark); } public static ProfileItem? ResolveFull(string strData, string? subRemarks) diff --git a/v2rayN/ServiceLib/Handler/Fmt/ShadowsocksFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/ShadowsocksFmt.cs index 93c387f6..57f8e1bc 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/ShadowsocksFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/ShadowsocksFmt.cs @@ -42,9 +42,7 @@ namespace ServiceLib.Handler.Fmt //url = Utile.Base64Encode(url); //new Sip002 var pw = Utils.Base64Encode($"{item.security}:{item.id}"); - url = $"{pw}@{GetIpv6(item.address)}:{item.port}"; - url = $"{Global.ProtocolShares[EConfigType.Shadowsocks]}{url}{remark}"; - return url; + return ToUri(EConfigType.Shadowsocks, item.address, item.port, pw, null, remark); } private static readonly Regex UrlFinder = new(@"ss://(?[A-Za-z0-9+-/=_]+)(?:#(?\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled); @@ -98,7 +96,7 @@ namespace ServiceLib.Handler.Fmt address = parsedUrl.IdnHost, port = parsedUrl.Port, }; - string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped); + var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo); //2022-blake3 if (rawUserInfo.Contains(':')) { diff --git a/v2rayN/ServiceLib/Handler/Fmt/SocksFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/SocksFmt.cs index 0f0df5fb..cbf24fcc 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/SocksFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/SocksFmt.cs @@ -40,9 +40,7 @@ //url = Utile.Base64Encode(url); //new var pw = Utils.Base64Encode($"{item.security}:{item.id}"); - url = $"{pw}@{GetIpv6(item.address)}:{item.port}"; - url = $"{Global.ProtocolShares[EConfigType.SOCKS]}{url}{remark}"; - return url; + return ToUri(EConfigType.SOCKS, item.address, item.port, pw, null, remark); } private static ProfileItem? ResolveSocks(string result) @@ -112,9 +110,9 @@ }; // parse base64 UserInfo - string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped); - string userInfo = Utils.Base64Decode(rawUserInfo); - string[] userInfoParts = userInfo.Split(new[] { ':' }, 2); + var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo); + var userInfo = Utils.Base64Decode(rawUserInfo); + var userInfoParts = userInfo.Split(new[] { ':' }, 2); if (userInfoParts.Length == 2) { item.security = userInfoParts[0]; diff --git a/v2rayN/ServiceLib/Handler/Fmt/TrojanFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/TrojanFmt.cs index 51f08524..129ba9f3 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/TrojanFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/TrojanFmt.cs @@ -36,14 +36,8 @@ } var dicQuery = new Dictionary(); GetStdTransport(item, null, ref dicQuery); - string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); - url = string.Format("{0}@{1}:{2}", - item.id, - GetIpv6(item.address), - item.port); - url = $"{Global.ProtocolShares[EConfigType.Trojan]}{url}{query}{remark}"; - return url; + return ToUri(EConfigType.Trojan, item.address, item.port, item.id, dicQuery, remark); } } } \ No newline at end of file diff --git a/v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs index bdfdce91..e8da3ada 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs @@ -16,7 +16,8 @@ item.address = url.IdnHost; item.port = url.Port; item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); - var userInfoParts = url.UserInfo.Split(new[] { ':' }, 2); + var rawUserInfo = Utils.UrlDecode(url.UserInfo); + var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); if (userInfoParts.Length == 2) { item.id = userInfoParts[0]; @@ -51,14 +52,7 @@ } dicQuery.Add("congestion_control", item.headerType); - string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); - - url = string.Format("{0}@{1}:{2}", - $"{item.id}:{item.security}", - GetIpv6(item.address), - item.port); - url = $"{Global.ProtocolShares[EConfigType.TUIC]}{url}{query}{remark}"; - return url; + return ToUri(EConfigType.TUIC, item.address, item.port, $"{item.id}:{item.security}", dicQuery, remark); } } } \ No newline at end of file diff --git a/v2rayN/ServiceLib/Handler/Fmt/VLESSFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/VLESSFmt.cs index fdcc34d3..aa26af15 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/VLESSFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/VLESSFmt.cs @@ -47,14 +47,8 @@ dicQuery.Add("encryption", Global.None); } GetStdTransport(item, Global.None, ref dicQuery); - string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()); - url = string.Format("{0}@{1}:{2}", - item.id, - GetIpv6(item.address), - item.port); - url = $"{Global.ProtocolShares[EConfigType.VLESS]}{url}{query}{remark}"; - return url; + return ToUri(EConfigType.VLESS, item.address, item.port, item.id, dicQuery, remark); } } } \ No newline at end of file diff --git a/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs index 743a82be..b6c980a0 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs @@ -56,14 +56,7 @@ { 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; + return ToUri(EConfigType.WireGuard, item.address, item.port, item.id, dicQuery, remark); } } } \ No newline at end of file diff --git a/v2rayN/ServiceLib/Handler/WebDavHandler.cs b/v2rayN/ServiceLib/Handler/WebDavHandler.cs index 81386cc2..3eda381c 100644 --- a/v2rayN/ServiceLib/Handler/WebDavHandler.cs +++ b/v2rayN/ServiceLib/Handler/WebDavHandler.cs @@ -12,7 +12,7 @@ namespace ServiceLib.Handler private WebDavClient? _client; private string? _lastDescription; private string _webDir = Global.AppName + "_backup"; - private string _webFileName = "backup.zip"; + private readonly string _webFileName = "backup.zip"; private string _logTitle = "WebDav--"; public WebDavHandler() @@ -130,7 +130,7 @@ namespace ServiceLib.Handler try { - using var fs = File.OpenRead(fileName); + await using var fs = File.OpenRead(fileName); var result = await _client.PutFile($"{_webDir}/{_webFileName}", fs); // upload a resource if (result.IsSuccessful) { @@ -162,8 +162,9 @@ namespace ServiceLib.Handler SaveLog(response.Description); return false; } - using var outputFileStream = new FileStream(fileName, FileMode.Create); - response.Stream.CopyTo(outputFileStream); + + await using var outputFileStream = new FileStream(fileName, FileMode.Create); + await response.Stream.CopyToAsync(outputFileStream); return true; } catch (Exception ex) diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 90f5a643..15f1d568 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -3707,5 +3707,14 @@ namespace ServiceLib.Resx { return ResourceManager.GetString("UpdateStandalonePackageTip", resourceCulture); } } + + /// + /// 查找类似 UpgradeApp does not exist 的本地化字符串。 + /// + public static string UpgradeAppNotExistTip { + get { + return ResourceManager.GetString("UpgradeAppNotExistTip", resourceCulture); + } + } } } diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index c852e7a1..95053d3a 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1332,5 +1332,7 @@ Sing-box srs files source (optional) + + UpgradeApp does not exist \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index e2355650..59cba9c2 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1327,4 +1327,7 @@ Geo文件来源(可选) + + 升级工具App不存在 + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx index b85c239d..b53aa888 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1207,4 +1207,7 @@ Geo文件來源(可選) + + 升级工具App不存在 + \ No newline at end of file diff --git a/v2rayN/ServiceLib/ServiceLib.csproj b/v2rayN/ServiceLib/ServiceLib.csproj index 3a598909..d9b47d73 100644 --- a/v2rayN/ServiceLib/ServiceLib.csproj +++ b/v2rayN/ServiceLib/ServiceLib.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - 6.60.0 + 6.10.0 diff --git a/v2rayN/ServiceLib/Services/DownloadService.cs b/v2rayN/ServiceLib/Services/DownloadService.cs index 887ef88a..0a6c5ec7 100644 --- a/v2rayN/ServiceLib/Services/DownloadService.cs +++ b/v2rayN/ServiceLib/Services/DownloadService.cs @@ -100,7 +100,7 @@ namespace ServiceLib.Services }; HttpClient client = new(webRequestHandler); - HttpResponseMessage response = await client.GetAsync(url); + var response = await client.GetAsync(url); if (response.StatusCode == HttpStatusCode.Redirect && response.Headers.Location is not null) { return response.Headers.Location.ToString(); @@ -253,15 +253,12 @@ namespace ServiceLib.Services { try { - if (webProxy == null) - { - webProxy = GetWebProxy(true); - } + webProxy ??= GetWebProxy(true); try { var config = AppHandler.Instance.Config; - int responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10); + var responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10); return responseTime; } catch (Exception ex) @@ -279,7 +276,7 @@ namespace ServiceLib.Services public async Task GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout) { - int responseTime = -1; + var responseTime = -1; try { using var cts = new CancellationTokenSource(); @@ -290,8 +287,8 @@ namespace ServiceLib.Services UseProxy = webProxy != null }); - List oneTime = []; - for (int i = 0; i < 2; i++) + List oneTime = new(); + for (var i = 0; i < 2; i++) { var timer = Stopwatch.StartNew(); await client.GetAsync(url, cts.Token); diff --git a/v2rayN/ServiceLib/Services/UpdateService.cs b/v2rayN/ServiceLib/Services/UpdateService.cs index 97ac42c6..f25548ce 100644 --- a/v2rayN/ServiceLib/Services/UpdateService.cs +++ b/v2rayN/ServiceLib/Services/UpdateService.cs @@ -423,7 +423,7 @@ namespace ServiceLib.Services && File.Exists(Path.Combine(Utils.StartupPath(), "D3DCompiler_47_cor3.dll")) ) { - return coreInfo?.DownloadUrlWin64?.Replace("v2rayN.zip", "zz_v2rayN-SelfContained.zip"); + return coreInfo?.DownloadUrlWin64?.Replace(".zip", "-SelfContained.zip"); } return RuntimeInformation.ProcessArchitecture switch diff --git a/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs b/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs index 3b96c3da..7deececd 100644 --- a/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs @@ -126,11 +126,16 @@ namespace ServiceLib.ViewModels } //check var lstFiles = FileManager.GetFilesFromZip(fileName); - if (lstFiles is null || !lstFiles.Where(t => t.Contains(_guiConfigs)).Any()) + if (lstFiles is null || !lstFiles.Any(t => t.Contains(_guiConfigs))) { DisplayOperationMsg(ResUI.LocalRestoreInvalidZipTips); return; } + if (!Utils.UpgradeAppExists(out _)) + { + DisplayOperationMsg(ResUI.UpgradeAppNotExistTip); + return; + } //backup first var fileBackup = Utils.GetBackupPath(BackupFileName); diff --git a/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs b/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs index f7800ad8..aac02973 100644 --- a/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs @@ -235,6 +235,11 @@ namespace ServiceLib.ViewModels { return; } + if (!Utils.UpgradeAppExists(out _)) + { + UpdateView(_v2rayN, ResUI.UpgradeAppNotExistTip); + return; + } Locator.Current.GetService()?.UpgradeApp(fileName); } catch (Exception ex) diff --git a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs index a691647e..084e0f86 100644 --- a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs @@ -280,14 +280,21 @@ namespace ServiceLib.ViewModels } } - public async Task UpgradeApp(string fileName) + public async Task UpgradeApp(string arg) { + if (!Utils.UpgradeAppExists(out var fileName)) + { + NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.UpgradeAppNotExistTip); + Logging.SaveLog("UpgradeApp does not exist"); + return; + } + Process process = new() { StartInfo = new ProcessStartInfo { - FileName = "AmazTool", - Arguments = fileName.AppendQuotes(), + FileName = fileName, + Arguments = arg.AppendQuotes(), WorkingDirectory = Utils.StartupPath() } };