diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs
index 16aafafb0e..206f5bf7b7 100644
--- a/MediaBrowser.Api/DisplayPreferencesService.cs
+++ b/MediaBrowser.Api/DisplayPreferencesService.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Serialization;
using ServiceStack;
@@ -79,14 +78,6 @@ namespace MediaBrowser.Api
{
var result = _displayPreferencesManager.GetDisplayPreferences(request.Id, request.UserId, request.Client);
- if (result == null)
- {
- result = new DisplayPreferences
- {
- Id = request.Id
- };
- }
-
return ToOptimizedSerializedResultUsingCache(result);
}
diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
index c143635bfa..0d61c2ce12 100644
--- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
+++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
using System.Collections.Generic;
@@ -11,7 +12,7 @@ namespace MediaBrowser.Api.ScheduledTasks
///
/// Class ScheduledTasksWebSocketListener
///
- public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener, object>
+ public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState>
{
///
/// Gets or sets the task manager.
@@ -37,6 +38,26 @@ namespace MediaBrowser.Api.ScheduledTasks
: base(logger)
{
TaskManager = taskManager;
+
+ TaskManager.TaskExecuting += TaskManager_TaskExecuting;
+ TaskManager.TaskCompleted += TaskManager_TaskCompleted;
+ }
+
+ void TaskManager_TaskCompleted(object sender, TaskCompletionEventArgs e)
+ {
+ SendData(true);
+ e.Task.TaskProgress -= Argument_TaskProgress;
+ }
+
+ void TaskManager_TaskExecuting(object sender, GenericEventArgs e)
+ {
+ SendData(true);
+ e.Argument.TaskProgress += Argument_TaskProgress;
+ }
+
+ void Argument_TaskProgress(object sender, GenericEventArgs e)
+ {
+ SendData(false);
}
///
@@ -44,12 +65,20 @@ namespace MediaBrowser.Api.ScheduledTasks
///
/// The state.
/// Task{IEnumerable{TaskInfo}}.
- protected override Task> GetDataToSend(object state)
+ protected override Task> GetDataToSend(WebSocketListenerState state)
{
return Task.FromResult(TaskManager.ScheduledTasks
.OrderBy(i => i.Name)
.Select(ScheduledTaskHelpers.GetTaskInfo)
.Where(i => !i.IsHidden));
}
+
+ protected override bool SendOnTimer
+ {
+ get
+ {
+ return false;
+ }
+ }
}
}
diff --git a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs
index 7fbea2f401..46dabb0420 100644
--- a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs
+++ b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs
@@ -133,7 +133,7 @@ namespace MediaBrowser.Api.WebSocket
///
/// Class LogFileWebSocketState
///
- public class LogFileWebSocketState
+ public class LogFileWebSocketState : WebSocketListenerState
{
///
/// Gets or sets the last log file path.
diff --git a/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs
index 721d8976b2..a16ea863f0 100644
--- a/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.Api.WebSocket
///
/// Class SessionInfoWebSocketListener
///
- class SessionInfoWebSocketListener : BasePeriodicWebSocketListener, object>
+ class SessionInfoWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState>
{
///
/// Gets the name.
@@ -43,7 +43,7 @@ namespace MediaBrowser.Api.WebSocket
///
/// The state.
/// Task{SystemInfo}.
- protected override Task> GetDataToSend(object state)
+ protected override Task> GetDataToSend(WebSocketListenerState state)
{
return Task.FromResult(_sessionManager.Sessions.Where(i => i.IsActive).Select(_sessionManager.GetSessionInfoDto));
}
diff --git a/MediaBrowser.Api/WebSocket/SystemInfoWebSocketListener.cs b/MediaBrowser.Api/WebSocket/SystemInfoWebSocketListener.cs
index 62e642c927..2940bcef06 100644
--- a/MediaBrowser.Api/WebSocket/SystemInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/WebSocket/SystemInfoWebSocketListener.cs
@@ -9,7 +9,7 @@ namespace MediaBrowser.Api.WebSocket
///
/// Class SystemInfoWebSocketListener
///
- public class SystemInfoWebSocketListener : BasePeriodicWebSocketListener
+ public class SystemInfoWebSocketListener : BasePeriodicWebSocketListener
{
///
/// Gets the name.
@@ -41,7 +41,7 @@ namespace MediaBrowser.Api.WebSocket
///
/// The state.
/// Task{SystemInfo}.
- protected override Task GetDataToSend(object state)
+ protected override Task GetDataToSend(WebSocketListenerState state)
{
return Task.FromResult(_appHost.GetSystemInfo());
}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index d7d0cb886e..68222d8436 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -1,6 +1,8 @@
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Tasks;
@@ -18,6 +20,8 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
///
public class ScheduledTaskWorker : IScheduledTaskWorker
{
+ public event EventHandler> TaskProgress;
+
///
/// Gets or sets the scheduled task.
///
@@ -344,13 +348,13 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
throw new InvalidOperationException("Cannot execute a Task that is already running");
}
+ var progress = new Progress();
+
CurrentCancellationTokenSource = new CancellationTokenSource();
Logger.Info("Executing {0}", Name);
- ((TaskManager)TaskManager).OnTaskExecuting(ScheduledTask);
-
- var progress = new Progress();
+ ((TaskManager)TaskManager).OnTaskExecuting(this);
progress.ProgressChanged += progress_ProgressChanged;
@@ -412,6 +416,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
void progress_ProgressChanged(object sender, double e)
{
CurrentProgress = e;
+
+ EventHelper.FireEventIfNotNull(TaskProgress, this, new GenericEventArgs
+ {
+ Argument = e
+
+ }, Logger);
}
///
@@ -546,7 +556,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
LastExecutionResult = result;
- ((TaskManager) TaskManager).OnTaskCompleted(ScheduledTask, result);
+ ((TaskManager)TaskManager).OnTaskCompleted(this, result);
}
///
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
index cead5de04b..5aec39b89c 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
@@ -17,8 +17,8 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
///
public class TaskManager : ITaskManager
{
- public event EventHandler TaskExecuting;
- public event EventHandler> TaskCompleted;
+ public event EventHandler> TaskExecuting;
+ public event EventHandler TaskCompleted;
///
/// Gets the list of Scheduled Tasks
@@ -125,7 +125,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
// If it's idle just execute immediately
if (task.State == TaskState.Idle)
{
- ((ScheduledTaskWorker)task).Execute();
+ Execute(task);
return;
}
@@ -149,7 +149,8 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
var myTasks = ScheduledTasks.ToList();
- myTasks.AddRange(tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger)));
+ var list = tasks.ToList();
+ myTasks.AddRange(list.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger)));
ScheduledTasks = myTasks.ToArray();
}
@@ -189,9 +190,13 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// Called when [task executing].
///
/// The task.
- internal void OnTaskExecuting(IScheduledTask task)
+ internal void OnTaskExecuting(IScheduledTaskWorker task)
{
- EventHelper.QueueEventIfNotNull(TaskExecuting, task, EventArgs.Empty, Logger);
+ EventHelper.QueueEventIfNotNull(TaskExecuting, this, new GenericEventArgs
+ {
+ Argument = task
+
+ }, Logger);
}
///
@@ -199,9 +204,15 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
///
/// The task.
/// The result.
- internal void OnTaskCompleted(IScheduledTask task, TaskResult result)
+ internal void OnTaskCompleted(IScheduledTaskWorker task, TaskResult result)
{
- EventHelper.QueueEventIfNotNull(TaskCompleted, task, new GenericEventArgs { Argument = result }, Logger);
+ EventHelper.QueueEventIfNotNull(TaskCompleted, task, new TaskCompletionEventArgs
+ {
+ Result = result,
+ Task = task
+
+ }, Logger);
+
ExecuteQueuedTasks();
}
@@ -219,7 +230,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
if (scheduledTask.State == TaskState.Idle)
{
- ((ScheduledTaskWorker)scheduledTask).Execute();
+ Execute(scheduledTask);
_taskQueue.Remove(type);
}
diff --git a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs
index 33d3f368b6..a2af3707be 100644
--- a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Common.Net
/// The type of the T return data type.
/// The type of the T state type.
public abstract class BasePeriodicWebSocketListener : IWebSocketListener, IDisposable
- where TStateType : class, new()
+ where TStateType : WebSocketListenerState, new()
where TReturnDataType : class
{
///
@@ -83,7 +83,15 @@ namespace MediaBrowser.Common.Net
}
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
+
+ protected virtual bool SendOnTimer
+ {
+ get
+ {
+ return true;
+ }
+ }
+
///
/// Starts sending messages over a web socket
///
@@ -99,9 +107,15 @@ namespace MediaBrowser.Common.Net
Logger.Info("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name);
- var timer = new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite);
+ var timer = SendOnTimer ?
+ new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) :
+ null;
- var state = new TStateType();
+ var state = new TStateType
+ {
+ IntervalMs = periodMs,
+ InitialDelayMs = dueTimeMs
+ };
var semaphore = new SemaphoreSlim(1, 1);
@@ -110,14 +124,17 @@ namespace MediaBrowser.Common.Net
ActiveConnections.Add(new Tuple(message.Connection, cancellationTokenSource, timer, state, semaphore));
}
- timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs));
+ if (timer != null)
+ {
+ timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs));
+ }
}
///
/// Timers the callback.
///
/// The state.
- private async void TimerCallback(object state)
+ private void TimerCallback(object state)
{
var connection = (IWebSocketConnection)state;
@@ -139,11 +156,50 @@ namespace MediaBrowser.Common.Net
return;
}
+ SendData(tuple);
+ }
+
+ protected void SendData(bool force)
+ {
+ List> tuples;
+
+ lock (ActiveConnections)
+ {
+ tuples = ActiveConnections
+ .Where(c =>
+ {
+ if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested)
+ {
+ var state = c.Item4;
+
+ if (force || (DateTime.UtcNow - state.DateLastSendUtc).TotalMilliseconds >= state.IntervalMs)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ })
+ .ToList();
+ }
+
+ foreach (var tuple in tuples)
+ {
+ SendData(tuple);
+ }
+ }
+
+ private async void SendData(Tuple tuple)
+ {
+ var connection = tuple.Item1;
+
try
{
await tuple.Item5.WaitAsync(tuple.Item2.Token).ConfigureAwait(false);
- var data = await GetDataToSend(tuple.Item4).ConfigureAwait(false);
+ var state = tuple.Item4;
+
+ var data = await GetDataToSend(state).ConfigureAwait(false);
if (data != null)
{
@@ -153,6 +209,8 @@ namespace MediaBrowser.Common.Net
Data = data
}, tuple.Item2.Token).ConfigureAwait(false);
+
+ state.DateLastSendUtc = DateTime.UtcNow;
}
tuple.Item5.Release();
@@ -196,13 +254,18 @@ namespace MediaBrowser.Common.Net
{
Logger.Info("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name);
- try
- {
- connection.Item3.Dispose();
- }
- catch (ObjectDisposedException)
+ var timer = connection.Item3;
+
+ if (timer != null)
{
+ try
+ {
+ timer.Dispose();
+ }
+ catch (ObjectDisposedException)
+ {
+ }
}
try
@@ -212,7 +275,7 @@ namespace MediaBrowser.Common.Net
}
catch (ObjectDisposedException)
{
-
+
}
try
@@ -223,7 +286,7 @@ namespace MediaBrowser.Common.Net
{
}
-
+
ActiveConnections.Remove(connection);
}
@@ -253,4 +316,11 @@ namespace MediaBrowser.Common.Net
Dispose(true);
}
}
+
+ public class WebSocketListenerState
+ {
+ public DateTime DateLastSendUtc { get; set; }
+ public long InitialDelayMs { get; set; }
+ public long IntervalMs { get; set; }
+ }
}
diff --git a/MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs b/MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs
index d0d363df76..f50bd9e76e 100644
--- a/MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs
+++ b/MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Events;
+using MediaBrowser.Model.Tasks;
using System;
using System.Collections.Generic;
@@ -9,6 +10,11 @@ namespace MediaBrowser.Common.ScheduledTasks
///
public interface IScheduledTaskWorker : IDisposable
{
+ ///
+ /// Occurs when [task progress].
+ ///
+ event EventHandler> TaskProgress;
+
///
/// Gets or sets the scheduled task.
///
diff --git a/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs b/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
index 38548801b2..01dc355c33 100644
--- a/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
+++ b/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Tasks;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -50,7 +49,7 @@ namespace MediaBrowser.Common.ScheduledTasks
void Cancel(IScheduledTaskWorker task);
Task Execute(IScheduledTaskWorker task);
- event EventHandler TaskExecuting;
- event EventHandler> TaskCompleted;
+ event EventHandler> TaskExecuting;
+ event EventHandler TaskCompleted;
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Common/ScheduledTasks/TaskCompletionEventArgs.cs b/MediaBrowser.Common/ScheduledTasks/TaskCompletionEventArgs.cs
index 8aab6b50d4..2974806d02 100644
--- a/MediaBrowser.Common/ScheduledTasks/TaskCompletionEventArgs.cs
+++ b/MediaBrowser.Common/ScheduledTasks/TaskCompletionEventArgs.cs
@@ -5,7 +5,7 @@ namespace MediaBrowser.Common.ScheduledTasks
{
public class TaskCompletionEventArgs : EventArgs
{
- public IScheduledTask Task { get; set; }
+ public IScheduledTaskWorker Task { get; set; }
public TaskResult Result { get; set; }
}
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index 19287b0cbb..a67d69f79f 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -85,13 +85,7 @@
-
-
-
- This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
+