From e26aed5c6a7dd196af4be6452230dbd2caef12a2 Mon Sep 17 00:00:00 2001 From: Natsumi Date: Wed, 17 Jul 2024 10:31:18 +1200 Subject: [PATCH] Proxy settings --- Dotnet/Cef/CefService.cs | 8 ++++++ Dotnet/ImageCache.cs | 21 +++++++++++----- Dotnet/MainForm.cs | 6 ----- Dotnet/Program.cs | 3 +-- Dotnet/StartupArgs.cs | 6 ++--- Dotnet/Update.cs | 2 +- Dotnet/WebApi.cs | 42 +++++++++++++++++++++++++++---- html/src/app.js | 33 ++++++++++++++++++++++++ html/src/localization/en/en.json | 12 ++++++++- html/src/mixins/loginPage.pug | 5 +++- html/src/mixins/tabs/settings.pug | 2 ++ 11 files changed, 114 insertions(+), 26 deletions(-) diff --git a/Dotnet/Cef/CefService.cs b/Dotnet/Cef/CefService.cs index b1751d74..10e119e5 100644 --- a/Dotnet/Cef/CefService.cs +++ b/Dotnet/Cef/CefService.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Net; using CefSharp; using CefSharp.SchemeHandler; using CefSharp.WinForms; @@ -9,6 +10,7 @@ namespace VRCX public class CefService { public static readonly CefService Instance; + private static readonly NLog.Logger logger = NLog.LogManager.GetLogger("VRCX"); static CefService() { @@ -51,8 +53,14 @@ namespace VRCX cefSettings.CefCommandLineArgs.Add("disable-web-security"); cefSettings.SetOffScreenRenderingBestPerformanceArgs(); // causes white screen sometimes? + if (WebApi.ProxySet) + { + cefSettings.CefCommandLineArgs["proxy-server"] = WebApi.ProxyUrl; + } + if (Program.LaunchDebug) { + logger.Info("Debug mode enabled"); cefSettings.RemoteDebuggingPort = 8088; cefSettings.CefCommandLineArgs["remote-allow-origins"] = "*"; } diff --git a/Dotnet/ImageCache.cs b/Dotnet/ImageCache.cs index 7e327451..fe887f6e 100644 --- a/Dotnet/ImageCache.cs +++ b/Dotnet/ImageCache.cs @@ -8,11 +8,10 @@ using System.Threading.Tasks; namespace VRCX { - class ImageCache + internal static class ImageCache { - private static readonly string cacheLocation = Path.Combine(Program.AppDataDirectory, "ImageCache"); - private static readonly HttpClientHandler httpClientHandler = new HttpClientHandler(){ Proxy = WebApi.Proxy }; - private static readonly HttpClient httpClient = new HttpClient(httpClientHandler); + private static readonly string cacheLocation; + private static readonly HttpClient httpClient; private static readonly List _imageHosts = [ "api.vrchat.cloud", @@ -21,6 +20,16 @@ namespace VRCX "assets.vrchat.com" ]; + static ImageCache() + { + cacheLocation = Path.Combine(Program.AppDataDirectory, "ImageCache"); + var httpClientHandler = new HttpClientHandler(); + if (WebApi.ProxySet) + httpClientHandler.Proxy = WebApi.Proxy; + + httpClient = new HttpClient(httpClientHandler); + } + public static async Task GetImage(string url, string fileId, string version) { var directoryLocation = Path.Combine(cacheLocation, fileId); @@ -74,9 +83,9 @@ namespace VRCX private static void CleanImageCache() { - DirectoryInfo dirInfo = new DirectoryInfo(cacheLocation); + var dirInfo = new DirectoryInfo(cacheLocation); var folders = dirInfo.GetDirectories().OrderByDescending(p => p.LastWriteTime).Skip(1000); - foreach (DirectoryInfo folder in folders) + foreach (var folder in folders) { folder.Delete(true); } diff --git a/Dotnet/MainForm.cs b/Dotnet/MainForm.cs index e762953e..662708c9 100644 --- a/Dotnet/MainForm.cs +++ b/Dotnet/MainForm.cs @@ -58,12 +58,6 @@ namespace VRCX Dock = DockStyle.Fill }; - string? proxyUrl = VRCXStorage.Instance.Get("VRCX_ProxyServer"); - if (!string.IsNullOrEmpty(proxyUrl)) - { - WebApi.Proxy = new WebProxy(proxyUrl); - } - Browser.IsBrowserInitializedChanged += (A, B) => { if (Program.LaunchDebug) diff --git a/Dotnet/Program.cs b/Dotnet/Program.cs index b82513fd..b80aeca1 100644 --- a/Dotnet/Program.cs +++ b/Dotnet/Program.cs @@ -167,8 +167,7 @@ namespace VRCX Application.SetCompatibleTextRenderingDefault(false); logger.Info("{0} Starting...", Version); - - + ProcessMonitor.Instance.Init(); SQLiteLegacy.Instance.Init(); AppApi.Instance.Init(); diff --git a/Dotnet/StartupArgs.cs b/Dotnet/StartupArgs.cs index 601647fe..e6bf753c 100644 --- a/Dotnet/StartupArgs.cs +++ b/Dotnet/StartupArgs.cs @@ -19,6 +19,7 @@ namespace VRCX internal class StartupArgs { public static string LaunchCommand; + public static string ProxyUrl; public static Process[] processList; public static void ArgsCheck() @@ -52,10 +53,7 @@ namespace VRCX Program.LaunchDebug = true; if (arg.Length >= 16 && arg.Substring(0, 14) == "--proxy-server") - { - string proxyUrl = arg.Substring(15).Replace("'", string.Empty).Replace("\"", string.Empty); - WebApi.Proxy = new WebProxy(proxyUrl); - } + ProxyUrl = arg.Substring(15).Replace("'", string.Empty).Replace("\"", string.Empty); } var type = CommandLineArgsParser.GetArgumentValue(args, CefSharpArguments.SubProcessTypeArgument); diff --git a/Dotnet/Update.cs b/Dotnet/Update.cs index 648a30d8..c66ed823 100644 --- a/Dotnet/Update.cs +++ b/Dotnet/Update.cs @@ -56,6 +56,7 @@ namespace VRCX MessageBox.Show(e.ToString(), "Update failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } + public static void DownloadInstallRedist() { try @@ -78,7 +79,6 @@ namespace VRCX } } - private static string DownloadFile(string fileUrl) { HttpClient client = new HttpClient(); diff --git a/Dotnet/WebApi.cs b/Dotnet/WebApi.cs index f22b339b..86953f89 100644 --- a/Dotnet/WebApi.cs +++ b/Dotnet/WebApi.cs @@ -16,10 +16,14 @@ namespace VRCX public class WebApi { public static readonly WebApi Instance; + + public static bool ProxySet; + public static string ProxyUrl = ""; + public static IWebProxy Proxy = WebRequest.DefaultWebProxy; + public CookieContainer _cookieContainer; private bool _cookieDirty; private Timer _timer; - public static IWebProxy? Proxy = WebRequest.DefaultWebProxy; static WebApi() { @@ -47,10 +51,30 @@ namespace VRCX internal void Init() { + SetProxy(); LoadCookies(); _timer.Change(1000, 1000); } + private void SetProxy() + { + if (!string.IsNullOrEmpty(StartupArgs.ProxyUrl)) + ProxyUrl = StartupArgs.ProxyUrl; + + if (string.IsNullOrEmpty(ProxyUrl)) + { + var proxyUrl = VRCXStorage.Instance.Get("VRCX_ProxyServer"); + if (!string.IsNullOrEmpty(proxyUrl)) + ProxyUrl = proxyUrl; + } + + if (string.IsNullOrEmpty(ProxyUrl)) + return; + + ProxySet = true; + Proxy = new WebProxy(ProxyUrl); + } + internal void Exit() { _timer.Change(-1, -1); @@ -145,7 +169,9 @@ namespace VRCX private static async Task LegacyImageUpload(HttpWebRequest request, IDictionary options) { - request.Proxy = Proxy; + if (ProxySet) + request.Proxy = Proxy; + request.Method = "POST"; string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); request.ContentType = "multipart/form-data; boundary=" + boundary; @@ -190,7 +216,9 @@ namespace VRCX private static async Task UploadFilePut(HttpWebRequest request, IDictionary options) { - request.Proxy = Proxy; + if (ProxySet) + request.Proxy = Proxy; + request.Method = "PUT"; request.ContentType = options["fileMIME"] as string; var fileData = options["fileData"] as string; @@ -205,7 +233,9 @@ namespace VRCX private static async Task ImageUpload(HttpWebRequest request, IDictionary options) { - request.Proxy = Proxy; + if (ProxySet) + request.Proxy = Proxy; + request.Method = "POST"; string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); request.ContentType = "multipart/form-data; boundary=" + boundary; @@ -259,7 +289,9 @@ namespace VRCX try { var request = WebRequest.CreateHttp((string)options["url"]); - request.Proxy = Proxy; + if (ProxySet) + request.Proxy = Proxy; + request.CookieContainer = _cookieContainer; request.KeepAlive = true; request.UserAgent = Program.Version; diff --git a/html/src/app.js b/html/src/app.js index 62b98233..48fb93fe 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -15659,6 +15659,10 @@ speechSynthesis.getVoices(); if (!(await VRCXStorage.Get('VRCX_DatabaseLocation'))) { await VRCXStorage.Set('VRCX_DatabaseLocation', ''); } + if (!(await VRCXStorage.Get('VRCX_ProxyServer'))) { + await VRCXStorage.Set('VRCX_ProxyServer', ''); + } + $app.data.proxyServer = await VRCXStorage.Get('VRCX_ProxyServer'); $app.data.disableWorldDatabase = (await VRCXStorage.Get('VRCX_DisableWorldDatabase')) === 'true'; $app.methods.saveVRCXWindowOption = async function () { @@ -32886,6 +32890,35 @@ speechSynthesis.getVoices(); // #endregion + // #region proxy settings + + $app.methods.promptProxySettings = function () { + this.$prompt( + $t('prompt.proxy_settings.description'), + $t('prompt.proxy_settings.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.proxy_settings.restart'), + cancelButtonText: $t('prompt.proxy_settings.close'), + inputValue: this.proxyServer, + inputPlaceholder: $t('prompt.proxy_settings.placeholder'), + callback: async (action, instance) => { + this.proxyServer = instance.inputValue; + await VRCXStorage.Set('VRCX_ProxyServer', this.proxyServer); + await VRCXStorage.Flush(); + await new Promise((resolve) => { + workerTimers.setTimeout(resolve, 100); + }); + if (action === 'confirm') { + AppApi.RestartApplication(); + } + } + } + ); + }; + + // #endregion + $app = new Vue($app); window.$app = $app; })(); diff --git a/html/src/localization/en/en.json b/html/src/localization/en/en.json index 76cc6469..b61e6156 100644 --- a/html/src/localization/en/en.json +++ b/html/src/localization/en/en.json @@ -20,6 +20,8 @@ "login": "Login", "register": "Register", "forgotPassword": "Forgot Password?", + "updater": "Updater", + "proxy_settings": "Proxy settings", "field": { "username": "Username or Email", "password": "Password", @@ -211,7 +213,8 @@ "header": "Application", "startup": "Start at Windows startup", "minimized": "Start as minimized state", - "tray": "Close to tray" + "tray": "Close to tray", + "proxy": "Proxy settings" }, "favorites": { "header": "VRCX Favorite Friends", @@ -1600,6 +1603,13 @@ "cancel": "Cancel", "save": "Save", "input_error": "Valid number is required" + }, + "proxy_settings": { + "header": "Proxy Settings", + "description": "Enter proxy server address and port", + "placeholder": "127.0.0.1:8080", + "close": "Close", + "restart": "Restart" } }, "table": { diff --git a/html/src/mixins/loginPage.pug b/html/src/mixins/loginPage.pug index cf45bbc2..21776c1d 100644 --- a/html/src/mixins/loginPage.pug +++ b/html/src/mixins/loginPage.pug @@ -2,7 +2,10 @@ mixin loginPage() .x-login-container(v-if="!API.isLoggedIn" v-loading="loginForm.loading") .x-login div(style="position:fixed; top: 0; left: 0; margin:5px") - el-button(type="default" @click="showVRCXUpdateDialog" size="mini" icon="el-icon-download" circle) + el-tooltip(placement="top" :content="$t('view.login.updater')" :disabled="hideTooltips") + el-button(type="default" @click="showVRCXUpdateDialog" size="mini" icon="el-icon-download" circle) + el-tooltip(placement="top" :content="$t('view.login.proxy_settings')" :disabled="hideTooltips") + el-button(type="default" @click="promptProxySettings" size="mini" icon="el-icon-connection" style="margin-left:5px" circle) div.x-login-form-container div diff --git a/html/src/mixins/tabs/settings.pug b/html/src/mixins/tabs/settings.pug index 92a4c8b0..a3d721d0 100644 --- a/html/src/mixins/tabs/settings.pug +++ b/html/src/mixins/tabs/settings.pug @@ -84,6 +84,8 @@ mixin settingsTab() +simpleSwitch("view.settings.general.application.startup", "isStartAtWindowsStartup", "saveVRCXWindowOption") +simpleSwitch("view.settings.general.application.minimized", "isStartAsMinimizedState", "saveVRCXWindowOption") +simpleSwitch("view.settings.general.application.tray", "isCloseToTray", "saveVRCXWindowOption") + div.options-container-item + el-button(size="small" icon="el-icon-connection" @click="promptProxySettings()") {{ $t("view.settings.general.application.proxy") }} //- General | Favorite +simpleSettingsCategory("view.settings.general.favorites.header") br