diff --git a/MPF.Library/Utilities/DumpEnvironment.cs b/MPF.Library/Utilities/DumpEnvironment.cs index ba70d826..ba6e892a 100644 --- a/MPF.Library/Utilities/DumpEnvironment.cs +++ b/MPF.Library/Utilities/DumpEnvironment.cs @@ -74,7 +74,7 @@ namespace MPF.Utilities /// /// Queue of items that need to be logged /// - private readonly ConcurrentQueue outputQueue = new ConcurrentQueue(); + private ProcessingQueue outputQueue; /// /// Event handler for data returned from a process @@ -87,20 +87,9 @@ namespace MPF.Utilities /// /// Process the outputs in the queue /// - private void ProcessOutputs() + private void ProcessOutputs(string nextOutput) { - while (true) - { - // Nothing in the queue means we get to idle - if (outputQueue.Count == 0) - continue; - - // Get the next item from the queue - if (!outputQueue.TryDequeue(out string nextOutput)) - continue; - - ReportStatus.Invoke(this, nextOutput); - } + ReportStatus.Invoke(this, nextOutput); } #endregion @@ -396,7 +385,7 @@ namespace MPF.Utilities // Invoke output processing, if needed if (!Options.ToolsInSeparateWindow) { - Task.Run(() => ProcessOutputs()); + outputQueue = new ProcessingQueue(ProcessOutputs); Parameters.ReportStatus += OutputToLog; } @@ -411,9 +400,12 @@ namespace MPF.Utilities result = await Task.Run(() => ExecuteAdditionalTools()); progress?.Report(result); - // Remove evet habdler if needed + // Remove event handler if needed if (!Options.ToolsInSeparateWindow) + { + outputQueue.Dispose(); Parameters.ReportStatus -= OutputToLog; + } return result; } diff --git a/MPF.Library/Utilities/ProcessingQueue.cs b/MPF.Library/Utilities/ProcessingQueue.cs index 83edca3b..bfbcf92d 100644 --- a/MPF.Library/Utilities/ProcessingQueue.cs +++ b/MPF.Library/Utilities/ProcessingQueue.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace MPF.Utilities { - internal class ProcessingQueue + public class ProcessingQueue : IDisposable { /// /// Internal queue to hold data to process @@ -16,11 +16,33 @@ namespace MPF.Utilities /// private readonly Action CustomProcessing; + /// + /// Internal processing task for dequeueing + /// + private readonly Task ProcessingTask; + public ProcessingQueue(Action customProcessing) { this.InternalQueue = new ConcurrentQueue(); this.CustomProcessing = customProcessing; - Task.Run(() => ProcessQueue()); + this.ProcessingTask = Task.Run(() => ProcessQueue()); + } + + /// + /// Dispose the current instance + /// + public void Dispose() + { + this.ProcessingTask.Dispose(); + } + + /// + /// Enqueue a new item for processing + /// + /// + public void Enqueue(T item) + { + this.InternalQueue.Enqueue(item); } /// diff --git a/MPF/UserControls/LogOutput.xaml.cs b/MPF/UserControls/LogOutput.xaml.cs index a79689f8..67114f2a 100644 --- a/MPF/UserControls/LogOutput.xaml.cs +++ b/MPF/UserControls/LogOutput.xaml.cs @@ -1,14 +1,13 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; +using MPF.Utilities; namespace MPF.UserControls { @@ -27,7 +26,7 @@ namespace MPF.UserControls /// /// Queue of items that need to be logged /// - private readonly ConcurrentQueue logQueue; + private readonly ProcessingQueue logQueue; /// /// List of Matchers for progress tracking @@ -58,8 +57,7 @@ namespace MPF.UserControls AddAaruMatchers(); AddDiscImageCreatorMatchers(); - logQueue = new ConcurrentQueue(); - Task.Run(() => ProcessLogLines()); + logQueue = new ProcessingQueue(ProcessLogLine); } #region Matching @@ -370,77 +368,67 @@ namespace MPF.UserControls /// /// Process the log lines in the queue /// - private void ProcessLogLines() + /// LogLine item to process + private void ProcessLogLine(LogLine nextLogLine) { - while (true) + // Null text gets ignored + string nextText = Dispatcher.Invoke(() => nextLogLine.Text); + if (nextText == null) + return; + + try { - // Nothing in the queue means we get to idle - if (logQueue.Count == 0) - continue; + // Get last line + lastLine = lastLine ?? GetLastLine(); - // Get the next item from the queue - if (!logQueue.TryDequeue(out LogLine nextLogLine)) - continue; - - // Null text gets ignored - string nextText = Dispatcher.Invoke(() => nextLogLine.Text); - if (nextText == null) - continue; - - try + // Always append if there's no previous line + if (lastLine == null) { - // Get last line - lastLine = lastLine ?? GetLastLine(); + AppendToTextBox(nextLogLine); + lastUsedMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText) == true); + } + // Return always means overwrite + else if (nextText.StartsWith("\r")) + { + ReplaceLastLine(nextLogLine); + } + // If we have a cached matcher and we match + else if (lastUsedMatcher?.Matches(nextText) == true) + { + ReplaceLastLine(nextLogLine); + } + else + { + // Get the first matching Matcher + var firstMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText) == true); + if (firstMatcher.HasValue) + { + string lastText = Dispatcher.Invoke(() => { return lastLine.Text; }); + if (firstMatcher.Value.Matches(lastText)) + ReplaceLastLine(nextLogLine); + else if (string.IsNullOrWhiteSpace(lastText)) + ReplaceLastLine(nextLogLine); + else + AppendToTextBox(nextLogLine); - // Always append if there's no previous line - if (lastLine == null) - { - AppendToTextBox(nextLogLine); - lastUsedMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText) == true); - } - // Return always means overwrite - else if (nextText.StartsWith("\r")) - { - ReplaceLastLine(nextLogLine); - } - // If we have a cached matcher and we match - else if (lastUsedMatcher?.Matches(nextText) == true) - { - ReplaceLastLine(nextLogLine); + // Cache the last used Matcher + lastUsedMatcher = firstMatcher; } + // Default case for all other text else { - // Get the first matching Matcher - var firstMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText) == true); - if (firstMatcher.HasValue) - { - string lastText = Dispatcher.Invoke(() => { return lastLine.Text; }); - if (firstMatcher.Value.Matches(lastText)) - ReplaceLastLine(nextLogLine); - else if (string.IsNullOrWhiteSpace(lastText)) - ReplaceLastLine(nextLogLine); - else - AppendToTextBox(nextLogLine); - - // Cache the last used Matcher - lastUsedMatcher = firstMatcher; - } - // Default case for all other text - else - { - AppendToTextBox(nextLogLine); - lastUsedMatcher = null; - } + AppendToTextBox(nextLogLine); + lastUsedMatcher = null; } + } - // Update the bar if needed - ProcessStringForProgressBar(nextText, lastUsedMatcher); - } - catch (Exception ex) - { - // In the event that something fails horribly, we want to log - AppendToTextBox(new LogLine(ex.ToString(), LogLevel.ERROR)); - } + // Update the bar if needed + ProcessStringForProgressBar(nextText, lastUsedMatcher); + } + catch (Exception ex) + { + // In the event that something fails horribly, we want to log + AppendToTextBox(new LogLine(ex.ToString(), LogLevel.ERROR)); } }