using System; using System.IO; using System.IO.Compression; using System.Text; using CefSharp; using CefSharp.SchemeHandler; using CefSharp.WinForms; using NLog; namespace VRCX { public class CefService { public static readonly CefService Instance; private static readonly Logger logger = LogManager.GetCurrentClassLogger(); private static string _lastCefVersionPath = string.Empty; static CefService() { _lastCefVersionPath = Path.Join(Program.AppDataDirectory, "LastCefVersion"); Instance = new CefService(); } internal void Init() { var isOverlay = StartupArgs.LaunchArguments.IsOverlay; var userDataDir = Path.Join(Program.AppDataDirectory, "userdata"); if (isOverlay) userDataDir = Path.Join(Program.AppDataDirectory, "overlay/userdata"); // delete userdata if Cef version has been downgraded, fixes VRCX not opening after a downgrade CheckCefVersion(userDataDir); var cefSettings = new CefSettings { RootCachePath = userDataDir, CachePath = Path.Join(userDataDir, "cache"), LogSeverity = Program.LaunchDebug ? LogSeverity.Verbose : LogSeverity.Error, LogFile = Path.Join(Program.AppDataDirectory, "logs", "cef.log"), WindowlessRenderingEnabled = true, PersistSessionCookies = true, UserAgent = Program.Version, BrowserSubprocessPath = Environment.ProcessPath, BackgroundColor = 0xFF0A0A0A }; if (isOverlay) cefSettings.LogFile = Path.Join(Program.AppDataDirectory, "overlay/logs/cef.log"); cefSettings.RegisterScheme(new CefCustomScheme { SchemeName = "file", DomainName = "vrcx", SchemeHandlerFactory = new FolderSchemeHandlerFactory( Path.Join(Program.BaseDirectory, "html"), "file", defaultPage: "index.html" ), IsLocal = true }); // cefSettings.CefCommandLineArgs.Add("ignore-certificate-errors"); // cefSettings.CefCommandLineArgs.Add("disable-plugins"); cefSettings.CefCommandLineArgs.Add("disable-spell-checking"); cefSettings.CefCommandLineArgs.Add("disable-pdf-extension"); cefSettings.CefCommandLineArgs["autoplay-policy"] = "no-user-gesture-required"; cefSettings.CefCommandLineArgs.Add("disable-web-security"); // cefSettings.CefCommandLineArgs.Add("disk-cache-size", "2147483647"); cefSettings.CefCommandLineArgs.Add("unsafely-disable-devtools-self-xss-warnings"); cefSettings.CefCommandLineArgs.Add("do-not-de-elevate"); // fix program failing to start when running as admin if (WebApi.ProxySet) { cefSettings.CefCommandLineArgs["proxy-server"] = WebApi.ProxyUrl; } if (VRCXStorage.Instance.Get("VRCX_DisableGpuAcceleration") == "true") { cefSettings.CefCommandLineArgs.Add("disable-gpu"); } if (Program.LaunchDebug) { // chrome://inspect/#devices // Discover network targets, Configure... // Add Remote Target: localhost:8089 logger.Info("Debug mode enabled"); cefSettings.RemoteDebuggingPort = !isOverlay ? 8089 : 8090; cefSettings.CefCommandLineArgs["remote-allow-origins"] = "*"; } // load extensions in debug mode if (Program.LaunchDebug && !isOverlay) { var extensionsPath = Path.Join(Program.AppDataDirectory, "extensions"); Directory.CreateDirectory(extensionsPath); // extract Vue Devtools var vueDevtoolsCrxPath = Path.Join(Program.BaseDirectory, @"..\..\Dotnet\build-tools\Vue-js-devtools.crx"); if (File.Exists(vueDevtoolsCrxPath)) { var vueDevtoolsPath = Path.Join(extensionsPath, "Vue-js-devtools"); try { if (Directory.Exists(vueDevtoolsPath)) Directory.Delete(vueDevtoolsPath, true); Directory.CreateDirectory(vueDevtoolsPath); ZipFile.ExtractToDirectory(vueDevtoolsCrxPath, vueDevtoolsPath); } catch (Exception ex) { logger.Error(ex, "Failed to extract Vue Devtools"); } } // load extensions var folders = Directory.GetDirectories(extensionsPath); foreach (var folder in folders) { cefSettings.CefCommandLineArgs.Add("load-extension", folder); } } CefSharpSettings.ShutdownOnExit = true; CefSharpSettings.SubprocessExitIfParentProcessClosed = true; CefSharpSettings.ConcurrentTaskExecution = true; if (!Cef.Initialize(cefSettings, false)) { logger.Error("Cef failed to initialize"); throw new Exception("Cef.Initialize()"); } } private void CheckCefVersion(string userDataDir) { var currentVersion = Cef.ChromiumVersion; if (File.Exists(_lastCefVersionPath)) { var lastCefVersion = File.ReadAllText(_lastCefVersionPath).Trim(); var lastCefVersionParts = lastCefVersion.Split('.'); var currentVersionParts = currentVersion.Split('.'); if (lastCefVersionParts.Length != currentVersionParts.Length) { logger.Info("Cef version mismatch detected, deleting userdata: {0} -> {1}", lastCefVersion, currentVersion); DeleteUserData(userDataDir); } for (var i = 0; i < lastCefVersionParts.Length; i++) { if (int.TryParse(lastCefVersionParts[i], out var lastPart) && int.TryParse(currentVersionParts[i], out var currentPart) && lastPart > currentPart) { logger.Info("Cef downgrade detected, deleting userdata: {0} -> {1}", lastCefVersion, currentVersion); DeleteUserData(userDataDir); break; } } } File.WriteAllBytes(_lastCefVersionPath, Encoding.UTF8.GetBytes(currentVersion)); logger.Info("Cef version: {0}", currentVersion); } private static void DeleteUserData(string userDataDir) { if (!Directory.Exists(userDataDir)) return; try { Directory.Delete(userDataDir, true); } catch (Exception ex) { logger.Error(ex, "Failed to delete userdata directory: {0}", userDataDir); } } internal void Exit() { Cef.Shutdown(); } } }