From 8ce3e74e8112a94773df22827849bf274fc88198 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sun, 24 Feb 2013 16:53:54 -0500 Subject: More DI --- .../BaseApplicationPaths.cs | 304 +++++++++++++++++++ .../MediaBrowser.Common.Implementations.csproj | 87 ++++++ .../Properties/AssemblyInfo.cs | 31 ++ .../ScheduledTasks/TaskManager.cs | 322 +++++++++++++++++++++ .../ScheduledTasks/Tasks/DeleteCacheFileTask.cs | 119 ++++++++ .../ScheduledTasks/Tasks/DeleteLogFileTask.cs | 107 +++++++ .../ScheduledTasks/Tasks/ReloadLoggerTask.cs | 71 +++++ .../ScheduledTasks/Tasks/SystemUpdateTask.cs | 122 ++++++++ .../Serialization/JsonSerializer.cs | 240 +++++++++++++++ .../Serialization/ProtobufSerializer.cs | 158 ++++++++++ .../Serialization/XmlSerializer.cs | 140 +++++++++ .../packages.config | 5 + 12 files changed, 1706 insertions(+) create mode 100644 MediaBrowser.Common.Implementations/BaseApplicationPaths.cs create mode 100644 MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj create mode 100644 MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs create mode 100644 MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs create mode 100644 MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs create mode 100644 MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs create mode 100644 MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs create mode 100644 MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs create mode 100644 MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs create mode 100644 MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs create mode 100644 MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs create mode 100644 MediaBrowser.Common.Implementations/packages.config (limited to 'MediaBrowser.Common.Implementations') diff --git a/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs new file mode 100644 index 000000000..93478b22c --- /dev/null +++ b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs @@ -0,0 +1,304 @@ +using System; +using System.Configuration; +using System.IO; +using System.Reflection; + +namespace MediaBrowser.Common.Implementations +{ + /// + /// Provides a base class to hold common application paths used by both the Ui and Server. + /// This can be subclassed to add application-specific paths. + /// + public abstract class BaseApplicationPaths + { + /// + /// The _program data path + /// + private string _programDataPath; + /// + /// Gets the path to the program data folder + /// + /// The program data path. + public string ProgramDataPath + { + get + { + return _programDataPath ?? (_programDataPath = GetProgramDataPath()); + } + } + + /// + /// The _data directory + /// + private string _dataDirectory; + /// + /// Gets the folder path to the data directory + /// + /// The data directory. + public string DataPath + { + get + { + if (_dataDirectory == null) + { + _dataDirectory = Path.Combine(ProgramDataPath, "data"); + + if (!Directory.Exists(_dataDirectory)) + { + Directory.CreateDirectory(_dataDirectory); + } + } + + return _dataDirectory; + } + } + + /// + /// The _image cache path + /// + private string _imageCachePath; + /// + /// Gets the image cache path. + /// + /// The image cache path. + public string ImageCachePath + { + get + { + if (_imageCachePath == null) + { + _imageCachePath = Path.Combine(CachePath, "images"); + + if (!Directory.Exists(_imageCachePath)) + { + Directory.CreateDirectory(_imageCachePath); + } + } + + return _imageCachePath; + } + } + + /// + /// The _plugins path + /// + private string _pluginsPath; + /// + /// Gets the path to the plugin directory + /// + /// The plugins path. + public string PluginsPath + { + get + { + if (_pluginsPath == null) + { + _pluginsPath = Path.Combine(ProgramDataPath, "plugins"); + if (!Directory.Exists(_pluginsPath)) + { + Directory.CreateDirectory(_pluginsPath); + } + } + + return _pluginsPath; + } + } + + /// + /// The _plugin configurations path + /// + private string _pluginConfigurationsPath; + /// + /// Gets the path to the plugin configurations directory + /// + /// The plugin configurations path. + public string PluginConfigurationsPath + { + get + { + if (_pluginConfigurationsPath == null) + { + _pluginConfigurationsPath = Path.Combine(PluginsPath, "configurations"); + if (!Directory.Exists(_pluginConfigurationsPath)) + { + Directory.CreateDirectory(_pluginConfigurationsPath); + } + } + + return _pluginConfigurationsPath; + } + } + + private string _tempUpdatePath; + /// + /// Gets the path to where temporary update files will be stored + /// + /// The plugin configurations path. + public string TempUpdatePath + { + get + { + if (_tempUpdatePath == null) + { + _tempUpdatePath = Path.Combine(ProgramDataPath, "Updates"); + if (!Directory.Exists(_tempUpdatePath)) + { + Directory.CreateDirectory(_tempUpdatePath); + } + } + + return _tempUpdatePath; + } + } + + /// + /// The _log directory path + /// + private string _logDirectoryPath; + /// + /// Gets the path to the log directory + /// + /// The log directory path. + public string LogDirectoryPath + { + get + { + if (_logDirectoryPath == null) + { + _logDirectoryPath = Path.Combine(ProgramDataPath, "logs"); + if (!Directory.Exists(_logDirectoryPath)) + { + Directory.CreateDirectory(_logDirectoryPath); + } + } + return _logDirectoryPath; + } + } + + /// + /// The _configuration directory path + /// + private string _configurationDirectoryPath; + /// + /// Gets the path to the application configuration root directory + /// + /// The configuration directory path. + public string ConfigurationDirectoryPath + { + get + { + if (_configurationDirectoryPath == null) + { + _configurationDirectoryPath = Path.Combine(ProgramDataPath, "config"); + if (!Directory.Exists(_configurationDirectoryPath)) + { + Directory.CreateDirectory(_configurationDirectoryPath); + } + } + return _configurationDirectoryPath; + } + } + + /// + /// The _system configuration file path + /// + private string _systemConfigurationFilePath; + /// + /// Gets the path to the system configuration file + /// + /// The system configuration file path. + public string SystemConfigurationFilePath + { + get + { + return _systemConfigurationFilePath ?? (_systemConfigurationFilePath = Path.Combine(ConfigurationDirectoryPath, "system.xml")); + } + } + + /// + /// The _cache directory + /// + private string _cachePath; + /// + /// Gets the folder path to the cache directory + /// + /// The cache directory. + public string CachePath + { + get + { + if (_cachePath == null) + { + _cachePath = Path.Combine(ProgramDataPath, "cache"); + + if (!Directory.Exists(_cachePath)) + { + Directory.CreateDirectory(_cachePath); + } + } + + return _cachePath; + } + } + + /// + /// The _temp directory + /// + private string _tempDirectory; + /// + /// Gets the folder path to the temp directory within the cache folder + /// + /// The temp directory. + public string TempDirectory + { + get + { + if (_tempDirectory == null) + { + _tempDirectory = Path.Combine(CachePath, "temp"); + + if (!Directory.Exists(_tempDirectory)) + { + Directory.CreateDirectory(_tempDirectory); + } + } + + return _tempDirectory; + } + } + + /// + /// Gets the path to the application's ProgramDataFolder + /// + /// System.String. + public static string GetProgramDataPath() + { +#if DEBUG + string programDataPath = ConfigurationManager.AppSettings["DebugProgramDataPath"]; + +#else + string programDataPath = Path.Combine(ConfigurationManager.AppSettings["ReleaseProgramDataPath"], ConfigurationManager.AppSettings["ProgramDataFolderName"]); +#endif + + programDataPath = programDataPath.Replace("%CommonApplicationData%", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)); + + // If it's a relative path, e.g. "..\" + if (!Path.IsPathRooted(programDataPath)) + { + var path = Assembly.GetExecutingAssembly().Location; + path = Path.GetDirectoryName(path); + + programDataPath = Path.Combine(path, programDataPath); + + programDataPath = Path.GetFullPath(programDataPath); + } + + if (!Directory.Exists(programDataPath)) + { + Directory.CreateDirectory(programDataPath); + } + + return programDataPath; + } + } +} diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj new file mode 100644 index 000000000..d271db060 --- /dev/null +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -0,0 +1,87 @@ + + + + + Debug + AnyCPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D} + Library + Properties + MediaBrowser.Common.Implementations + MediaBrowser.Common.Implementations + v4.5 + 512 + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll + + + ..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll + + + + + + + + + + + + + Properties\SharedVersion.cs + + + + + + + + + + + + + + + {9142eefa-7570-41e1-bfcc-468bb571af2f} + MediaBrowser.Common + + + {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + MediaBrowser.Model + + + + + + + + + \ No newline at end of file diff --git a/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs b/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..f9c3e0bd1 --- /dev/null +++ b/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs @@ -0,0 +1,31 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MediaBrowser.Common.Implementations")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MediaBrowser.Common.Implementations")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fc7d85c6-0fe7-4db6-8158-54f7b18f17cd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs new file mode 100644 index 000000000..c6eca29d1 --- /dev/null +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs @@ -0,0 +1,322 @@ +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; + +namespace MediaBrowser.Common.Implementations.ScheduledTasks +{ + /// + /// Class TaskManager + /// + public class TaskManager : ITaskManager + { + /// + /// Gets the list of Scheduled Tasks + /// + /// The scheduled tasks. + public IScheduledTask[] ScheduledTasks { get; private set; } + + /// + /// The _task queue + /// + private readonly List _taskQueue = new List(); + + /// + /// The _logger + /// + private readonly ILogger _logger; + + /// + /// The _application paths + /// + private readonly IApplicationPaths _applicationPaths; + + /// + /// The _json serializer + /// + private readonly IJsonSerializer _jsonSerializer; + + /// + /// Initializes a new instance of the class. + /// + /// The application paths. + /// The json serializer. + /// The logger. + /// 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; + + ScheduledTasks = new IScheduledTask[] {}; + } + + /// + /// Cancels if running and queue. + /// + /// + public void CancelIfRunningAndQueue() + where T : IScheduledTask + { + ScheduledTasks.OfType().First().CancelIfRunning(); + QueueScheduledTask(); + } + + /// + /// Queues the scheduled task. + /// + /// + public void QueueScheduledTask() + where T : IScheduledTask + { + var scheduledTask = ScheduledTasks.OfType().First(); + + QueueScheduledTask(scheduledTask); + } + + /// + /// Queues the scheduled task. + /// + /// The task. + public void QueueScheduledTask(IScheduledTask task) + { + var type = task.GetType(); + + var scheduledTask = ScheduledTasks.First(t => t.GetType() == type); + + lock (_taskQueue) + { + // If it's idle just execute immediately + if (scheduledTask.State == TaskState.Idle) + { + scheduledTask.Execute(); + return; + } + + if (!_taskQueue.Contains(type)) + { + _logger.Info("Queueing task {0}", type.Name); + _taskQueue.Add(type); + } + else + { + _logger.Info("Task already queued: {0}", type.Name); + } + } + } + + /// + /// Called when [task completed]. + /// + /// The task. + public void OnTaskCompleted(IScheduledTask task) + { + // Execute queued tasks + lock (_taskQueue) + { + var copy = _taskQueue.ToList(); + + foreach (var type in copy) + { + var scheduledTask = ScheduledTasks.First(t => t.GetType() == type); + + if (scheduledTask.State == TaskState.Idle) + { + scheduledTask.Execute(); + + _taskQueue.Remove(type); + } + } + } + } + + /// + /// Adds the tasks. + /// + /// The tasks. + public void AddTasks(IEnumerable tasks) + { + var myTasks = ScheduledTasks.ToList(); + + myTasks.AddRange(tasks); + + 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. + /// + 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) + { + foreach (var task in ScheduledTasks) + { + task.Dispose(); + } + } + } +} diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs new file mode 100644 index 000000000..2ef056658 --- /dev/null +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -0,0 +1,119 @@ +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks +{ + /// + /// Deletes old cache files + /// + public class DeleteCacheFileTask : BaseScheduledTask + { + /// + /// 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) + { + } + + /// + /// Creates the triggers that define when the task will run + /// + /// IEnumerable{BaseTaskTrigger}. + public override IEnumerable GetDefaultTriggers() + { + var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am + + return new[] { trigger }; + } + + /// + /// Returns the task to be executed + /// + /// The cancellation token. + /// The progress. + /// Task. + protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + { + return Task.Run(() => + { + var minDateModified = DateTime.UtcNow.AddMonths(-2); + + DeleteCacheFilesFromDirectory(cancellationToken, Kernel.ApplicationPaths.CachePath, minDateModified, progress); + }); + } + + + /// + /// Deletes the cache files from directory with a last write time less than a given date + /// + /// The task cancellation token. + /// The directory. + /// The min date modified. + /// The progress. + private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress progress) + { + var filesToDelete = new DirectoryInfo(directory).EnumerateFileSystemInfos("*", SearchOption.AllDirectories) + .Where(f => !f.Attributes.HasFlag(FileAttributes.Directory) && f.LastWriteTimeUtc < minDateModified) + .ToList(); + + var index = 0; + + foreach (var file in filesToDelete) + { + double percent = index; + percent /= filesToDelete.Count; + + progress.Report(100 * percent); + + cancellationToken.ThrowIfCancellationRequested(); + + File.Delete(file.FullName); + + index++; + } + + progress.Report(100); + } + + /// + /// Gets the name of the task + /// + /// The name. + public override string Name + { + get { return "Cache file cleanup"; } + } + + /// + /// Gets the description. + /// + /// The description. + public override string Description + { + get { return "Deletes cache files no longer needed by the system"; } + } + + /// + /// Gets the category. + /// + /// The category. + public override string Category + { + get + { + return "Maintenance"; + } + } + } +} diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs new file mode 100644 index 000000000..dd00a7148 --- /dev/null +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -0,0 +1,107 @@ +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks +{ + /// + /// Deletes old log files + /// + public class DeleteLogFileTask : BaseScheduledTask + { + /// + /// 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) + { + } + + /// + /// Creates the triggers that define when the task will run + /// + /// IEnumerable{BaseTaskTrigger}. + public override IEnumerable GetDefaultTriggers() + { + var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am + + return new[] { trigger }; + } + + /// + /// Returns the task to be executed + /// + /// The cancellation token. + /// The progress. + /// Task. + protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + { + return Task.Run(() => + { + // Delete log files more than n days old + var minDateModified = DateTime.UtcNow.AddDays(-(Kernel.Configuration.LogFileRetentionDays)); + + var filesToDelete = new DirectoryInfo(Kernel.ApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories) + .Where(f => f.LastWriteTimeUtc < minDateModified) + .ToList(); + + var index = 0; + + foreach (var file in filesToDelete) + { + double percent = index; + percent /= filesToDelete.Count; + + progress.Report(100 * percent); + + cancellationToken.ThrowIfCancellationRequested(); + + File.Delete(file.FullName); + + index++; + } + + progress.Report(100); + }); + } + + /// + /// Gets the name of the task + /// + /// The name. + public override string Name + { + get { return "Log file cleanup"; } + } + + /// + /// Gets the description. + /// + /// The description. + public override string Description + { + get { return string.Format("Deletes log files that are more than {0} days old.", Kernel.Configuration.LogFileRetentionDays); } + } + + /// + /// Gets the category. + /// + /// The category. + public override string Category + { + get + { + return "Maintenance"; + } + } + } +} diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs new file mode 100644 index 000000000..79c633c76 --- /dev/null +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs @@ -0,0 +1,71 @@ +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks +{ + /// + /// Class ReloadLoggerFileTask + /// + public class ReloadLoggerFileTask : BaseScheduledTask + { + /// + /// 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) + { + } + + /// + /// Gets the default triggers. + /// + /// IEnumerable{BaseTaskTrigger}. + public override IEnumerable GetDefaultTriggers() + { + var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(0) }; //12am + + return new[] { trigger }; + } + + /// + /// Executes the internal. + /// + /// The cancellation token. + /// The progress. + /// Task. + protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + { + cancellationToken.ThrowIfCancellationRequested(); + + progress.Report(0); + + return Task.Run(() => Kernel.ReloadLogger()); + } + + /// + /// Gets the name. + /// + /// The name. + public override string Name + { + get { return "Start new log file"; } + } + + /// + /// Gets the description. + /// + /// The description. + public override string Description + { + get { return "Moves logging to a new file to help reduce log file sizes."; } + } + } +} diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs new file mode 100644 index 000000000..a101ad3dd --- /dev/null +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs @@ -0,0 +1,122 @@ +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks +{ + /// + /// Plugin Update Task + /// + public class SystemUpdateTask : BaseScheduledTask + { + /// + /// The _app host + /// + private readonly IApplicationHost _appHost; + + /// + /// 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) + { + _appHost = appHost; + } + + /// + /// Creates the triggers that define when the task will run + /// + /// IEnumerable{BaseTaskTrigger}. + public override IEnumerable GetDefaultTriggers() + { + return new ITaskTrigger[] { + + // 1am + new DailyTrigger { TimeOfDay = TimeSpan.FromHours(1) }, + + new IntervalTrigger { Interval = TimeSpan.FromHours(2)} + }; + } + + /// + /// Returns the task to be executed + /// + /// The cancellation token. + /// The progress. + /// Task. + protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + { + if (!_appHost.CanSelfUpdate) return; + + EventHandler innerProgressHandler = (sender, e) => progress.Report(e * .1); + + // Create a progress object for the update check + var innerProgress = new Progress(); + innerProgress.ProgressChanged += innerProgressHandler; + + var updateInfo = await _appHost.CheckForApplicationUpdate(cancellationToken, innerProgress).ConfigureAwait(false); + + // Release the event handler + innerProgress.ProgressChanged -= innerProgressHandler; + + progress.Report(10); + + if (!updateInfo.IsUpdateAvailable) + { + progress.Report(100); + return; + } + + cancellationToken.ThrowIfCancellationRequested(); + + if (Kernel.Configuration.EnableAutoUpdate) + { + Logger.Info("Update Revision {0} available. Updating...", updateInfo.AvailableVersion); + + innerProgressHandler = (sender, e) => progress.Report((e * .9) + .1); + + innerProgress = new Progress(); + innerProgress.ProgressChanged += innerProgressHandler; + + await _appHost.UpdateApplication(cancellationToken, innerProgress).ConfigureAwait(false); + + // Release the event handler + innerProgress.ProgressChanged -= innerProgressHandler; + + Kernel.OnApplicationUpdated(updateInfo.AvailableVersion); + } + else + { + Logger.Info("A new version of Media Browser is available."); + } + + progress.Report(100); + } + + /// + /// Gets the name of the task + /// + /// The name. + public override string Name + { + get { return "Check for application updates"; } + } + + /// + /// Gets the description. + /// + /// The description. + public override string Description + { + get { return "Downloads and installs application updates."; } + } + } +} diff --git a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs new file mode 100644 index 000000000..bc8935a86 --- /dev/null +++ b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs @@ -0,0 +1,240 @@ +using MediaBrowser.Model.Serialization; +using System; +using System.IO; + +namespace MediaBrowser.Common.Implementations.Serialization +{ + /// + /// Provides a wrapper around third party json serialization. + /// + public class JsonSerializer : IJsonSerializer + { + public JsonSerializer() + { + Configure(); + } + + /// + /// Serializes to stream. + /// + /// + /// The obj. + /// The stream. + /// obj + public void SerializeToStream(T obj, Stream stream) + where T : class + { + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + + if (stream == null) + { + throw new ArgumentNullException("stream"); + } + + ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream); + } + + /// + /// Serializes to file. + /// + /// + /// The obj. + /// The file. + /// obj + public void SerializeToFile(T obj, string file) + where T : class + { + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + + if (string.IsNullOrEmpty(file)) + { + throw new ArgumentNullException("file"); + } + + using (Stream stream = File.Open(file, FileMode.Create)) + { + SerializeToStream(obj, stream); + } + } + + /// + /// Deserializes from file. + /// + /// The type. + /// The file. + /// System.Object. + /// type + public object DeserializeFromFile(Type type, string file) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + if (string.IsNullOrEmpty(file)) + { + throw new ArgumentNullException("file"); + } + + using (Stream stream = File.OpenRead(file)) + { + return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream); + } + } + + /// + /// Deserializes from file. + /// + /// + /// The file. + /// ``0. + /// file + public T DeserializeFromFile(string file) + where T : class + { + if (string.IsNullOrEmpty(file)) + { + throw new ArgumentNullException("file"); + } + + using (Stream stream = File.OpenRead(file)) + { + return ServiceStack.Text.JsonSerializer.DeserializeFromStream(stream); + } + } + + /// + /// Deserializes from stream. + /// + /// + /// The stream. + /// ``0. + /// stream + public T DeserializeFromStream(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException("stream"); + } + + return ServiceStack.Text.JsonSerializer.DeserializeFromStream(stream); + } + + /// + /// Deserializes from string. + /// + /// + /// The text. + /// ``0. + /// text + public T DeserializeFromString(string text) + { + if (string.IsNullOrEmpty(text)) + { + throw new ArgumentNullException("text"); + } + + return ServiceStack.Text.JsonSerializer.DeserializeFromString(text); + } + + /// + /// Deserializes from stream. + /// + /// The stream. + /// The type. + /// System.Object. + /// stream + public object DeserializeFromStream(Stream stream, Type type) + { + if (stream == null) + { + throw new ArgumentNullException("stream"); + } + + if (type == null) + { + throw new ArgumentNullException("type"); + } + + return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream); + } + + /// + /// Configures this instance. + /// + private void Configure() + { + ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.JsonDateHandler.ISO8601; + ServiceStack.Text.JsConfig.ExcludeTypeInfo = true; + ServiceStack.Text.JsConfig.IncludeNullValues = false; + } + + /// + /// Deserializes from string. + /// + /// The json. + /// The type. + /// System.Object. + /// json + public object DeserializeFromString(string json, Type type) + { + if (string.IsNullOrEmpty(json)) + { + throw new ArgumentNullException("json"); + } + + if (type == null) + { + throw new ArgumentNullException("type"); + } + + return ServiceStack.Text.JsonSerializer.DeserializeFromString(json, type); + } + + /// + /// Serializes to string. + /// + /// + /// The obj. + /// System.String. + /// obj + public string SerializeToString(T obj) + where T : class + { + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + + return ServiceStack.Text.JsonSerializer.SerializeToString(obj, obj.GetType()); + } + + /// + /// Serializes to bytes. + /// + /// + /// The obj. + /// System.Byte[][]. + /// obj + public byte[] SerializeToBytes(T obj) + where T : class + { + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + + using (var stream = new MemoryStream()) + { + SerializeToStream(obj, stream); + return stream.ToArray(); + } + } + } +} diff --git a/MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs new file mode 100644 index 000000000..85325f3c1 --- /dev/null +++ b/MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs @@ -0,0 +1,158 @@ +using MediaBrowser.Model.Serialization; +using ProtoBuf; +using ProtoBuf.Meta; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Common.Implementations.Serialization +{ + /// + /// Creates a compiled protobuf serializer based on a set of assemblies + /// + public class ProtobufSerializer : IProtobufSerializer + { + /// + /// Gets or sets the type model. + /// + /// The type model. + private TypeModel TypeModel { get; set; } + + /// + /// Serializes to stream. + /// + /// The obj. + /// The stream. + /// obj + public void SerializeToStream(object obj, Stream stream) + { + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + if (stream == null) + { + throw new ArgumentNullException("stream"); + } + + TypeModel.Serialize(stream, obj); + } + + /// + /// Deserializes from stream. + /// + /// The stream. + /// The type. + /// System.Object. + /// stream + public object DeserializeFromStream(Stream stream, Type type) + { + if (stream == null) + { + throw new ArgumentNullException("stream"); + } + + return TypeModel.Deserialize(stream, null, type); + } + + /// + /// Deserializes from stream. + /// + /// + /// The stream. + /// ``0. + public T DeserializeFromStream(Stream stream) + where T : class + { + return DeserializeFromStream(stream, typeof(T)) as T; + } + + /// + /// Serializes to file. + /// + /// + /// The obj. + /// The file. + /// file + public void SerializeToFile(T obj, string file) + { + if (string.IsNullOrEmpty(file)) + { + throw new ArgumentNullException("file"); + } + + using (Stream stream = File.Open(file, FileMode.Create)) + { + SerializeToStream(obj, stream); + } + } + + /// + /// Deserializes from file. + /// + /// + /// The file. + /// ``0. + /// file + public T DeserializeFromFile(string file) + where T : class + { + if (string.IsNullOrEmpty(file)) + { + throw new ArgumentNullException("file"); + } + + using (Stream stream = File.OpenRead(file)) + { + return DeserializeFromStream(stream); + } + } + + /// + /// Serializes to bytes. + /// + /// + /// The obj. + /// System.Byte[][]. + /// obj + public byte[] SerializeToBytes(T obj) + where T : class + { + if (obj == null) + { + throw new ArgumentNullException("obj"); + } + + using (var stream = new MemoryStream()) + { + SerializeToStream(obj, stream); + return stream.ToArray(); + } + } + + /// + /// Creates the specified assemblies. + /// + /// DynamicProtobufSerializer. + /// assemblies + public static ProtobufSerializer Create(IEnumerable types) + { + if (types == null) + { + throw new ArgumentNullException("types"); + } + + var model = TypeModel.Create(); + var attributeType = typeof(ProtoContractAttribute); + + // Find all ProtoContracts in the current assembly + foreach (var type in types.Where(t => Attribute.IsDefined(t, attributeType))) + { + model.Add(type, true); + } + + return new ProtobufSerializer { TypeModel = model.Compile() }; + } + } +} diff --git a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs new file mode 100644 index 000000000..d01199f6f --- /dev/null +++ b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs @@ -0,0 +1,140 @@ +using MediaBrowser.Model.Serialization; +using System; +using System.IO; +using System.Xml; + +namespace MediaBrowser.Common.Implementations.Serialization +{ + /// + /// Provides a wrapper around third party xml serialization. + /// + public class XmlSerializer : IXmlSerializer + { + /// + /// Serializes to writer. + /// + /// The obj. + /// The writer. + private void SerializeToWriter(object obj, XmlTextWriter writer) + { + writer.Formatting = Formatting.Indented; + var netSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType()); + netSerializer.Serialize(writer, obj); + } + + /// + /// Deserializes from stream. + /// + /// + /// The stream. + /// ``0. + public T DeserializeFromStream(Stream stream) + { + using (var reader = new XmlTextReader(stream)) + { + var netSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); + + return (T)netSerializer.Deserialize(reader); + } + } + + /// + /// Deserializes from stream. + /// + /// The type. + /// The stream. + /// System.Object. + public object DeserializeFromStream(Type type, Stream stream) + { + using (var reader = new XmlTextReader(stream)) + { + var netSerializer = new System.Xml.Serialization.XmlSerializer(type); + + return netSerializer.Deserialize(reader); + } + } + + /// + /// Serializes to stream. + /// + /// The obj. + /// The stream. + public void SerializeToStream(object obj, Stream stream) + { + using (var writer = new XmlTextWriter(stream, null)) + { + SerializeToWriter(obj, writer); + } + } + + /// + /// Deserializes from file. + /// + /// + /// The file. + /// ``0. + public T DeserializeFromFile(string file) + { + using (var stream = File.OpenRead(file)) + { + return DeserializeFromStream(stream); + } + } + + /// + /// Serializes to file. + /// + /// The obj. + /// The file. + public void SerializeToFile(object obj, string file) + { + using (var stream = new FileStream(file, FileMode.Create)) + { + SerializeToStream(obj, stream); + } + } + + /// + /// Deserializes from file. + /// + /// The type. + /// The file. + /// System.Object. + public object DeserializeFromFile(Type type, string file) + { + using (var stream = File.OpenRead(file)) + { + return DeserializeFromStream(type, stream); + } + } + + /// + /// Deserializes from bytes. + /// + /// The type. + /// The buffer. + /// System.Object. + public object DeserializeFromBytes(Type type, byte[] buffer) + { + using (var stream = new MemoryStream(buffer)) + { + return DeserializeFromStream(type, stream); + } + } + + /// + /// Serializes to bytes. + /// + /// The obj. + /// System.Byte[][]. + public byte[] SerializeToBytes(object obj) + { + using (var stream = new MemoryStream()) + { + SerializeToStream(obj, stream); + + return stream.ToArray(); + } + } + } +} diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config new file mode 100644 index 000000000..14eb42cac --- /dev/null +++ b/MediaBrowser.Common.Implementations/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file -- cgit v1.2.3