From 2d06095447b972c8c7239277428e2c67c8b7ca86 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Mon, 25 Feb 2013 22:43:04 -0500 Subject: plugin security fixes and other abstractions --- .../BaseApplicationHost.cs | 295 +++++++++++ .../MediaBrowser.Common.Implementations.csproj | 5 + .../ScheduledTasks/ScheduledTaskWorker.cs | 538 +++++++++++++++++++++ .../ScheduledTasks/TaskManager.cs | 202 ++------ .../ScheduledTasks/Tasks/DeleteCacheFileTask.cs | 29 +- .../ScheduledTasks/Tasks/DeleteLogFileTask.cs | 29 +- .../ScheduledTasks/Tasks/ReloadLoggerTask.cs | 36 +- .../ScheduledTasks/Tasks/SystemUpdateTask.cs | 36 +- .../Serialization/JsonSerializer.cs | 16 +- .../packages.config | 1 + 10 files changed, 971 insertions(+), 216 deletions(-) create mode 100644 MediaBrowser.Common.Implementations/BaseApplicationHost.cs create mode 100644 MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs (limited to 'MediaBrowser.Common.Implementations') diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs new file mode 100644 index 0000000000..c5af5059f3 --- /dev/null +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -0,0 +1,295 @@ +using System.IO; +using System.Linq; +using System.Reflection; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using SimpleInjector; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace MediaBrowser.Common.Implementations +{ + public abstract class BaseApplicationHost : IDisposable + { + /// + /// Gets or sets the logger. + /// + /// The logger. + public ILogger Logger { get; protected set; } + + /// + /// The container + /// + protected readonly Container Container = new Container(); + + /// + /// Gets assemblies that failed to load + /// + public List FailedAssemblies { get; protected set; } + + /// + /// Gets all types within all running assemblies + /// + /// All types. + public Type[] AllTypes { get; protected set; } + + /// + /// Gets all concrete types. + /// + /// All concrete types. + public Type[] AllConcreteTypes { get; protected set; } + + /// + /// The disposable parts + /// + protected readonly List DisposableParts = new List(); + + /// + /// The _protobuf serializer initialized + /// + private bool _protobufSerializerInitialized; + /// + /// The _protobuf serializer sync lock + /// + private object _protobufSerializerSyncLock = new object(); + /// + /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection + /// + private IProtobufSerializer _protobufSerializer; + /// + /// Gets the protobuf serializer. + /// + /// The protobuf serializer. + protected IProtobufSerializer ProtobufSerializer + { + get + { + // Lazy load + LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => Serialization.ProtobufSerializer.Create(AllTypes)); + return _protobufSerializer; + } + private set + { + _protobufSerializer = value; + _protobufSerializerInitialized = value != null; + } + } + + /// + /// Initializes a new instance of the class. + /// + protected BaseApplicationHost() + { + FailedAssemblies = new List(); + } + + /// + /// Gets the composable part assemblies. + /// + /// IEnumerable{Assembly}. + protected abstract IEnumerable GetComposablePartAssemblies(); + + /// + /// Discovers the types. + /// + protected void DiscoverTypes() + { + FailedAssemblies.Clear(); + + AllTypes = GetComposablePartAssemblies().SelectMany(GetTypes).ToArray(); + + AllConcreteTypes = AllTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray(); + } + + /// + /// Gets a list of types within an assembly + /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference + /// + /// The assembly. + /// IEnumerable{Type}. + /// assembly + protected IEnumerable GetTypes(Assembly assembly) + { + if (assembly == null) + { + throw new ArgumentNullException("assembly"); + } + + try + { + return assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + // If it fails we can still get a list of the Types it was able to resolve + return ex.Types.Where(t => t != null); + } + } + + /// + /// Creates an instance of type and resolves all constructor dependancies + /// + /// The type. + /// System.Object. + public object CreateInstance(Type type) + { + try + { + return Container.GetInstance(type); + } + catch + { + Logger.Error("Error creating {0}", type.Name); + + throw; + } + } + + /// + /// Registers the specified obj. + /// + /// + /// The obj. + protected void RegisterSingleInstance(T obj) + where T : class + { + Container.RegisterSingle(obj); + } + + /// + /// Registers the specified func. + /// + /// + /// The func. + protected void Register(Func func) + where T : class + { + Container.Register(func); + } + + /// + /// Registers the single instance. + /// + /// + /// The func. + protected void RegisterSingleInstance(Func func) + where T : class + { + Container.RegisterSingle(func); + } + + /// + /// Resolves this instance. + /// + /// + /// ``0. + public T Resolve() + { + return (T)Container.GetRegistration(typeof(T), true).GetInstance(); + } + + /// + /// Resolves this instance. + /// + /// + /// ``0. + public T TryResolve() + { + var result = Container.GetRegistration(typeof(T), false); + + if (result == null) + { + return default(T); + } + return (T)result.GetInstance(); + } + + /// + /// Registers the specified service type. + /// + /// Type of the service. + /// Type of the concrete. + protected void Register(Type serviceType, Type implementation) + { + Container.Register(serviceType, implementation); + } + + /// + /// Loads the assembly. + /// + /// The file. + /// Assembly. + protected Assembly LoadAssembly(string file) + { + try + { + return Assembly.Load(File.ReadAllBytes((file))); + } + catch (Exception ex) + { + FailedAssemblies.Add(file); + Logger.ErrorException("Error loading assembly {0}", ex, file); + return null; + } + } + + /// + /// Gets the exports. + /// + /// + /// if set to true [manage liftime]. + /// IEnumerable{``0}. + public IEnumerable GetExports(bool manageLiftime = true) + { + var currentType = typeof(T); + + Logger.Info("Composing instances of " + currentType.Name); + + var parts = AllConcreteTypes.Where(currentType.IsAssignableFrom).Select(CreateInstance).Cast().ToArray(); + + if (manageLiftime) + { + DisposableParts.AddRange(parts.OfType()); + } + + return parts; + } + + /// + /// Gets the current application version + /// + /// The application version. + public Version ApplicationVersion + { + get + { + return GetType().Assembly.GetName().Version; + } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool dispose) + { + foreach (var part in DisposableParts) + { + part.Dispose(); + } + + var b = Container.GetCurrentRegistrations(); + + DisposableParts.Clear(); + } + } +} diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index 736a15d423..acd798d733 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -41,6 +41,9 @@ ..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll + + ..\packages\SimpleInjector.2.0.0-beta5\lib\net40-client\SimpleInjector.dll + @@ -54,8 +57,10 @@ Properties\SharedVersion.cs + + diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs new file mode 100644 index 0000000000..7fa30f4ae0 --- /dev/null +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -0,0 +1,538 @@ +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Tasks; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Implementations.ScheduledTasks +{ + /// + /// Class ScheduledTaskWorker + /// + public class ScheduledTaskWorker : IScheduledTaskWorker + { + /// + /// Gets or sets the scheduled task. + /// + /// The scheduled task. + public IScheduledTask ScheduledTask { get; private set; } + + /// + /// Gets or sets the json serializer. + /// + /// The json serializer. + private IJsonSerializer JsonSerializer { get; set; } + + /// + /// Gets or sets the application paths. + /// + /// The application paths. + private IApplicationPaths ApplicationPaths { get; set; } + + /// + /// Gets the logger. + /// + /// The logger. + private ILogger Logger { get; set; } + + /// + /// Gets the task manager. + /// + /// The task manager. + private ITaskManager TaskManager { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The scheduled task. + /// The application paths. + /// The task manager. + /// The json serializer. + /// The logger. + public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger) + { + ScheduledTask = scheduledTask; + ApplicationPaths = applicationPaths; + TaskManager = taskManager; + JsonSerializer = jsonSerializer; + Logger = logger; + } + + /// + /// The _last execution result + /// + private TaskResult _lastExecutionResult; + /// + /// The _last execution resultinitialized + /// + private bool _lastExecutionResultinitialized; + /// + /// The _last execution result sync lock + /// + private object _lastExecutionResultSyncLock = new object(); + /// + /// Gets the last execution result. + /// + /// The last execution result. + public TaskResult LastExecutionResult + { + get + { + LazyInitializer.EnsureInitialized(ref _lastExecutionResult, ref _lastExecutionResultinitialized, ref _lastExecutionResultSyncLock, () => + { + try + { + return JsonSerializer.DeserializeFromFile(GetHistoryFilePath()); + } + catch (IOException) + { + // File doesn't exist. No biggie + return null; + } + }); + + return _lastExecutionResult; + } + private set + { + _lastExecutionResult = value; + + _lastExecutionResultinitialized = value != null; + } + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ScheduledTask.Name; } + } + + /// + /// Gets the description. + /// + /// The description. + public string Description + { + get { return ScheduledTask.Description; } + } + + /// + /// Gets the category. + /// + /// The category. + public string Category + { + get { return ScheduledTask.Category; } + } + + /// + /// Gets the current cancellation token + /// + /// The current cancellation token source. + private CancellationTokenSource CurrentCancellationTokenSource { get; set; } + + /// + /// Gets or sets the current execution start time. + /// + /// The current execution start time. + private DateTime CurrentExecutionStartTime { get; set; } + + /// + /// Gets the state. + /// + /// The state. + public TaskState State + { + get + { + if (CurrentCancellationTokenSource != null) + { + return CurrentCancellationTokenSource.IsCancellationRequested + ? TaskState.Cancelling + : TaskState.Running; + } + + return TaskState.Idle; + } + } + + /// + /// Gets the current progress. + /// + /// The current progress. + public double? CurrentProgress { get; private set; } + + /// + /// The _triggers + /// + private IEnumerable _triggers; + /// + /// The _triggers initialized + /// + private bool _triggersInitialized; + /// + /// The _triggers sync lock + /// + private object _triggersSyncLock = new object(); + /// + /// Gets the triggers that define when the task will run + /// + /// The triggers. + /// value + public IEnumerable Triggers + { + get + { + LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, () => LoadTriggers()); + + return _triggers; + } + set + { + if (value == null) + { + throw new ArgumentNullException("value"); + } + + // Cleanup current triggers + if (_triggers != null) + { + DisposeTriggers(); + } + + _triggers = value.ToList(); + + _triggersInitialized = true; + + ReloadTriggerEvents(false); + + SaveTriggers(_triggers); + } + } + + /// + /// The _id + /// + private Guid? _id; + + /// + /// Gets the unique id. + /// + /// The unique id. + public Guid Id + { + get + { + if (!_id.HasValue) + { + _id = ScheduledTask.GetType().FullName.GetMD5(); + } + + return _id.Value; + } + } + + /// + /// Reloads the trigger events. + /// + /// if set to true [is application startup]. + private void ReloadTriggerEvents(bool isApplicationStartup) + { + foreach (var trigger in Triggers) + { + trigger.Stop(); + + trigger.Triggered -= trigger_Triggered; + trigger.Triggered += trigger_Triggered; + trigger.Start(isApplicationStartup); + } + } + + /// + /// Handles the Triggered event of the trigger control. + /// + /// The source of the event. + /// The instance containing the event data. + async void trigger_Triggered(object sender, EventArgs e) + { + var trigger = (ITaskTrigger)sender; + + Logger.Info("{0} fired for task: {1}", trigger.GetType().Name, Name); + + trigger.Stop(); + + TaskManager.QueueScheduledTask(ScheduledTask); + + await Task.Delay(1000).ConfigureAwait(false); + + trigger.Start(false); + } + + /// + /// Executes the task + /// + /// Task. + /// Cannot execute a Task that is already running + public async Task Execute() + { + // Cancel the current execution, if any + if (CurrentCancellationTokenSource != null) + { + throw new InvalidOperationException("Cannot execute a Task that is already running"); + } + + CurrentCancellationTokenSource = new CancellationTokenSource(); + + Logger.Info("Executing {0}", Name); + + var progress = new Progress(); + + progress.ProgressChanged += progress_ProgressChanged; + + TaskCompletionStatus status; + CurrentExecutionStartTime = DateTime.UtcNow; + + //Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskBeginExecute", Name); + + try + { + await System.Threading.Tasks.Task.Run(async () => await ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress).ConfigureAwait(false)).ConfigureAwait(false); + + status = TaskCompletionStatus.Completed; + } + catch (OperationCanceledException) + { + status = TaskCompletionStatus.Cancelled; + } + catch (Exception ex) + { + Logger.ErrorException("Error", ex); + + status = TaskCompletionStatus.Failed; + } + + var startTime = CurrentExecutionStartTime; + var endTime = DateTime.UtcNow; + + //Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskEndExecute", LastExecutionResult); + + progress.ProgressChanged -= progress_ProgressChanged; + CurrentCancellationTokenSource.Dispose(); + CurrentCancellationTokenSource = null; + CurrentProgress = null; + + OnTaskCompleted(startTime, endTime, status); + } + + /// + /// Progress_s the progress changed. + /// + /// The sender. + /// The e. + void progress_ProgressChanged(object sender, double e) + { + CurrentProgress = e; + } + + /// + /// Stops the task if it is currently executing + /// + /// Cannot cancel a Task unless it is in the Running state. + public void Cancel() + { + if (State != TaskState.Running) + { + throw new InvalidOperationException("Cannot cancel a Task unless it is in the Running state."); + } + + CancelIfRunning(); + } + + /// + /// Cancels if running. + /// + public void CancelIfRunning() + { + if (State == TaskState.Running) + { + Logger.Info("Attempting to cancel Scheduled Task {0}", Name); + CurrentCancellationTokenSource.Cancel(); + } + } + + /// + /// The _scheduled tasks configuration directory + /// + private string _scheduledTasksConfigurationDirectory; + /// + /// Gets the scheduled tasks configuration directory. + /// + /// The scheduled tasks configuration directory. + private string ScheduledTasksConfigurationDirectory + { + get + { + if (_scheduledTasksConfigurationDirectory == null) + { + _scheduledTasksConfigurationDirectory = Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); + + if (!Directory.Exists(_scheduledTasksConfigurationDirectory)) + { + Directory.CreateDirectory(_scheduledTasksConfigurationDirectory); + } + } + return _scheduledTasksConfigurationDirectory; + } + } + + /// + /// The _scheduled tasks data directory + /// + private string _scheduledTasksDataDirectory; + /// + /// Gets the scheduled tasks data directory. + /// + /// The scheduled tasks data directory. + private string ScheduledTasksDataDirectory + { + get + { + if (_scheduledTasksDataDirectory == null) + { + _scheduledTasksDataDirectory = Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks"); + + if (!Directory.Exists(_scheduledTasksDataDirectory)) + { + Directory.CreateDirectory(_scheduledTasksDataDirectory); + } + } + return _scheduledTasksDataDirectory; + } + } + + /// + /// Gets the history file path. + /// + /// The history file path. + private string GetHistoryFilePath() + { + return Path.Combine(ScheduledTasksDataDirectory, Id + ".js"); + } + + /// + /// Gets the configuration file path. + /// + /// System.String. + private string GetConfigurationFilePath() + { + return Path.Combine(ScheduledTasksConfigurationDirectory, Id + ".js"); + } + + /// + /// Loads the triggers. + /// + /// IEnumerable{BaseTaskTrigger}. + private IEnumerable LoadTriggers() + { + try + { + return JsonSerializer.DeserializeFromFile>(GetConfigurationFilePath()) + .Select(ScheduledTaskHelpers.GetTrigger) + .ToList(); + } + catch (IOException) + { + // File doesn't exist. No biggie. Return defaults. + return ScheduledTask.GetDefaultTriggers(); + } + } + + /// + /// Saves the triggers. + /// + /// The triggers. + private void SaveTriggers(IEnumerable triggers) + { + JsonSerializer.SerializeToFile(triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), GetConfigurationFilePath()); + } + + /// + /// Called when [task completed]. + /// + /// The start time. + /// The end time. + /// The status. + private void OnTaskCompleted(DateTime startTime, DateTime endTime, TaskCompletionStatus status) + { + var elapsedTime = endTime - startTime; + + Logger.Info("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); + + var result = new TaskResult + { + StartTimeUtc = startTime, + EndTimeUtc = endTime, + Status = status, + Name = Name, + Id = Id + }; + + JsonSerializer.SerializeToFile(result, GetHistoryFilePath()); + + LastExecutionResult = result; + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + DisposeTriggers(); + + if (State == TaskState.Running) + { + OnTaskCompleted(CurrentExecutionStartTime, DateTime.UtcNow, TaskCompletionStatus.Aborted); + } + + if (CurrentCancellationTokenSource != null) + { + CurrentCancellationTokenSource.Dispose(); + } + } + } + + /// + /// Disposes each trigger + /// + private void DisposeTriggers() + { + foreach (var trigger in Triggers) + { + trigger.Triggered -= trigger_Triggered; + trigger.Stop(); + } + } + } +} diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs index c6eca29d1c..4b61492d66 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs @@ -5,7 +5,6 @@ using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using System; using System.Collections.Generic; -using System.IO; using System.Linq; namespace MediaBrowser.Common.Implementations.ScheduledTasks @@ -19,7 +18,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks /// Gets the list of Scheduled Tasks /// /// The scheduled tasks. - public IScheduledTask[] ScheduledTasks { get; private set; } + public IScheduledTaskWorker[] ScheduledTasks { get; private set; } /// /// The _task queue @@ -27,19 +26,22 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks private readonly List _taskQueue = new List(); /// - /// The _logger + /// Gets or sets the json serializer. /// - private readonly ILogger _logger; + /// The json serializer. + private IJsonSerializer JsonSerializer { get; set; } /// - /// The _application paths + /// Gets or sets the application paths. /// - private readonly IApplicationPaths _applicationPaths; + /// The application paths. + private IApplicationPaths ApplicationPaths { get; set; } /// - /// The _json serializer + /// Gets the logger. /// - private readonly IJsonSerializer _jsonSerializer; + /// The logger. + private ILogger Logger { get; set; } /// /// Initializes a new instance of the class. @@ -50,24 +52,11 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks /// kernel public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger) { - if (applicationPaths == null) - { - throw new ArgumentException("applicationPaths"); - } - if (jsonSerializer == null) - { - throw new ArgumentException("jsonSerializer"); - } - if (logger == null) - { - throw new ArgumentException("logger"); - } + ApplicationPaths = applicationPaths; + JsonSerializer = jsonSerializer; + Logger = logger; - _applicationPaths = applicationPaths; - _jsonSerializer = jsonSerializer; - _logger = logger; - - ScheduledTasks = new IScheduledTask[] {}; + ScheduledTasks = new IScheduledTaskWorker[] { }; } /// @@ -77,7 +66,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks public void CancelIfRunningAndQueue() where T : IScheduledTask { - ScheduledTasks.OfType().First().CancelIfRunning(); + ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)).CancelIfRunning(); QueueScheduledTask(); } @@ -88,7 +77,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks public void QueueScheduledTask() where T : IScheduledTask { - var scheduledTask = ScheduledTasks.OfType().First(); + var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)); QueueScheduledTask(scheduledTask); } @@ -99,27 +88,36 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks /// The task. public void QueueScheduledTask(IScheduledTask task) { - var type = task.GetType(); + var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == task.GetType()); - var scheduledTask = ScheduledTasks.First(t => t.GetType() == type); + QueueScheduledTask(scheduledTask); + } + + /// + /// Queues the scheduled task. + /// + /// The task. + private void QueueScheduledTask(IScheduledTaskWorker task) + { + var type = task.GetType(); lock (_taskQueue) { // If it's idle just execute immediately - if (scheduledTask.State == TaskState.Idle) + if (task.State == TaskState.Idle) { - scheduledTask.Execute(); + task.Execute(); return; } if (!_taskQueue.Contains(type)) { - _logger.Info("Queueing task {0}", type.Name); + Logger.Info("Queueing task {0}", type.Name); _taskQueue.Add(type); } else { - _logger.Info("Task already queued: {0}", type.Name); + Logger.Info("Task already queued: {0}", type.Name); } } } @@ -157,147 +155,11 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks { var myTasks = ScheduledTasks.ToList(); - myTasks.AddRange(tasks); + myTasks.AddRange(tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger))); ScheduledTasks = myTasks.ToArray(); } - /// - /// The _scheduled tasks configuration directory - /// - private string _scheduledTasksConfigurationDirectory; - /// - /// Gets the scheduled tasks configuration directory. - /// - /// The scheduled tasks configuration directory. - private string ScheduledTasksConfigurationDirectory - { - get - { - if (_scheduledTasksConfigurationDirectory == null) - { - _scheduledTasksConfigurationDirectory = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); - - if (!Directory.Exists(_scheduledTasksConfigurationDirectory)) - { - Directory.CreateDirectory(_scheduledTasksConfigurationDirectory); - } - } - return _scheduledTasksConfigurationDirectory; - } - } - - /// - /// The _scheduled tasks data directory - /// - private string _scheduledTasksDataDirectory; - /// - /// Gets the scheduled tasks data directory. - /// - /// The scheduled tasks data directory. - private string ScheduledTasksDataDirectory - { - get - { - if (_scheduledTasksDataDirectory == null) - { - _scheduledTasksDataDirectory = Path.Combine(_applicationPaths.DataPath, "ScheduledTasks"); - - if (!Directory.Exists(_scheduledTasksDataDirectory)) - { - Directory.CreateDirectory(_scheduledTasksDataDirectory); - } - } - return _scheduledTasksDataDirectory; - } - } - - /// - /// Gets the history file path. - /// - /// The history file path. - private string GetHistoryFilePath(IScheduledTask task) - { - return Path.Combine(ScheduledTasksDataDirectory, task.Id + ".js"); - } - - /// - /// Gets the configuration file path. - /// - /// The task. - /// System.String. - private string GetConfigurationFilePath(IScheduledTask task) - { - return Path.Combine(ScheduledTasksConfigurationDirectory, task.Id + ".js"); - } - - /// - /// Called when [task completed]. - /// - /// The task. - /// The start time. - /// The end time. - /// The status. - public void OnTaskCompleted(IScheduledTask task, DateTime startTime, DateTime endTime, TaskCompletionStatus status) - { - var elapsedTime = endTime - startTime; - - _logger.Info("{0} {1} after {2} minute(s) and {3} seconds", task.Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); - - var result = new TaskResult - { - StartTimeUtc = startTime, - EndTimeUtc = endTime, - Status = status, - Name = task.Name, - Id = task.Id - }; - - _jsonSerializer.SerializeToFile(result, GetHistoryFilePath(task)); - - //task.LastExecutionResult = result; - } - - /// - /// Gets the last execution result. - /// - /// The task. - /// TaskResult. - public TaskResult GetLastExecutionResult(IScheduledTask task) - { - return _jsonSerializer.DeserializeFromFile(GetHistoryFilePath(task)); - } - - /// - /// Loads the triggers. - /// - /// The task. - /// IEnumerable{BaseTaskTrigger}. - public IEnumerable LoadTriggers(IScheduledTask task) - { - try - { - return _jsonSerializer.DeserializeFromFile>(GetConfigurationFilePath(task)) - .Select(ScheduledTaskHelpers.GetTrigger) - .ToList(); - } - catch (IOException) - { - // File doesn't exist. No biggie. Return defaults. - return task.GetDefaultTriggers(); - } - } - - /// - /// Saves the triggers. - /// - /// The task. - /// The triggers. - public void SaveTriggers(IScheduledTask task, IEnumerable triggers) - { - _jsonSerializer.SerializeToFile(triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), GetConfigurationFilePath(task)); - } - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index 2ef0566587..a9c82c3578 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -13,24 +13,35 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// /// Deletes old cache files /// - public class DeleteCacheFileTask : BaseScheduledTask + public class DeleteCacheFileTask : IScheduledTask { + /// + /// Gets or sets the kernel. + /// + /// The kernel. + private IKernel Kernel { get; set; } + /// + /// Gets or sets the logger. + /// + /// The logger. + private ILogger Logger { get; set; } + /// /// Initializes a new instance of the class. /// /// The kernel. - /// The task manager. /// The logger. - public DeleteCacheFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger) - : base(kernel, taskManager, logger) + public DeleteCacheFileTask(IKernel kernel, ILogger logger) { + Kernel = kernel; + Logger = logger; } /// /// Creates the triggers that define when the task will run /// /// IEnumerable{BaseTaskTrigger}. - public override IEnumerable GetDefaultTriggers() + public IEnumerable GetDefaultTriggers() { var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am @@ -43,7 +54,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// The cancellation token. /// The progress. /// Task. - protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + public Task Execute(CancellationToken cancellationToken, IProgress progress) { return Task.Run(() => { @@ -90,7 +101,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the name of the task /// /// The name. - public override string Name + public string Name { get { return "Cache file cleanup"; } } @@ -99,7 +110,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the description. /// /// The description. - public override string Description + public string Description { get { return "Deletes cache files no longer needed by the system"; } } @@ -108,7 +119,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the category. /// /// The category. - public override string Category + public string Category { get { diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs index dd00a71489..a7d8a68a04 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -13,24 +13,35 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// /// Deletes old log files /// - public class DeleteLogFileTask : BaseScheduledTask + public class DeleteLogFileTask : IScheduledTask { + /// + /// Gets or sets the kernel. + /// + /// The kernel. + private IKernel Kernel { get; set; } + /// + /// Gets or sets the logger. + /// + /// The logger. + private ILogger Logger { get; set; } + /// /// Initializes a new instance of the class. /// /// The kernel. - /// The task manager. /// The logger. - public DeleteLogFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger) - : base(kernel, taskManager, logger) + public DeleteLogFileTask(IKernel kernel, ILogger logger) { + Kernel = kernel; + Logger = logger; } /// /// Creates the triggers that define when the task will run /// /// IEnumerable{BaseTaskTrigger}. - public override IEnumerable GetDefaultTriggers() + public IEnumerable GetDefaultTriggers() { var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am @@ -43,7 +54,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// The cancellation token. /// The progress. /// Task. - protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + public Task Execute(CancellationToken cancellationToken, IProgress progress) { return Task.Run(() => { @@ -78,7 +89,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the name of the task /// /// The name. - public override string Name + public string Name { get { return "Log file cleanup"; } } @@ -87,7 +98,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the description. /// /// The description. - public override string Description + public string Description { get { return string.Format("Deletes log files that are more than {0} days old.", Kernel.Configuration.LogFileRetentionDays); } } @@ -96,7 +107,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the category. /// /// The category. - public override string Category + public string Category { get { diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs index 79c633c765..ac06f111a2 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs @@ -11,24 +11,35 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// /// Class ReloadLoggerFileTask /// - public class ReloadLoggerFileTask : BaseScheduledTask + public class ReloadLoggerFileTask : IScheduledTask { + /// + /// Gets or sets the kernel. + /// + /// The kernel. + private IKernel Kernel { get; set; } + /// + /// Gets or sets the logger. + /// + /// The logger. + private ILogger Logger { get; set; } + /// /// Initializes a new instance of the class. /// /// The kernel. - /// The task manager. /// The logger. - public ReloadLoggerFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger) - : base(kernel, taskManager, logger) + public ReloadLoggerFileTask(IKernel kernel, ILogger logger) { + Kernel = kernel; + Logger = logger; } /// /// Gets the default triggers. /// /// IEnumerable{BaseTaskTrigger}. - public override IEnumerable GetDefaultTriggers() + public IEnumerable GetDefaultTriggers() { var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(0) }; //12am @@ -41,7 +52,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// The cancellation token. /// The progress. /// Task. - protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + public Task Execute(CancellationToken cancellationToken, IProgress progress) { cancellationToken.ThrowIfCancellationRequested(); @@ -54,7 +65,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the name. /// /// The name. - public override string Name + public string Name { get { return "Start new log file"; } } @@ -63,9 +74,18 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the description. /// /// The description. - public override string Description + public string Description { get { return "Moves logging to a new file to help reduce log file sizes."; } } + + /// + /// Gets the category. + /// + /// The category. + public string Category + { + get { return "Application"; } + } } } diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs index a101ad3dd4..18fcdbbda9 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs @@ -11,31 +11,42 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// /// Plugin Update Task /// - public class SystemUpdateTask : BaseScheduledTask + public class SystemUpdateTask : IScheduledTask { /// /// The _app host /// private readonly IApplicationHost _appHost; + /// + /// Gets or sets the kernel. + /// + /// The kernel. + private IKernel Kernel { get; set; } + /// + /// Gets or sets the logger. + /// + /// The logger. + private ILogger Logger { get; set; } + /// /// Initializes a new instance of the class. /// /// The app host. - /// The task manager. /// The kernel. /// The logger. - public SystemUpdateTask(IApplicationHost appHost, ITaskManager taskManager, IKernel kernel, ILogger logger) - : base(kernel, taskManager, logger) + public SystemUpdateTask(IApplicationHost appHost, IKernel kernel, ILogger logger) { _appHost = appHost; + Kernel = kernel; + Logger = logger; } /// /// Creates the triggers that define when the task will run /// /// IEnumerable{BaseTaskTrigger}. - public override IEnumerable GetDefaultTriggers() + public IEnumerable GetDefaultTriggers() { return new ITaskTrigger[] { @@ -52,7 +63,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// The cancellation token. /// The progress. /// Task. - protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + public async Task Execute(CancellationToken cancellationToken, IProgress progress) { if (!_appHost.CanSelfUpdate) return; @@ -105,7 +116,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the name of the task /// /// The name. - public override string Name + public string Name { get { return "Check for application updates"; } } @@ -114,9 +125,18 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Gets the description. /// /// The description. - public override string Description + public string Description { get { return "Downloads and installs application updates."; } } + + /// + /// Gets the category. + /// + /// The category. + public string Category + { + get { return "Application"; } + } } } diff --git a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs index bc8935a86c..4a6b9255c1 100644 --- a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs +++ b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs @@ -17,12 +17,10 @@ namespace MediaBrowser.Common.Implementations.Serialization /// /// Serializes to stream. /// - /// /// The obj. /// The stream. /// obj - public void SerializeToStream(T obj, Stream stream) - where T : class + public void SerializeToStream(object obj, Stream stream) { if (obj == null) { @@ -40,12 +38,10 @@ namespace MediaBrowser.Common.Implementations.Serialization /// /// Serializes to file. /// - /// /// The obj. /// The file. /// obj - public void SerializeToFile(T obj, string file) - where T : class + public void SerializeToFile(object obj, string file) { if (obj == null) { @@ -200,12 +196,10 @@ namespace MediaBrowser.Common.Implementations.Serialization /// /// Serializes to string. /// - /// /// The obj. /// System.String. /// obj - public string SerializeToString(T obj) - where T : class + public string SerializeToString(object obj) { if (obj == null) { @@ -218,12 +212,10 @@ namespace MediaBrowser.Common.Implementations.Serialization /// /// Serializes to bytes. /// - /// /// The obj. /// System.Byte[][]. /// obj - public byte[] SerializeToBytes(T obj) - where T : class + public byte[] SerializeToBytes(object obj) { if (obj == null) { diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index 14eb42cace..63fd0052fc 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -2,4 +2,5 @@ + \ No newline at end of file -- cgit v1.2.3