From 8a82a45ab2370cb1143f9d0c0a8f644601d929cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=CC=81=20Manuel=20Ca=CC=81mara=20Iglesias?= Date: Sat, 30 May 2020 22:19:01 +0200 Subject: [PATCH] Include queue for the requests To ensure we are not sending too many requests at once --- Editor/WakaTime/ClientManager.cs | 143 ++++++++++++++++++++++------- Editor/WakaTime/Main.cs | 42 ++++++++- Editor/WakaTime/PythonInstaller.cs | 8 +- Editor/WakaTime/Window.cs | 2 + 4 files changed, 156 insertions(+), 39 deletions(-) diff --git a/Editor/WakaTime/ClientManager.cs b/Editor/WakaTime/ClientManager.cs index 5f1de8e..d9479e3 100644 --- a/Editor/WakaTime/ClientManager.cs +++ b/Editor/WakaTime/ClientManager.cs @@ -1,14 +1,55 @@ using System.Diagnostics; using System.IO; using UnityEngine; +using System.Collections.Generic; +using System.Threading.Tasks; +using System; namespace WakaTime { + /// + /// Client request. + /// Contains the information needed to make 1 wakatime heartbeat. + /// + public readonly struct ClientRequest + { + /// + /// Constructor. + /// + /// + /// + public ClientRequest(string apiKey, string file) + { + this.apiKey = apiKey; + this.file = file; + } + + /// + /// WakaTime API Key + /// + public readonly string apiKey; + + /// + /// File to sned to wakatime. + /// + public readonly string file; + } + /// /// Handles operations with wakatime client. /// public class ClientManager { + /// + /// Requests stacks + /// + protected static readonly Queue requests = new Queue(); + + /// + /// Number of active requests. + /// + protected static int activeRequests = 0; + /// /// Gets the base directory where wakatime is installed. /// @@ -65,54 +106,90 @@ public static bool IsClientLatestVersion() /// /// /// - public static void HeartBeat(string apiKey, string file, bool write = false) + public async static Task HeartBeat(string apiKey, string file, bool write = false) { - if (!PythonManager.IsPythonInstalled()) return; + if (activeRequests < Main.MaxRequests) + { + activeRequests++; - string arguments = "--key " + apiKey + - " --file " + "\"" + file + "\"" + - " --plugin " + WakaTimeConstants.PLUGIN_NAME + - " --project " + "\"" + Main.GetProjectName() + "\"" + - " --verbose"; + if (Main.IsDebug) + { + UnityEngine.Debug.Log("[wakatime] Making request: " + activeRequests + " / " + Main.MaxRequests + " (enqueued: " + requests.Count + ")"); + } - if (Main.IsDebug) - { - UnityEngine.Debug.Log("[wakatime] Sending file: " + PythonManager.GetPythonPath() + " " + GetClientPath() + - " " + arguments); - } + var dataPath = Application.dataPath; + var projectName = Main.GetProjectName(); + var clientPath = GetClientPath(); + await Task.Run(() => MakeRequest(apiKey, file, projectName, dataPath, clientPath)); - Process p = new Process + activeRequests--; + if (requests.Count > 0) + { + var request = requests.Dequeue(); + await HeartBeat(request.apiKey, request.file); + } + } + else { - StartInfo = { - FileName = PythonManager.GetPythonPath (), - Arguments = "\"" + GetClientPath () + "\" " + arguments, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - WorkingDirectory = Application.dataPath, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true + if (Main.IsDebug) + { + UnityEngine.Debug.Log("[wakatime] Request enqueued (" + requests.Count + ")"); } - }; - p.Start(); + requests.Enqueue(new ClientRequest(apiKey, file)); + } + } - if (Main.IsDebug) + /// + /// Sends a heart-beat to wakatime. + /// Only works if the client is not installed. + /// + /// + /// + /// + /// + /// + protected static void MakeRequest(string apiKey, string file, string projectName, string dataPath, string clientPath) + { + try { - var output = p.StandardOutput.ReadToEnd(); - if (output.Length > 0) + string arguments = "--key " + apiKey + + " --file " + "\"" + file + "\"" + + " --plugin " + WakaTimeConstants.PLUGIN_NAME + + " --project " + "\"" + projectName + "\"" + + " --verbose"; + + if (Main.IsDebug) { - UnityEngine.Debug.Log("[wakatime] Output: " + output); + UnityEngine.Debug.Log("[wakatime] Sending file: " + file); } - var errors = p.StandardError.ReadToEnd(); - if (errors.Length > 0) + Process p = new Process { - UnityEngine.Debug.LogError("[wakatime] Error: " + errors); + StartInfo = { + FileName = PythonManager.GetPythonPath (), + Arguments = "\"" + clientPath + "\" " + arguments, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + WorkingDirectory = dataPath, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + } + }; + + p.Start(); + p.WaitForExit(5000); + + UnityEngine.Debug.Log("[wakatime] Finished sending file " + file); + } + catch (Exception ex) + { + if (Main.IsDebug) + { + UnityEngine.Debug.LogError("[wakatime] Error found while sending heartbeat to wakatime for file " + file + ": " + ex); } } - - p.Close(); } } } \ No newline at end of file diff --git a/Editor/WakaTime/Main.cs b/Editor/WakaTime/Main.cs index ea6485e..41dd79e 100644 --- a/Editor/WakaTime/Main.cs +++ b/Editor/WakaTime/Main.cs @@ -29,6 +29,11 @@ public class Main /// public const string KEY_API_KEY = "wakatime_api_key"; + /// + /// Key in editor preferences to get max requests. + /// + public const string KEY_MAX_REQUESTS = "wakatime_max_requests"; + /// /// Name of the current scene. /// @@ -113,6 +118,35 @@ public static bool IsDebug } } + /// + /// Maximun number of concurrent requests to wakatime. + /// 5 by default. + /// + static int? _maxRequests = null; + + /// + /// Max requests wrapper. + /// Gets the value from the editor preferences if it's not set. + /// Saves the new value in the editor preferences. + /// + public static int MaxRequests + { + get + { + if (_maxRequests == null) + { + _maxRequests = EditorPrefs.GetInt(KEY_API_KEY, 5); + } + + return (int)_maxRequests; + } + set + { + _maxRequests = value; + EditorPrefs.SetInt(KEY_MAX_REQUESTS, value); + } + } + /// /// Last times when the files changed. /// {file path} => {last updated at} @@ -167,7 +201,7 @@ public static bool Check() { bool res = false; - // Checking pythong client is expensive, so only do if the API key is set. + // Checking python client is expensive, so only do if the API key is set. if (CheckAPIKey()) { res = CheckPython(); @@ -292,11 +326,11 @@ public static void OnAssetSaved(string path) /// /// File path /// - static void RequestSendFile(string path, bool write = false) + static async void RequestSendFile(string path, bool write = false) { if (Check() && ShouldSendFile(path)) { - ClientManager.HeartBeat(GetApiKey(), path, write); + await ClientManager.HeartBeat(GetApiKey(), path, write); } } @@ -344,7 +378,7 @@ static bool ShouldSendFile(string path) Debug.Log("[wakatime] Should send " + path.Substring(path.LastIndexOf("/") + 1) + "? [" + (shouldSendFile ? "yes" : "no") + "]"); } - return shouldSendFile; + return true; } } } diff --git a/Editor/WakaTime/PythonInstaller.cs b/Editor/WakaTime/PythonInstaller.cs index 8ab22a4..f521776 100644 --- a/Editor/WakaTime/PythonInstaller.cs +++ b/Editor/WakaTime/PythonInstaller.cs @@ -5,6 +5,8 @@ using System.IO; +#pragma warning disable 612, 618 + namespace WakaTime { /// @@ -122,7 +124,7 @@ static void DownloadCompleted() if (Main.IsDebug) { - UnityEngine.Debug.Log("Python downloaded: " + www.size.ToString()); + UnityEngine.Debug.Log("Python downloaded: " + www.bytesDownloaded.ToString()); } string dir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData); string localFile = dir + PythonManager.GetPythonFileName(); @@ -183,4 +185,6 @@ static void Install() } } } -} \ No newline at end of file +} + +#pragma warning restore 612, 618 \ No newline at end of file diff --git a/Editor/WakaTime/Window.cs b/Editor/WakaTime/Window.cs index 6915647..08a9d6c 100644 --- a/Editor/WakaTime/Window.cs +++ b/Editor/WakaTime/Window.cs @@ -41,6 +41,8 @@ void OnGUI() { EditorGUILayout.HelpBox("API Key is required", MessageType.Error, false); } + Main.MaxRequests = EditorGUILayout.IntField("Max Requests", Main.MaxRequests); + EditorGUILayout.HelpBox("Maximum number of simultaneous requests to wakatime. Be cautious when increasing this value, since that might cause CPU problems.", MessageType.Info, true); EditorGUILayout.Separator();