private static void ProcessPulses(object sender, ElapsedEventArgs e) { Task.Run(() => { try { if (pulseQueue != null && ((currentPulse != null && !currentPulse.isEmpty()) || !pulseQueue.IsEmpty) && EnoughTimePassed(DateTime.Now)) { if (currentPulse != null && !currentPulse.isEmpty()) { pulseQueue.Enqueue(currentPulse); currentPulse = new Pulse(); currentCount = 0; } // run only if the task didn't run yet, or the previous one already finished if (pulseProcessor == null || pulseProcessor.IsCompleted || pulseProcessor.IsFaulted) // don't start if it's cancelled { try { pulseProcessor = ProcessPulses(pulseProcessor_tokensource); } catch (OperationCanceledException) {} } //ProcessPulses(); } UpdateStatusbar(); } catch (Exception ex) { Logger.Error("Error processing pulses", ex); } }); }
internal static void PluginCleanUp() { try { nppStarted = false; Logger.Debug("Cancelling pulses..."); // Flush the current pulse if (pulseQueue != null && currentPulse != null && !currentPulse.IsEmpty()) { pulseQueue.Enqueue(currentPulse); currentPulse = new Pulse(); currentCount = 0; } pulseProcessor_tokensource.Cancel(); if (timer != null) { timer.Stop(); timer.Elapsed -= ProcessPulses; timer.Dispose(); timer = null; // make sure the queue is empty //ProcessPulses(); } // test if we can cancel and dump pulses JavaScriptSerializer jsonSerializer = new JavaScriptSerializer(); if (pulseProcessor == null) { Logger.Info("pulseProcessor.wait() would fail, as pulseProcessor is null"); } else { Logger.Info("calling pulseProcessor.Wait()"); pulseProcessor.Wait(); } while (pulseQueue.TryDequeue(out Pulse result)) { if (!result.IsEmpty()) { string json = jsonSerializer.Serialize(result); Logger.Debug("Unsaved pulse: " + json); } } } catch (Exception ex) { Logger.Error("error on plugincleanup", ex); } }
internal static void PluginCleanUp() { nppStarted = false; Logger.Debug("Cancelling pulses..."); // Flush the current pulse if (pulseQueue != null && currentPulse != null && !currentPulse.isEmpty()) { pulseQueue.Enqueue(currentPulse); currentPulse = new Pulse(); currentCount = 0; } pulseProcessor_tokensource.Cancel(); if (timer != null) { timer.Stop(); timer.Elapsed -= ProcessPulses; timer.Dispose(); timer = null; // make sure the queue is empty //ProcessPulses(); } // test if we can cancel and dump pulses var jsonSerializer = new JavaScriptSerializer(); pulseProcessor.Wait(); Pulse result; while (pulseQueue.TryDequeue(out result)) { if (!result.isEmpty()) { string json = jsonSerializer.Serialize(result); Logger.Debug("Unsaved pulse: " + json); } } }
private static void InitializeAsync() { if (System.Net.ServicePointManager.SecurityProtocol != 0) { // If the value is not set to 0 (SystemDefault), disable old protocols and make sure TLS 1.3, 1.2, 1.1 are enabled System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3; System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Tls; System.Net.ServicePointManager.SecurityProtocol |= (SecurityProtocolType)12288 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; } //System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)0; // SystemDefault, we don't use this since it's supported only since .NET 4.7 //Updater.RenameTest(); //Updater.SignatureVerificationTest(); try { // Delete existing log file to save space Logger.Delete(); } catch { } Logger.Info(string.Format("Initializing Code::Stats v{0}", Constants.PluginVersion)); try { currentPulse = new Pulse(); Logger.Info("Initialing settings form..."); // Settings Form _settingsForm = new CodeStats.Forms.SettingsForm(); _settingsForm.ConfigSaved += SettingsFormOnConfigSaved; Logger.Info("Initialized settings form"); // it takes 5 seconds to get here from Initializing Code::Stats message... // Load config file _CodeStatsConfigFile = new ConfigFile(); GetSettings(true); Logger.Debug("Loaded config"); LoadExtensionMapping(); // Check for updates Task.Run(() => { try { string latest = Constants.LatestPluginVersion(); if (Constants.PluginVersion != latest && !String.IsNullOrWhiteSpace(latest)) { MessageBox.Show("There is Code::Stats plugin update available!\nDownload it from Plugin Admin (if already available there) or GitHub.\nYour version: " + Constants.PluginVersion + "\nLatest: " + latest, "Code::Stats"); } } catch { } }); if (string.IsNullOrEmpty(ApiKey)) { Stats = false; // Disable stats reporting for this session/launch PromptApiKey(); // Prompt for API token if not already set } // setup timer to process queued pulses pulseProcessor_tokensource = new CancellationTokenSource(); pulseProcessor_httpClientHandler = new HttpClientHandler(); pulseProcessor_httpClientHandler.Proxy = GetProxy(); proxyChangePending = false; pulseProcessor_client = new HttpClient(pulseProcessor_httpClientHandler); timer.Interval = pulseFrequency; timer.Elapsed += ProcessPulses; timer.Start(); if (Stats) { ReportStats(); } Logger.Info(string.Format("Finished initializing Code::Stats v{0}", Constants.PluginVersion)); } catch (Exception ex) { Logger.Error("Error Initializing Code::Stats", ex); } }
private static Task ProcessPulses(CancellationTokenSource tokenSource) { return(Task.Run(async() => { if (pulseQueue != null && ((currentPulse != null && !currentPulse.isEmpty()) || !pulseQueue.IsEmpty) && EnoughTimePassed(DateTime.Now)) { if (currentPulse != null && !currentPulse.isEmpty()) { pulseQueue.Enqueue(currentPulse); currentPulse = new Pulse(); currentCount = 0; } if (String.IsNullOrWhiteSpace(ApiKey)) { Logger.Debug("No API token - cannot pulse!"); return; } if (proxyChangePending) { pulseProcessor_httpClientHandler = new HttpClientHandler(); pulseProcessor_httpClientHandler.Proxy = GetProxy(); pulseProcessor_client = new HttpClient(pulseProcessor_httpClientHandler); proxyChangePending = false; } //var client = new WebClient { Proxy = CodeStatsPackage.GetProxy() }; var jsonSerializer = new JavaScriptSerializer(); string URL; bool usesCustomEndpoint = false; if (String.IsNullOrWhiteSpace(ApiUrl)) { URL = Constants.ApiMyPulsesEndpoint; } else { URL = ApiUrl; usesCustomEndpoint = true; } /*client.Headers["User-Agent"] = Constants.PluginUserAgent; * client.Headers["Content-Type"] = "application/json"; * client.Headers["Accept"] = "* /*"; * client.Headers["X-API-Token"] = ApiKey;*/ Pulse result; while (pulseQueue.TryDequeue(out result)) { if (!result.isEmpty()) { bool error = false; HttpResponseMessage response = null; // Try to pulse to API try { string json; var httpRequestMessage = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri(URL), Headers = { { "User-Agent", Constants.PluginUserAgent }, { "Accept", "*/*" }, { "X-API-Token", ApiKey } }, Content = new StringContent(json = jsonSerializer.Serialize(result), Encoding.UTF8, "application/json") }; Logger.Debug("Pulsing " + json); response = await pulseProcessor_client.SendAsync(httpRequestMessage, tokenSource.Token); response.EnsureSuccessStatusCode(); string JsonResult = await response.Content.ReadAsStringAsync(); _lastPulse = DateTime.Now; if (!JsonResult.Contains(@"""ok""") && !JsonResult.Contains(@"success")) { error = true; Logger.Error(@"Error pulsing, response does not contain ""ok"" or ""success"": " + JsonResult); } } catch (TaskCanceledException) { pulseQueue.Enqueue(result); // requeue current pulse return; } catch (HttpRequestException ex) { error = true; if (response != null && response.StatusCode != 0) { if ((int)response.StatusCode == 403) { Logger.Error("Could not pulse (error 403). Please make sure you entered a valid API token in Code::Stats settings.", ex); if (!_hasAlreadyShownInvalidApiTokenMessage) // we want to inform user only once, and if they do not provide the token, let's not bomb him with error each time after they type something { _hasAlreadyShownInvalidApiTokenMessage = true; MessageBox.Show("Could not pulse. Please make sure you entered a valid API token in Code::Stats settings.\nAll recorded XP from this session will be lost if you do not provide the correct API token!", "Code::Stats – error 403", MessageBoxButtons.OK, MessageBoxIcon.Error); PromptApiKey(); } } else if ((int)response.StatusCode == 404 && usesCustomEndpoint) { Logger.Error("Could not pulse (error 404). The entered custom endpoint (" + URL + ") is invalid. ", ex); MessageBox.Show("Could not pulse. Invalid API endpoint URL. Please make sure you entered a valid API URL in Code::Stats settings or delete the value altogether to restore the default.\nAll recorded XP from this session will be lost if you do not provide the correct API URL path!", "Code::Stats – error 404", MessageBoxButtons.OK, MessageBoxIcon.Error); _settingsForm.FocusTxtAPIURL(); _settingsForm.ShowAPIURLTooltip(); SettingsPopup(); _settingsForm.ShowAPIURLTooltip(); } else { Logger.Error("Could not pulse - HTTP error " + (int)response.StatusCode + ". Server response: " + response.Content.ReadAsStringAsync().Result, ex); } } else { // response==null - no http status code available Logger.Error("Could not pulse. Are you behind a proxy? Try setting a proxy in Code::Stats settings with format https://user:pass@host:port. Exception Traceback", ex); } } catch (Exception ex) { error = true; Logger.Error("Error pulsing. Exception Traceback", ex); } if (error) { pulseQueue.Enqueue(result); // Requeue, since we failed to pulse return; } } if (tokenSource.Token.IsCancellationRequested) { tokenSource.Token.ThrowIfCancellationRequested(); } } } }, tokenSource.Token)); }
private static void InitializeAsync() { try { // Delete existing log file to save space Logger.Delete(); } catch { } try { Logger.Info(string.Format("Initializing Code::Stats v{0}", Constants.PluginVersion)); //Logger.Debug(Assembly.GetExecutingAssembly().GetManifestResourceNames().ToString()); //Logger.Debug(Assembly.GetExecutingAssembly().GetName().Name); Assembly _assembly; StreamReader _textStreamReader; Stream _stream; string extensionMappingJson; try { var client = new WebClient { Proxy = CodeStatsPackage.GetProxy() }; client.Headers[HttpRequestHeader.UserAgent] = Constants.PluginUserAgent; try { extensionMappingJson = client.DownloadString("https://raw.githubusercontent.com/p0358/notepadpp-CodeStats/master/CodeStats/Resources/extension_mapping.json"); if (!extensionMappingJson.Trim().StartsWith("{") || !extensionMappingJson.Trim().EndsWith("}")) { extensionMappingJson = string.Empty; } } catch (Exception ex) { extensionMappingJson = string.Empty; Logger.Error("Exception when trying to download latest extension mappings, using local ones instead", ex); } } catch { extensionMappingJson = string.Empty; } if (String.IsNullOrWhiteSpace(extensionMappingJson)) { // Load precompiled/included extension mapping _assembly = Assembly.GetExecutingAssembly(); _stream = _assembly.GetManifestResourceStream("CodeStats.Resources.extension_mapping.json"); _textStreamReader = new StreamReader(_stream); extensionMappingJson = _textStreamReader.ReadToEnd(); } Logger.Debug("Extension mapping JSON: " + extensionMappingJson); //var json = "{\"id\":\"13\", \"value\": true}"; var serializer = new JavaScriptSerializer(); //var table = serializer.Deserialize<dynamic>(json); //Dictionary<string, string> values = serializer.Deserialize<Dictionary<string, string>>(json); extensionMapping = serializer.Deserialize <Dictionary <string, string> >(extensionMappingJson); //Logger.Debug(values["id"]); //Logger.Debug(table["value"]); } catch (Exception ex) { Logger.Error("Error loading extension mappings!", ex); } try { // Settings Form _settingsForm = new CodeStats.Forms.SettingsForm(); _settingsForm.ConfigSaved += SettingsFormOnConfigSaved; // Load config file _CodeStatsConfigFile = new ConfigFile(); GetSettings(); try { // Check for updates string latest = Constants.LatestPluginVersion(); if (Constants.PluginVersion != latest && !String.IsNullOrWhiteSpace(latest)) { MessageBox.Show("There is Code::Stats plugin update available!\nDownload it from Plugin Manager or GitHub.\nYour version: " + Constants.PluginVersion + "\nLatest: " + latest, "Code::Stats"); } } catch { } currentPulse = new Pulse(); if (string.IsNullOrEmpty(ApiKey)) { Stats = false; // Disable stats reporting for this session/launch PromptApiKey(); // Prompt for API token if not already set } // setup timer to process queued pulses timer.Interval = pulseFrequency; timer.Elapsed += ProcessPulses; timer.Start(); if (Stats) { ReportStats(); } Logger.Info(string.Format("Finished initializing Code::Stats v{0}", Constants.PluginVersion)); } catch (Exception ex) { Logger.Error("Error Initializing Code::Stats", ex); } }
private static void ProcessPulses() { if (pulseQueue != null && ((currentPulse != null && !currentPulse.isEmpty()) || !pulseQueue.IsEmpty) && EnoughTimePassed(DateTime.Now)) { if (currentPulse != null && !currentPulse.isEmpty()) { pulseQueue.Enqueue(currentPulse); currentPulse = new Pulse(); currentCount = 0; } if (String.IsNullOrWhiteSpace(ApiKey)) { Logger.Debug("No API token - cannot pulse!"); return; } var client = new WebClient { Proxy = CodeStatsPackage.GetProxy() }; var jsonSerializer = new JavaScriptSerializer(); string URL; if (String.IsNullOrWhiteSpace(_CodeStatsConfigFile.ApiUrl)) { URL = Constants.ApiMyPulsesEndpoint; } else { URL = _CodeStatsConfigFile.ApiUrl; } client.Headers[HttpRequestHeader.UserAgent] = Constants.PluginUserAgent; client.Headers[HttpRequestHeader.ContentType] = "application/json"; client.Headers[HttpRequestHeader.Accept] = "*/*"; client.Headers["X-API-Token"] = ApiKey; Pulse result; while (pulseQueue.TryDequeue(out result)) { if (!result.isEmpty()) { bool error = false; // Try to pulse to API try { string json = jsonSerializer.Serialize(result); Logger.Debug("Pulsing " + json); string HtmlResult = client.UploadString(URL, json); _lastPulse = DateTime.Now; if (!HtmlResult.Contains(@"""ok""") && !HtmlResult.Contains(@"success")) { error = true; Logger.Error(@"Error pulsing, response does not contain ""ok"" or ""success"": " + HtmlResult); } } catch (WebException ex) { error = true; if (ex.Status == WebExceptionStatus.ProtocolError) { var response = ex.Response as HttpWebResponse; if (response != null && (int)response.StatusCode == 403) { if (!_shownInvalidApiTokenMessage) // we want to inform user only once, and if he does not provide the token, let's not bomb him with error each time after he types something { MessageBox.Show("Could not pulse. Please make sure you entered a valid API token in Code::Stats settings.", "Code::Stats - error 403", MessageBoxButtons.OK, MessageBoxIcon.Error); _shownInvalidApiTokenMessage = true; } Logger.Error("Could not pulse. Please make sure you entered a valid API token in Code::Stats settings.", ex); } else { // response==null - no http status code available Logger.Error("Could not pulse. Are you behind a proxy? Try setting a proxy in Code::Stats settings with format https://user:pass@host:port. Exception Traceback", ex); } } else { Logger.Error("Could not pulse. Are you behind a proxy? Try setting a proxy in Code::Stats settings with format https://user:pass@host:port. Exception Traceback", ex); } } catch (Exception ex) { error = true; Logger.Error("Error pulsing. Exception Traceback", ex); } if (error) { pulseQueue.Enqueue(result); // Requeue, since we failed to pulse return; } } } } UpdateStatusbar(); }
private static void InitializeAsync() { if (System.Net.ServicePointManager.SecurityProtocol != 0) { // If the value is not set to 0 (SystemDefault), disable old protocols and make sure TLS 1.3, 1.2, 1.1 are enabled System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3; System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Tls; System.Net.ServicePointManager.SecurityProtocol |= (SecurityProtocolType)12288 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; } try { // Delete existing log file to save space Logger.Delete(); } catch { } Logger.Info($"Initializing Code::Stats v{Constants.PluginVersion}"); try { currentPulse = new Pulse(); Logger.Info("Initialing settings form..."); // Settings Form _settingsForm = new CodeStats.Forms.SettingsForm(); _settingsForm.OnSettingsSaved += SettingsFormOnConfigSaved; Logger.Info("Initialized settings form"); // it takes 5 seconds to get here from Initializing Code::Stats message... // Load config file codeStatsSettings = CodeStatsSettingsProvider.GetSingleton(); GetSettings(true); Logger.Debug("Loaded config"); LoadExtensionMapping(); if (String.IsNullOrEmpty(codeStatsSettings.ApiKey)) { PromptApiKey(); // Prompt for API token if not already set } // setup timer to process queued pulses pulseProcessor_tokensource = new CancellationTokenSource(); pulseProcessor_httpClientHandler = new HttpClientHandler { Proxy = GetProxy() }; proxyChangePending = false; pulseProcessor_client = new HttpClient(pulseProcessor_httpClientHandler); timer.Interval = pulseFrequency; timer.Elapsed += ProcessPulses; timer.Start(); Logger.Info($"Finished initializing Code::Stats v{Constants.PluginVersion}"); } catch (Exception ex) { Logger.Error("Error Initializing Code::Stats", ex); } }