/// <summary> /// Fetches console lines from storage. /// </summary> /// <param name="storage">Console data accessor</param> /// <param name="consoleId">Console identifier</param> /// <param name="start">Offset to read lines from</param> /// <remarks> /// On completion, <paramref name="start"/> is set to the end of the current batch, /// and can be used for next requests (or set to -1, if the job has finished processing). /// </remarks> private static IEnumerable <ConsoleLine> ReadLines(IConsoleStorage storage, ConsoleId consoleId, ref int start) { if (start < 0) { return(null); } var count = storage.GetLineCount(consoleId); var result = new List <ConsoleLine>(Math.Max(1, count - start)); if (count > start) { // has some new items to fetch Dictionary <string, ConsoleLine> progressBars = null; foreach (var entry in storage.GetLines(consoleId, start, count - 1)) { if (entry.ProgressValue.HasValue) { // aggregate progress value updates into single record if (progressBars != null) { ConsoleLine prev; if (progressBars.TryGetValue(entry.Message, out prev)) { prev.ProgressValue = entry.ProgressValue; prev.TextColor = entry.TextColor; continue; } } else { progressBars = new Dictionary <string, ConsoleLine>(); } progressBars.Add(entry.Message, entry); } result.Add(entry); } } if (count <= start || start == 0) { // no new items or initial load, check if the job is still performing var state = storage.GetState(consoleId); if (state == null) { // No state found for a job, probably it was deleted count = -2; } else { if (!string.Equals(state.Name, ProcessingState.StateName, StringComparison.OrdinalIgnoreCase) || !consoleId.Equals(new ConsoleId(consoleId.JobId, JobHelper.DeserializeDateTime(state.Data["StartedAt"])))) { // Job state has changed (either not Processing, or another Processing with different console id) count = -1; } } } start = count; return(result); }