using MediaBrowser.Common.IO; using MediaBrowser.Common.Kernel; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; namespace MediaBrowser.Api.WebSocket { /// /// Class ScheduledTasksWebSocketListener /// public class LogFileWebSocketListener : BasePeriodicWebSocketListener, LogFileWebSocketState> { /// /// Gets the name. /// /// The name. protected override string Name { get { return "LogFile"; } } /// /// The _kernel /// private readonly ILogManager _logManager; /// /// Initializes a new instance of the class. /// /// The logger. /// The log manager. public LogFileWebSocketListener(ILogger logger, ILogManager logManager) : base(logger) { _logManager = logManager; _logManager.LoggerLoaded += kernel_LoggerLoaded; } /// /// Gets the data to send. /// /// The state. /// IEnumerable{System.String}. protected override async Task> GetDataToSend(LogFileWebSocketState state) { if (!string.Equals(_logManager.LogFilePath, state.LastLogFilePath)) { state.LastLogFilePath = _logManager.LogFilePath; state.StartLine = 0; } var lines = await GetLogLines(state.LastLogFilePath, state.StartLine).ConfigureAwait(false); state.StartLine += lines.Count; return lines; } /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool dispose) { if (dispose) { _logManager.LoggerLoaded -= kernel_LoggerLoaded; } base.Dispose(dispose); } /// /// Handles the LoggerLoaded event of the kernel control. /// /// The source of the event. /// The instance containing the event data. void kernel_LoggerLoaded(object sender, EventArgs e) { // Reset the startline for each connection whenever the logger reloads lock (ActiveConnections) { foreach (var connection in ActiveConnections) { connection.Item4.StartLine = 0; } } } /// /// Gets the log lines. /// /// The log file path. /// The start line. /// Task{IEnumerable{System.String}}. internal static async Task> GetLogLines(string logFilePath, int startLine) { var lines = new List(); using (var fs = new FileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, true)) { using (var reader = new StreamReader(fs)) { while (!reader.EndOfStream) { lines.Add(await reader.ReadLineAsync().ConfigureAwait(false)); } } } if (startLine > 0) { lines = lines.Skip(startLine).ToList(); } return lines; } } /// /// Class LogFileWebSocketState /// public class LogFileWebSocketState { /// /// Gets or sets the last log file path. /// /// The last log file path. public string LastLogFilePath { get; set; } /// /// Gets or sets the start line. /// /// The start line. public int StartLine { get; set; } } }