Skip to content
Snippets Groups Projects
Browser.cs 5.75 KiB
Newer Older
  • Learn to ignore specific revisions
  • using Newtonsoft.Json;
    using Newtonsoft.Json.Serialization;
    using System;
    using System.Collections;
    using System.Diagnostics;
    using System.IO;
    using System.Threading;
    using UnityEngine;
    using UnityEngine.Networking;
    
    
    {
        public class Browser
        {
            /* singleton */
            private static Browser instance;
    
            private Process browserProcess;
    
    
            /* browser settings */
    
            public static string browserExecutablePath = "chrome";
            public static bool headless = true;
    
            private const int debugPort = 9222;
    
    
            /// <summary>
            /// Json serializer for the devtools connection
            /// </summary>
            public static JsonSerializer devtoolsSerializer;
            /// <summary>
            /// Json serializer settings for the devtools connection
            /// </summary>
            public static JsonSerializerSettings devtoolsSerializerSettings;
    
    
            public static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    
            /**
             * get singleton instance
             */
            public static Browser getInstance()
            {
    
                if (instance == null || instance.browserProcess.HasExited)
    
                {
                    instance = new Browser();
                    instance.launchBrowser();
                }
                return instance;
            }
    
            /**
             * constructor for the static fields
             */
            static Browser()
            {
                // initialize the JsonSerializer
    
                devtoolsSerializerSettings = new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                };
                devtoolsSerializer = JsonSerializer.Create(devtoolsSerializerSettings);
    
            }
    
            /**
            * Launch headless chrome browser with remote-debugging enabled, if not already running.
            */
            private  void launchBrowser()
            {
                // allow only one instance of chrome
    
                if (browserProcess == null || browserProcess.HasExited)
    
                    browserProcess = new Process();
                    browserProcess.StartInfo.FileName = browserExecutablePath;
                    browserProcess.StartInfo.Arguments = String.Join(" ", new []{
                        $"--user-data-dir={Path.Join(Application.temporaryCachePath, "BrowserView")}",
                        $"--remote-debugging-port={debugPort}",
                        $"--remote-allow-origins=http://localhost:{debugPort}",
                        "--hide-crash-restore-bubble",
                        "--disable-first-run-ui",
                        "--no-first-run"
                    });
    
    
                    // set headlessBrowser to false to see the browser window
    
                        browserProcess.StartInfo.Arguments = string.Concat(browserProcess.StartInfo.Arguments, " --headless=new");
    
                        browserProcess.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
    
                    // register an error handler
                    browserProcess.ErrorDataReceived += (sender, e) => UnityEngine.Debug.LogError($"Browser Error: {e.Data} ExitCode: {browserProcess.ExitCode}");
                    browserProcess.Exited += (sender, e) => UnityEngine.Debug.LogError($"Browser Exited, ExitCode: {browserProcess.ExitCode}");
    
                    browserProcess.Start();
                    if (browserProcess.HasExited) {
                        UnityEngine.Debug.LogError("Failed to start browser");
                    }
                    UnityEngine.Debug.Log($"launched '{browserProcess.StartInfo.FileName} {browserProcess.StartInfo.Arguments}'");
    
                }
            }
    
            /**
             * send web request to the devTools API
             */
    
            private IEnumerator DevToolsApiRequest(bool isPUT, string apiAddress, Action<string> callback)
    
            {
                UnityEngine.Debug.Log($"DevTools api Request: {apiAddress}");
                UnityWebRequest webRequest;
                if (isPUT)
                {
                    webRequest = UnityWebRequest.Put($"http://localhost:{debugPort}{apiAddress}", "");
                }
                else
                {
                    webRequest = UnityWebRequest.Get($"http://localhost:{debugPort}{apiAddress}");
                }
                yield return webRequest.SendWebRequest();
    
                if (webRequest.result != UnityWebRequest.Result.Success)
                {
                    UnityEngine.Debug.LogError(webRequest.error);
                    //TODO: handle error
                }
                else
                {
                    UnityEngine.Debug.Log($"DevTools api response (for {apiAddress}):\n{webRequest.downloadHandler.text}");
                    callback(webRequest.downloadHandler.text);
                }
            }
    
    
            public IEnumerator OpenNewTab(string targetUrl, Action<BrowserTab> callback)
    
            {
                yield return DevToolsApiRequest(true, $"/json/new?{targetUrl}", (response) =>
                {
    
                    PageTargetInfo pageTarget = JsonConvert.DeserializeObject<PageTargetInfo>(response, devtoolsSerializerSettings);
    
                    callback(new BrowserTab(pageTarget));
    
                });
            }
    
            /**
             * Not implemented.
             */
            [Obsolete("Not implemented.", true)]
            private IEnumerator GetOpenTabs()
            {
                yield return DevToolsApiRequest(false, "/json/list", (response) =>
                {
                    UnityEngine.Debug.Log($"Currently open tabs:\n{response}");
                });
            }
    
            /**
             * Close the browser
             */
            public void Close()
            {
                cancellationTokenSource.Cancel();
                if (browserProcess != null && !browserProcess.HasExited)
                {
                    browserProcess.Kill();
                }
            }
        }
    }