aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Common.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Common.Implementations')
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs773
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationPaths.cs178
-rw-r--r--MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs328
-rw-r--r--MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs60
-rw-r--r--MediaBrowser.Common.Implementations/Cryptography/CryptographyProvider.cs30
-rw-r--r--MediaBrowser.Common.Implementations/Devices/DeviceId.cs109
-rw-r--r--MediaBrowser.Common.Implementations/HttpClientManager/HttpClientInfo.cs16
-rw-r--r--MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs936
-rw-r--r--MediaBrowser.Common.Implementations/IO/IsoManager.cs75
-rw-r--r--MediaBrowser.Common.Implementations/IO/ManagedFileSystem.cs705
-rw-r--r--MediaBrowser.Common.Implementations/IO/WindowsFileSystem.cs13
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj110
-rw-r--r--MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs385
-rw-r--r--MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs30
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/DailyTrigger.cs91
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/IntervalTrigger.cs112
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs781
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/StartupTrigger.cs67
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/SystemEventTrigger.cs84
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs361
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs217
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs140
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs113
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/WeeklyTrigger.cs116
-rw-r--r--MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs130
-rw-r--r--MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs269
26 files changed, 0 insertions, 6229 deletions
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
deleted file mode 100644
index ec96818aa..000000000
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ /dev/null
@@ -1,773 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Implementations.Devices;
-using MediaBrowser.Common.Implementations.IO;
-using MediaBrowser.Common.Implementations.ScheduledTasks;
-using MediaBrowser.Common.Implementations.Serialization;
-using MediaBrowser.Common.Implementations.Updates;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Plugins;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Common.Security;
-using MediaBrowser.Common.Updates;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Updates;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Implementations.Cryptography;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Common.Implementations
-{
- /// <summary>
- /// Class BaseApplicationHost
- /// </summary>
- /// <typeparam name="TApplicationPathsType">The type of the T application paths type.</typeparam>
- public abstract class BaseApplicationHost<TApplicationPathsType> : IApplicationHost
- where TApplicationPathsType : class, IApplicationPaths
- {
- /// <summary>
- /// Occurs when [has pending restart changed].
- /// </summary>
- public event EventHandler HasPendingRestartChanged;
-
- /// <summary>
- /// Occurs when [application updated].
- /// </summary>
- public event EventHandler<GenericEventArgs<PackageVersionInfo>> ApplicationUpdated;
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
- /// </summary>
- /// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value>
- public bool HasPendingRestart { get; private set; }
-
- /// <summary>
- /// Gets or sets the logger.
- /// </summary>
- /// <value>The logger.</value>
- protected ILogger Logger { get; private set; }
-
- /// <summary>
- /// Gets or sets the plugins.
- /// </summary>
- /// <value>The plugins.</value>
- public IPlugin[] Plugins { get; protected set; }
-
- /// <summary>
- /// Gets or sets the log manager.
- /// </summary>
- /// <value>The log manager.</value>
- public ILogManager LogManager { get; protected set; }
-
- /// <summary>
- /// Gets the application paths.
- /// </summary>
- /// <value>The application paths.</value>
- protected TApplicationPathsType ApplicationPaths { get; private set; }
-
- /// <summary>
- /// The json serializer
- /// </summary>
- public IJsonSerializer JsonSerializer { get; private set; }
-
- /// <summary>
- /// The _XML serializer
- /// </summary>
- protected readonly IXmlSerializer XmlSerializer;
-
- /// <summary>
- /// Gets assemblies that failed to load
- /// </summary>
- /// <value>The failed assemblies.</value>
- public List<string> FailedAssemblies { get; protected set; }
-
- /// <summary>
- /// Gets all concrete types.
- /// </summary>
- /// <value>All concrete types.</value>
- public Type[] AllConcreteTypes { get; protected set; }
-
- /// <summary>
- /// The disposable parts
- /// </summary>
- protected readonly List<IDisposable> DisposableParts = new List<IDisposable>();
-
- /// <summary>
- /// Gets a value indicating whether this instance is first run.
- /// </summary>
- /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
- public bool IsFirstRun { get; private set; }
-
- /// <summary>
- /// Gets the kernel.
- /// </summary>
- /// <value>The kernel.</value>
- protected ITaskManager TaskManager { get; private set; }
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- public IHttpClient HttpClient { get; private set; }
- /// <summary>
- /// Gets the network manager.
- /// </summary>
- /// <value>The network manager.</value>
- protected INetworkManager NetworkManager { get; private set; }
-
- /// <summary>
- /// Gets the configuration manager.
- /// </summary>
- /// <value>The configuration manager.</value>
- protected IConfigurationManager ConfigurationManager { get; private set; }
-
- protected IFileSystem FileSystemManager { get; private set; }
-
- protected IIsoManager IsoManager { get; private set; }
-
- protected ISystemEvents SystemEvents { get; private set; }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public abstract string Name { get; }
-
- /// <summary>
- /// Gets a value indicating whether this instance is running as service.
- /// </summary>
- /// <value><c>true</c> if this instance is running as service; otherwise, <c>false</c>.</value>
- public abstract bool IsRunningAsService { get; }
-
- protected ICryptographyProvider CryptographyProvider = new CryptographyProvider();
-
- private DeviceId _deviceId;
- public string SystemId
- {
- get
- {
- if (_deviceId == null)
- {
- _deviceId = new DeviceId(ApplicationPaths, LogManager.GetLogger("SystemId"), FileSystemManager);
- }
-
- return _deviceId.Value;
- }
- }
-
- public virtual string OperatingSystemDisplayName
- {
- get { return Environment.OSVersion.VersionString; }
- }
-
- public IMemoryStreamProvider MemoryStreamProvider { get; set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
- /// </summary>
- protected BaseApplicationHost(TApplicationPathsType applicationPaths,
- ILogManager logManager,
- IFileSystem fileSystem)
- {
- // hack alert, until common can target .net core
- BaseExtensions.CryptographyProvider = CryptographyProvider;
-
- XmlSerializer = new XmlSerializer(fileSystem, logManager.GetLogger("XmlSerializer"));
- FailedAssemblies = new List<string>();
-
- ApplicationPaths = applicationPaths;
- LogManager = logManager;
- FileSystemManager = fileSystem;
-
- ConfigurationManager = GetConfigurationManager();
-
- // Initialize this early in case the -v command line option is used
- Logger = LogManager.GetLogger("App");
- }
-
- /// <summary>
- /// Inits this instance.
- /// </summary>
- /// <returns>Task.</returns>
- public virtual async Task Init(IProgress<double> progress)
- {
- progress.Report(1);
-
- JsonSerializer = CreateJsonSerializer();
-
- MemoryStreamProvider = CreateMemoryStreamProvider();
- SystemEvents = CreateSystemEvents();
-
- OnLoggerLoaded(true);
- LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false);
-
- IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted;
- progress.Report(2);
-
- LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging
- ? LogSeverity.Debug
- : LogSeverity.Info;
-
- progress.Report(3);
-
- DiscoverTypes();
- progress.Report(14);
-
- SetHttpLimit();
- progress.Report(15);
-
- var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report(.8 * p + 15));
-
- await RegisterResources(innerProgress).ConfigureAwait(false);
-
- FindParts();
- progress.Report(95);
-
- await InstallIsoMounters(CancellationToken.None).ConfigureAwait(false);
-
- progress.Report(100);
- }
-
- protected abstract IMemoryStreamProvider CreateMemoryStreamProvider();
- protected abstract ISystemEvents CreateSystemEvents();
-
- protected virtual void OnLoggerLoaded(bool isFirstLoad)
- {
- Logger.Info("Application version: {0}", ApplicationVersion);
-
- if (!isFirstLoad)
- {
- LogEnvironmentInfo(Logger, ApplicationPaths, false);
- }
-
- // Put the app config in the log for troubleshooting purposes
- Logger.LogMultiline("Application configuration:", LogSeverity.Info, new StringBuilder(JsonSerializer.SerializeToString(ConfigurationManager.CommonConfiguration)));
-
- if (Plugins != null)
- {
- var pluginBuilder = new StringBuilder();
-
- foreach (var plugin in Plugins)
- {
- pluginBuilder.AppendLine(string.Format("{0} {1}", plugin.Name, plugin.Version));
- }
-
- Logger.LogMultiline("Plugins:", LogSeverity.Info, pluginBuilder);
- }
- }
-
- public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup)
- {
- logger.LogMultiline("Emby", LogSeverity.Info, GetBaseExceptionMessage(appPaths));
- }
-
- protected static StringBuilder GetBaseExceptionMessage(IApplicationPaths appPaths)
- {
- var builder = new StringBuilder();
-
- builder.AppendLine(string.Format("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs())));
-
- builder.AppendLine(string.Format("Operating system: {0}", Environment.OSVersion));
- builder.AppendLine(string.Format("Processor count: {0}", Environment.ProcessorCount));
- builder.AppendLine(string.Format("64-Bit OS: {0}", Environment.Is64BitOperatingSystem));
- builder.AppendLine(string.Format("64-Bit Process: {0}", Environment.Is64BitProcess));
- builder.AppendLine(string.Format("Program data path: {0}", appPaths.ProgramDataPath));
-
- Type type = Type.GetType("Mono.Runtime");
- if (type != null)
- {
- MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
- if (displayName != null)
- {
- builder.AppendLine("Mono: " + displayName.Invoke(null, null));
- }
- }
-
- builder.AppendLine(string.Format("Application Path: {0}", appPaths.ApplicationPath));
-
- return builder;
- }
-
- protected abstract IJsonSerializer CreateJsonSerializer();
-
- private void SetHttpLimit()
- {
- try
- {
- // Increase the max http request limit
- ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error setting http limit", ex);
- }
- }
-
- /// <summary>
- /// Installs the iso mounters.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task InstallIsoMounters(CancellationToken cancellationToken)
- {
- var list = new List<IIsoMounter>();
-
- foreach (var isoMounter in GetExports<IIsoMounter>())
- {
- try
- {
- if (isoMounter.RequiresInstallation && !isoMounter.IsInstalled)
- {
- Logger.Info("Installing {0}", isoMounter.Name);
-
- await isoMounter.Install(cancellationToken).ConfigureAwait(false);
- }
-
- list.Add(isoMounter);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("{0} failed to load.", ex, isoMounter.Name);
- }
- }
-
- IsoManager.AddParts(list);
- }
-
- /// <summary>
- /// Runs the startup tasks.
- /// </summary>
- /// <returns>Task.</returns>
- public virtual Task RunStartupTasks()
- {
- Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
-
- ConfigureAutorun();
-
- ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
-
- return Task.FromResult(true);
- }
-
- /// <summary>
- /// Configures the autorun.
- /// </summary>
- private void ConfigureAutorun()
- {
- try
- {
- ConfigureAutoRunAtStartup(ConfigurationManager.CommonConfiguration.RunAtStartup);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error configuring autorun", ex);
- }
- }
-
- /// <summary>
- /// Gets the composable part assemblies.
- /// </summary>
- /// <returns>IEnumerable{Assembly}.</returns>
- protected abstract IEnumerable<Assembly> GetComposablePartAssemblies();
-
- /// <summary>
- /// Gets the configuration manager.
- /// </summary>
- /// <returns>IConfigurationManager.</returns>
- protected abstract IConfigurationManager GetConfigurationManager();
-
- /// <summary>
- /// Finds the parts.
- /// </summary>
- protected virtual void FindParts()
- {
- ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
- Plugins = GetExports<IPlugin>().Select(LoadPlugin).Where(i => i != null).ToArray();
- }
-
- private IPlugin LoadPlugin(IPlugin plugin)
- {
- try
- {
- var assemblyPlugin = plugin as IPluginAssembly;
-
- if (assemblyPlugin != null)
- {
- var assembly = plugin.GetType().Assembly;
- var assemblyName = assembly.GetName();
-
- var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
- var assemblyId = new Guid(attribute.Value);
-
- var assemblyFileName = assemblyName.Name + ".dll";
- var assemblyFilePath = Path.Combine(ApplicationPaths.PluginsPath, assemblyFileName);
-
- assemblyPlugin.SetAttributes(assemblyFilePath, assemblyFileName, assemblyName.Version, assemblyId);
- }
-
- var isFirstRun = !File.Exists(plugin.ConfigurationFilePath);
-
- plugin.SetStartupInfo(isFirstRun, File.GetLastWriteTimeUtc, s => Directory.CreateDirectory(s));
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error loading plugin {0}", ex, plugin.GetType().FullName);
- return null;
- }
-
- return plugin;
- }
-
- /// <summary>
- /// Discovers the types.
- /// </summary>
- protected void DiscoverTypes()
- {
- FailedAssemblies.Clear();
-
- var assemblies = GetComposablePartAssemblies().ToList();
-
- foreach (var assembly in assemblies)
- {
- Logger.Info("Loading {0}", assembly.FullName);
- }
-
- AllConcreteTypes = assemblies
- .SelectMany(GetTypes)
- .Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType)
- .ToArray();
- }
-
- /// <summary>
- /// Registers resources that classes will depend on
- /// </summary>
- /// <returns>Task.</returns>
- protected virtual Task RegisterResources(IProgress<double> progress)
- {
- RegisterSingleInstance(ConfigurationManager);
- RegisterSingleInstance<IApplicationHost>(this);
-
- RegisterSingleInstance<IApplicationPaths>(ApplicationPaths);
-
- TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, LogManager.GetLogger("TaskManager"), FileSystemManager, SystemEvents);
-
- RegisterSingleInstance(JsonSerializer);
- RegisterSingleInstance(XmlSerializer);
- RegisterSingleInstance(MemoryStreamProvider);
- RegisterSingleInstance(SystemEvents);
-
- RegisterSingleInstance(LogManager);
- RegisterSingleInstance(Logger);
-
- RegisterSingleInstance(TaskManager);
-
- RegisterSingleInstance(FileSystemManager);
-
- HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamProvider);
- RegisterSingleInstance(HttpClient);
-
- NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager"));
- RegisterSingleInstance(NetworkManager);
-
- IsoManager = new IsoManager();
- RegisterSingleInstance(IsoManager);
-
- return Task.FromResult(true);
- }
-
- /// <summary>
- /// 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
- /// </summary>
- /// <param name="assembly">The assembly.</param>
- /// <returns>IEnumerable{Type}.</returns>
- /// <exception cref="System.ArgumentNullException">assembly</exception>
- protected IEnumerable<Type> GetTypes(Assembly assembly)
- {
- if (assembly == null)
- {
- throw new ArgumentNullException("assembly");
- }
-
- try
- {
- return assembly.GetTypes();
- }
- catch (ReflectionTypeLoadException ex)
- {
- if (ex.LoaderExceptions != null)
- {
- foreach (var loaderException in ex.LoaderExceptions)
- {
- Logger.Error("LoaderException: " + loaderException.Message);
- }
- }
-
- // If it fails we can still get a list of the Types it was able to resolve
- return ex.Types.Where(t => t != null);
- }
- }
-
- protected abstract INetworkManager CreateNetworkManager(ILogger logger);
-
- /// <summary>
- /// Creates an instance of type and resolves all constructor dependancies
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns>System.Object.</returns>
- public abstract object CreateInstance(Type type);
-
- /// <summary>
- /// Creates the instance safe.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns>System.Object.</returns>
- protected abstract object CreateInstanceSafe(Type type);
-
- /// <summary>
- /// Registers the specified obj.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="obj">The obj.</param>
- /// <param name="manageLifetime">if set to <c>true</c> [manage lifetime].</param>
- protected abstract void RegisterSingleInstance<T>(T obj, bool manageLifetime = true)
- where T : class;
-
- /// <summary>
- /// Registers the single instance.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="func">The func.</param>
- protected abstract void RegisterSingleInstance<T>(Func<T> func)
- where T : class;
-
- /// <summary>
- /// Resolves this instance.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>``0.</returns>
- public abstract T Resolve<T>();
-
- /// <summary>
- /// Resolves this instance.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>``0.</returns>
- public abstract T TryResolve<T>();
-
- /// <summary>
- /// Loads the assembly.
- /// </summary>
- /// <param name="file">The file.</param>
- /// <returns>Assembly.</returns>
- 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;
- }
- }
-
- /// <summary>
- /// Gets the export types.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>IEnumerable{Type}.</returns>
- public IEnumerable<Type> GetExportTypes<T>()
- {
- var currentType = typeof(T);
-
- return AllConcreteTypes.AsParallel().Where(currentType.IsAssignableFrom);
- }
-
- /// <summary>
- /// Gets the exports.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
- /// <returns>IEnumerable{``0}.</returns>
- public IEnumerable<T> GetExports<T>(bool manageLiftime = true)
- {
- var parts = GetExportTypes<T>()
- .Select(CreateInstanceSafe)
- .Where(i => i != null)
- .Cast<T>()
- .ToList();
-
- if (manageLiftime)
- {
- lock (DisposableParts)
- {
- DisposableParts.AddRange(parts.OfType<IDisposable>());
- }
- }
-
- return parts;
- }
-
- /// <summary>
- /// Gets the application version.
- /// </summary>
- /// <value>The application version.</value>
- public abstract Version ApplicationVersion { get; }
-
- /// <summary>
- /// Handles the ConfigurationUpdated event of the ConfigurationManager control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- /// <exception cref="System.NotImplementedException"></exception>
- protected virtual void OnConfigurationUpdated(object sender, EventArgs e)
- {
- ConfigureAutorun();
- }
-
- protected abstract void ConfigureAutoRunAtStartup(bool autorun);
-
- /// <summary>
- /// Removes the plugin.
- /// </summary>
- /// <param name="plugin">The plugin.</param>
- public void RemovePlugin(IPlugin plugin)
- {
- var list = Plugins.ToList();
- list.Remove(plugin);
- Plugins = list.ToArray();
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance can self restart.
- /// </summary>
- /// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value>
- public abstract bool CanSelfRestart { get; }
-
- /// <summary>
- /// Notifies that the kernel that a change has been made that requires a restart
- /// </summary>
- public void NotifyPendingRestart()
- {
- var changed = !HasPendingRestart;
-
- HasPendingRestart = true;
-
- if (changed)
- {
- EventHelper.QueueEventIfNotNull(HasPendingRestartChanged, this, EventArgs.Empty, Logger);
- }
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- var type = GetType();
-
- Logger.Info("Disposing " + type.Name);
-
- var parts = DisposableParts.Distinct().Where(i => i.GetType() != type).ToList();
- DisposableParts.Clear();
-
- foreach (var part in parts)
- {
- Logger.Info("Disposing " + part.GetType().Name);
-
- try
- {
- part.Dispose();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error disposing {0}", ex, part.GetType().Name);
- }
- }
- }
- }
-
- /// <summary>
- /// Restarts this instance.
- /// </summary>
- public abstract Task Restart();
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance can self update.
- /// </summary>
- /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
- public abstract bool CanSelfUpdate { get; }
-
- /// <summary>
- /// Checks for update.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task{CheckForUpdateResult}.</returns>
- public abstract Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken,
- IProgress<double> progress);
-
- /// <summary>
- /// Updates the application.
- /// </summary>
- /// <param name="package">The package that contains the update</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public abstract Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken,
- IProgress<double> progress);
-
- /// <summary>
- /// Shuts down.
- /// </summary>
- public abstract Task Shutdown();
-
- /// <summary>
- /// Called when [application updated].
- /// </summary>
- /// <param name="package">The package.</param>
- protected void OnApplicationUpdated(PackageVersionInfo package)
- {
- Logger.Info("Application has been updated to version {0}", package.versionStr);
-
- EventHelper.FireEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs<PackageVersionInfo>
- {
- Argument = package
-
- }, Logger);
-
- NotifyPendingRestart();
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs
deleted file mode 100644
index 9ba2effd3..000000000
--- a/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs
+++ /dev/null
@@ -1,178 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using System.IO;
-
-namespace MediaBrowser.Common.Implementations
-{
- /// <summary>
- /// 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.
- /// </summary>
- public abstract class BaseApplicationPaths : IApplicationPaths
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
- /// </summary>
- protected BaseApplicationPaths(string programDataPath, string applicationPath)
- {
- ProgramDataPath = programDataPath;
- ApplicationPath = applicationPath;
- }
-
- public string ApplicationPath { get; private set; }
- public string ProgramDataPath { get; private set; }
-
- /// <summary>
- /// Gets the path to the system folder
- /// </summary>
- public string ProgramSystemPath
- {
- get { return Path.GetDirectoryName(ApplicationPath); }
- }
-
- /// <summary>
- /// The _data directory
- /// </summary>
- private string _dataDirectory;
- /// <summary>
- /// Gets the folder path to the data directory
- /// </summary>
- /// <value>The data directory.</value>
- public string DataPath
- {
- get
- {
- if (_dataDirectory == null)
- {
- _dataDirectory = Path.Combine(ProgramDataPath, "data");
-
- Directory.CreateDirectory(_dataDirectory);
- }
-
- return _dataDirectory;
- }
- }
-
- /// <summary>
- /// Gets the image cache path.
- /// </summary>
- /// <value>The image cache path.</value>
- public string ImageCachePath
- {
- get
- {
- return Path.Combine(CachePath, "images");
- }
- }
-
- /// <summary>
- /// Gets the path to the plugin directory
- /// </summary>
- /// <value>The plugins path.</value>
- public string PluginsPath
- {
- get
- {
- return Path.Combine(ProgramDataPath, "plugins");
- }
- }
-
- /// <summary>
- /// Gets the path to the plugin configurations directory
- /// </summary>
- /// <value>The plugin configurations path.</value>
- public string PluginConfigurationsPath
- {
- get
- {
- return Path.Combine(PluginsPath, "configurations");
- }
- }
-
- /// <summary>
- /// Gets the path to where temporary update files will be stored
- /// </summary>
- /// <value>The plugin configurations path.</value>
- public string TempUpdatePath
- {
- get
- {
- return Path.Combine(ProgramDataPath, "updates");
- }
- }
-
- /// <summary>
- /// Gets the path to the log directory
- /// </summary>
- /// <value>The log directory path.</value>
- public string LogDirectoryPath
- {
- get
- {
- return Path.Combine(ProgramDataPath, "logs");
- }
- }
-
- /// <summary>
- /// Gets the path to the application configuration root directory
- /// </summary>
- /// <value>The configuration directory path.</value>
- public string ConfigurationDirectoryPath
- {
- get
- {
- return Path.Combine(ProgramDataPath, "config");
- }
- }
-
- /// <summary>
- /// Gets the path to the system configuration file
- /// </summary>
- /// <value>The system configuration file path.</value>
- public string SystemConfigurationFilePath
- {
- get
- {
- return Path.Combine(ConfigurationDirectoryPath, "system.xml");
- }
- }
-
- /// <summary>
- /// The _cache directory
- /// </summary>
- private string _cachePath;
- /// <summary>
- /// Gets the folder path to the cache directory
- /// </summary>
- /// <value>The cache directory.</value>
- public string CachePath
- {
- get
- {
- if (string.IsNullOrEmpty(_cachePath))
- {
- _cachePath = Path.Combine(ProgramDataPath, "cache");
-
- Directory.CreateDirectory(_cachePath);
- }
-
- return _cachePath;
- }
- set
- {
- _cachePath = value;
- }
- }
-
- /// <summary>
- /// Gets the folder path to the temp directory within the cache folder
- /// </summary>
- /// <value>The temp directory.</value>
- public string TempDirectory
- {
- get
- {
- return Path.Combine(CachePath, "temp");
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
deleted file mode 100644
index 943e6c5f8..000000000
--- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
+++ /dev/null
@@ -1,328 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Extensions;
-
-namespace MediaBrowser.Common.Implementations.Configuration
-{
- /// <summary>
- /// Class BaseConfigurationManager
- /// </summary>
- public abstract class BaseConfigurationManager : IConfigurationManager
- {
- /// <summary>
- /// Gets the type of the configuration.
- /// </summary>
- /// <value>The type of the configuration.</value>
- protected abstract Type ConfigurationType { get; }
-
- /// <summary>
- /// Occurs when [configuration updated].
- /// </summary>
- public event EventHandler<EventArgs> ConfigurationUpdated;
-
- /// <summary>
- /// Occurs when [configuration updating].
- /// </summary>
- public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdating;
-
- /// <summary>
- /// Occurs when [named configuration updated].
- /// </summary>
- public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdated;
-
- /// <summary>
- /// Gets the logger.
- /// </summary>
- /// <value>The logger.</value>
- protected ILogger Logger { get; private set; }
- /// <summary>
- /// Gets the XML serializer.
- /// </summary>
- /// <value>The XML serializer.</value>
- protected IXmlSerializer XmlSerializer { get; private set; }
-
- /// <summary>
- /// Gets or sets the application paths.
- /// </summary>
- /// <value>The application paths.</value>
- public IApplicationPaths CommonApplicationPaths { get; private set; }
- public readonly IFileSystem FileSystem;
-
- /// <summary>
- /// The _configuration loaded
- /// </summary>
- private bool _configurationLoaded;
- /// <summary>
- /// The _configuration sync lock
- /// </summary>
- private object _configurationSyncLock = new object();
- /// <summary>
- /// The _configuration
- /// </summary>
- private BaseApplicationConfiguration _configuration;
- /// <summary>
- /// Gets the system configuration
- /// </summary>
- /// <value>The configuration.</value>
- public BaseApplicationConfiguration CommonConfiguration
- {
- get
- {
- // Lazy load
- LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => (BaseApplicationConfiguration)ConfigurationHelper.GetXmlConfiguration(ConfigurationType, CommonApplicationPaths.SystemConfigurationFilePath, XmlSerializer, FileSystem));
- return _configuration;
- }
- protected set
- {
- _configuration = value;
-
- _configurationLoaded = value != null;
- }
- }
-
- private ConfigurationStore[] _configurationStores = { };
- private IConfigurationFactory[] _configurationFactories = { };
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseConfigurationManager" /> class.
- /// </summary>
- /// <param name="applicationPaths">The application paths.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="xmlSerializer">The XML serializer.</param>
- protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
- {
- CommonApplicationPaths = applicationPaths;
- XmlSerializer = xmlSerializer;
- FileSystem = fileSystem;
- Logger = logManager.GetLogger(GetType().Name);
-
- UpdateCachePath();
- }
-
- public virtual void AddParts(IEnumerable<IConfigurationFactory> factories)
- {
- _configurationFactories = factories.ToArray();
-
- _configurationStores = _configurationFactories
- .SelectMany(i => i.GetConfigurations())
- .ToArray();
- }
-
- /// <summary>
- /// Saves the configuration.
- /// </summary>
- public void SaveConfiguration()
- {
- Logger.Info("Saving system configuration");
- var path = CommonApplicationPaths.SystemConfigurationFilePath;
-
- FileSystem.CreateDirectory(Path.GetDirectoryName(path));
-
- lock (_configurationSyncLock)
- {
- XmlSerializer.SerializeToFile(CommonConfiguration, path);
- }
-
- OnConfigurationUpdated();
- }
-
- /// <summary>
- /// Called when [configuration updated].
- /// </summary>
- protected virtual void OnConfigurationUpdated()
- {
- UpdateCachePath();
-
- EventHelper.QueueEventIfNotNull(ConfigurationUpdated, this, EventArgs.Empty, Logger);
- }
-
- /// <summary>
- /// Replaces the configuration.
- /// </summary>
- /// <param name="newConfiguration">The new configuration.</param>
- /// <exception cref="System.ArgumentNullException">newConfiguration</exception>
- public virtual void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration)
- {
- if (newConfiguration == null)
- {
- throw new ArgumentNullException("newConfiguration");
- }
-
- ValidateCachePath(newConfiguration);
-
- CommonConfiguration = newConfiguration;
- SaveConfiguration();
- }
-
- /// <summary>
- /// Updates the items by name path.
- /// </summary>
- private void UpdateCachePath()
- {
- string cachePath;
-
- if (string.IsNullOrWhiteSpace(CommonConfiguration.CachePath))
- {
- cachePath = null;
- }
- else
- {
- cachePath = Path.Combine(CommonConfiguration.CachePath, "cache");
- }
-
- ((BaseApplicationPaths)CommonApplicationPaths).CachePath = cachePath;
- }
-
- /// <summary>
- /// Replaces the cache path.
- /// </summary>
- /// <param name="newConfig">The new configuration.</param>
- /// <exception cref="System.IO.DirectoryNotFoundException"></exception>
- private void ValidateCachePath(BaseApplicationConfiguration newConfig)
- {
- var newPath = newConfig.CachePath;
-
- if (!string.IsNullOrWhiteSpace(newPath)
- && !string.Equals(CommonConfiguration.CachePath ?? string.Empty, newPath))
- {
- // Validate
- if (!FileSystem.DirectoryExists(newPath))
- {
- throw new FileNotFoundException(string.Format("{0} does not exist.", newPath));
- }
-
- EnsureWriteAccess(newPath);
- }
- }
-
- protected void EnsureWriteAccess(string path)
- {
- var file = Path.Combine(path, Guid.NewGuid().ToString());
-
- FileSystem.WriteAllText(file, string.Empty);
- FileSystem.DeleteFile(file);
- }
-
- private readonly ConcurrentDictionary<string, object> _configurations = new ConcurrentDictionary<string, object>();
-
- private string GetConfigurationFile(string key)
- {
- return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml");
- }
-
- public object GetConfiguration(string key)
- {
- return _configurations.GetOrAdd(key, k =>
- {
- var file = GetConfigurationFile(key);
-
- var configurationInfo = _configurationStores
- .FirstOrDefault(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase));
-
- if (configurationInfo == null)
- {
- throw new ResourceNotFoundException("Configuration with key " + key + " not found.");
- }
-
- var configurationType = configurationInfo.ConfigurationType;
-
- lock (_configurationSyncLock)
- {
- return LoadConfiguration(file, configurationType);
- }
- });
- }
-
- private object LoadConfiguration(string path, Type configurationType)
- {
- try
- {
- return XmlSerializer.DeserializeFromFile(configurationType, path);
- }
- catch (FileNotFoundException)
- {
- return Activator.CreateInstance(configurationType);
- }
- catch (IOException)
- {
- return Activator.CreateInstance(configurationType);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error loading configuration file: {0}", ex, path);
-
- return Activator.CreateInstance(configurationType);
- }
- }
-
- public void SaveConfiguration(string key, object configuration)
- {
- var configurationStore = GetConfigurationStore(key);
- var configurationType = configurationStore.ConfigurationType;
-
- if (configuration.GetType() != configurationType)
- {
- throw new ArgumentException("Expected configuration type is " + configurationType.Name);
- }
-
- var validatingStore = configurationStore as IValidatingConfiguration;
- if (validatingStore != null)
- {
- var currentConfiguration = GetConfiguration(key);
-
- validatingStore.Validate(currentConfiguration, configuration);
- }
-
- EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs
- {
- Key = key,
- NewConfiguration = configuration
-
- }, Logger);
-
- _configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
-
- var path = GetConfigurationFile(key);
- FileSystem.CreateDirectory(Path.GetDirectoryName(path));
-
- lock (_configurationSyncLock)
- {
- XmlSerializer.SerializeToFile(configuration, path);
- }
-
- OnNamedConfigurationUpdated(key, configuration);
- }
-
- protected virtual void OnNamedConfigurationUpdated(string key, object configuration)
- {
- EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs
- {
- Key = key,
- NewConfiguration = configuration
-
- }, Logger);
- }
-
- public Type GetConfigurationType(string key)
- {
- return GetConfigurationStore(key)
- .ConfigurationType;
- }
-
- private ConfigurationStore GetConfigurationStore(string key)
- {
- return _configurationStores
- .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase));
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
deleted file mode 100644
index 0c1683f93..000000000
--- a/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using MediaBrowser.Model.Serialization;
-using System;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Common.Implementations.Configuration
-{
- /// <summary>
- /// Class ConfigurationHelper
- /// </summary>
- public static class ConfigurationHelper
- {
- /// <summary>
- /// Reads an xml configuration file from the file system
- /// It will immediately re-serialize and save if new serialization data is available due to property changes
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="path">The path.</param>
- /// <param name="xmlSerializer">The XML serializer.</param>
- /// <returns>System.Object.</returns>
- public static object GetXmlConfiguration(Type type, string path, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
- {
- object configuration;
-
- byte[] buffer = null;
-
- // Use try/catch to avoid the extra file system lookup using File.Exists
- try
- {
- buffer = fileSystem.ReadAllBytes(path);
-
- configuration = xmlSerializer.DeserializeFromBytes(type, buffer);
- }
- catch (Exception)
- {
- configuration = Activator.CreateInstance(type);
- }
-
- using (var stream = new MemoryStream())
- {
- xmlSerializer.SerializeToStream(configuration, stream);
-
- // Take the object we just got and serialize it back to bytes
- var newBytes = stream.ToArray();
-
- // If the file didn't exist before, or if something has changed, re-save
- if (buffer == null || !buffer.SequenceEqual(newBytes))
- {
- fileSystem.CreateDirectory(Path.GetDirectoryName(path));
-
- // Save it after load in case we got new items
- fileSystem.WriteAllBytes(path, newBytes);
- }
-
- return configuration;
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Cryptography/CryptographyProvider.cs b/MediaBrowser.Common.Implementations/Cryptography/CryptographyProvider.cs
deleted file mode 100644
index 67dbd76d2..000000000
--- a/MediaBrowser.Common.Implementations/Cryptography/CryptographyProvider.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.IO;
-using System.Security.Cryptography;
-using System.Text;
-using MediaBrowser.Model.Cryptography;
-
-namespace MediaBrowser.Common.Implementations.Cryptography
-{
- public class CryptographyProvider : ICryptographyProvider
- {
- public Guid GetMD5(string str)
- {
- return new Guid(GetMD5Bytes(str));
- }
- public byte[] GetMD5Bytes(string str)
- {
- using (var provider = MD5.Create())
- {
- return provider.ComputeHash(Encoding.Unicode.GetBytes(str));
- }
- }
- public byte[] GetMD5Bytes(Stream str)
- {
- using (var provider = MD5.Create())
- {
- return provider.ComputeHash(str);
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
deleted file mode 100644
index 40bbe8713..000000000
--- a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Text;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Common.Implementations.Devices
-{
- public class DeviceId
- {
- private readonly IApplicationPaths _appPaths;
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
-
- private readonly object _syncLock = new object();
-
- private string CachePath
- {
- get { return Path.Combine(_appPaths.DataPath, "device.txt"); }
- }
-
- private string GetCachedId()
- {
- try
- {
- lock (_syncLock)
- {
- var value = File.ReadAllText(CachePath, Encoding.UTF8);
-
- Guid guid;
- if (Guid.TryParse(value, out guid))
- {
- return value;
- }
-
- _logger.Error("Invalid value found in device id file");
- }
- }
- catch (DirectoryNotFoundException)
- {
- }
- catch (FileNotFoundException)
- {
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error reading file", ex);
- }
-
- return null;
- }
-
- private void SaveId(string id)
- {
- try
- {
- var path = CachePath;
-
- _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
-
- lock (_syncLock)
- {
- _fileSystem.WriteAllText(path, id, Encoding.UTF8);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error writing to file", ex);
- }
- }
-
- private string GetNewId()
- {
- return Guid.NewGuid().ToString("N");
- }
-
- private string GetDeviceId()
- {
- var id = GetCachedId();
-
- if (string.IsNullOrWhiteSpace(id))
- {
- id = GetNewId();
- SaveId(id);
- }
-
- return id;
- }
-
- private string _id;
-
- public DeviceId(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
- {
- if (fileSystem == null) {
- throw new ArgumentNullException ("fileSystem");
- }
-
- _appPaths = appPaths;
- _logger = logger;
- _fileSystem = fileSystem;
- }
-
- public string Value
- {
- get { return _id ?? (_id = GetDeviceId()); }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientInfo.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientInfo.cs
deleted file mode 100644
index 8af6ef6c6..000000000
--- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientInfo.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-
-namespace MediaBrowser.Common.Implementations.HttpClientManager
-{
- /// <summary>
- /// Class HttpClientInfo
- /// </summary>
- public class HttpClientInfo
- {
- /// <summary>
- /// Gets or sets the last timeout.
- /// </summary>
- /// <value>The last timeout.</value>
- public DateTime LastTimeout { get; set; }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
deleted file mode 100644
index b18178ead..000000000
--- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ /dev/null
@@ -1,936 +0,0 @@
-using System.Net.Sockets;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Cache;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Common.Implementations.HttpClientManager
-{
- /// <summary>
- /// Class HttpClientManager
- /// </summary>
- public class HttpClientManager : IHttpClient
- {
- /// <summary>
- /// When one request to a host times out, we'll ban all other requests for this period of time, to prevent scans from stalling
- /// </summary>
- private const int TimeoutSeconds = 30;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- /// <summary>
- /// The _app paths
- /// </summary>
- private readonly IApplicationPaths _appPaths;
-
- private readonly IFileSystem _fileSystem;
- private readonly IMemoryStreamProvider _memoryStreamProvider;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="HttpClientManager" /> class.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <param name="logger">The logger.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <exception cref="System.ArgumentNullException">appPaths
- /// or
- /// logger</exception>
- public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IMemoryStreamProvider memoryStreamProvider)
- {
- if (appPaths == null)
- {
- throw new ArgumentNullException("appPaths");
- }
- if (logger == null)
- {
- throw new ArgumentNullException("logger");
- }
-
- _logger = logger;
- _fileSystem = fileSystem;
- _memoryStreamProvider = memoryStreamProvider;
- _appPaths = appPaths;
-
- // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
- ServicePointManager.Expect100Continue = false;
-
- // Trakt requests sometimes fail without this
- ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
- }
-
- /// <summary>
- /// Holds a dictionary of http clients by host. Use GetHttpClient(host) to retrieve or create a client for web requests.
- /// DON'T dispose it after use.
- /// </summary>
- /// <value>The HTTP clients.</value>
- private readonly ConcurrentDictionary<string, HttpClientInfo> _httpClients = new ConcurrentDictionary<string, HttpClientInfo>();
-
- /// <summary>
- /// Gets
- /// </summary>
- /// <param name="host">The host.</param>
- /// <param name="enableHttpCompression">if set to <c>true</c> [enable HTTP compression].</param>
- /// <returns>HttpClient.</returns>
- /// <exception cref="System.ArgumentNullException">host</exception>
- private HttpClientInfo GetHttpClient(string host, bool enableHttpCompression)
- {
- if (string.IsNullOrEmpty(host))
- {
- throw new ArgumentNullException("host");
- }
-
- HttpClientInfo client;
-
- var key = host + enableHttpCompression;
-
- if (!_httpClients.TryGetValue(key, out client))
- {
- client = new HttpClientInfo();
-
- _httpClients.TryAdd(key, client);
- }
-
- return client;
- }
-
- private WebRequest CreateWebRequest(string url)
- {
- try
- {
- return WebRequest.Create(url);
- }
- catch (NotSupportedException)
- {
- //Webrequest creation does fail on MONO randomly when using WebRequest.Create
- //the issue occurs in the GetCreator method here: http://www.oschina.net/code/explore/mono-2.8.1/mcs/class/System/System.Net/WebRequest.cs
-
- var type = Type.GetType("System.Net.HttpRequestCreator, System, Version=4.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089");
- var creator = Activator.CreateInstance(type, nonPublic: true) as IWebRequestCreate;
- return creator.Create(new Uri(url)) as HttpWebRequest;
- }
- }
-
- private void AddIpv4Option(HttpWebRequest request, HttpRequestOptions options)
- {
- request.ServicePoint.BindIPEndPointDelegate = (servicePount, remoteEndPoint, retryCount) =>
- {
- if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork)
- {
- return new IPEndPoint(IPAddress.Any, 0);
- }
- throw new InvalidOperationException("no IPv4 address");
- };
- }
-
- private WebRequest GetRequest(HttpRequestOptions options, string method)
- {
- var url = options.Url;
-
- var uriAddress = new Uri(url);
- var userInfo = uriAddress.UserInfo;
- if (!string.IsNullOrWhiteSpace(userInfo))
- {
- _logger.Info("Found userInfo in url: {0} ... url: {1}", userInfo, url);
- url = url.Replace(userInfo + "@", string.Empty);
- }
-
- var request = CreateWebRequest(url);
- var httpWebRequest = request as HttpWebRequest;
-
- if (httpWebRequest != null)
- {
- if (options.PreferIpv4)
- {
- AddIpv4Option(httpWebRequest, options);
- }
-
- AddRequestHeaders(httpWebRequest, options);
-
- httpWebRequest.AutomaticDecompression = options.EnableHttpCompression ?
- (options.DecompressionMethod ?? DecompressionMethods.Deflate) :
- DecompressionMethods.None;
- }
-
- request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
-
- if (httpWebRequest != null)
- {
- if (options.EnableKeepAlive)
- {
- httpWebRequest.KeepAlive = true;
- }
- }
-
- request.Method = method;
- request.Timeout = options.TimeoutMs;
-
- if (httpWebRequest != null)
- {
- if (!string.IsNullOrEmpty(options.Host))
- {
- httpWebRequest.Host = options.Host;
- }
-
- if (!string.IsNullOrEmpty(options.Referer))
- {
- httpWebRequest.Referer = options.Referer;
- }
- }
-
- if (!string.IsNullOrWhiteSpace(userInfo))
- {
- var parts = userInfo.Split(':');
- if (parts.Length == 2)
- {
- request.Credentials = GetCredential(url, parts[0], parts[1]);
- request.PreAuthenticate = true;
- }
- }
-
- return request;
- }
-
- private CredentialCache GetCredential(string url, string username, string password)
- {
- //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
- CredentialCache credentialCache = new CredentialCache();
- credentialCache.Add(new Uri(url), "Basic", new NetworkCredential(username, password));
- return credentialCache;
- }
-
- private void AddRequestHeaders(HttpWebRequest request, HttpRequestOptions options)
- {
- foreach (var header in options.RequestHeaders.ToList())
- {
- if (string.Equals(header.Key, "Accept", StringComparison.OrdinalIgnoreCase))
- {
- request.Accept = header.Value;
- }
- else if (string.Equals(header.Key, "User-Agent", StringComparison.OrdinalIgnoreCase))
- {
- request.UserAgent = header.Value;
- }
- else
- {
- request.Headers.Set(header.Key, header.Value);
- }
- }
- }
-
- /// <summary>
- /// Gets the response internal.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- public Task<HttpResponseInfo> GetResponse(HttpRequestOptions options)
- {
- return SendAsync(options, "GET");
- }
-
- /// <summary>
- /// Performs a GET request and returns the resulting stream
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{Stream}.</returns>
- public async Task<Stream> Get(HttpRequestOptions options)
- {
- var response = await GetResponse(options).ConfigureAwait(false);
-
- return response.Content;
- }
-
- /// <summary>
- /// Performs a GET request and returns the resulting stream
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="resourcePool">The resource pool.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{Stream}.</returns>
- public Task<Stream> Get(string url, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
- {
- return Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = resourcePool,
- CancellationToken = cancellationToken,
- BufferContent = resourcePool != null
- });
- }
-
- /// <summary>
- /// Gets the specified URL.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{Stream}.</returns>
- public Task<Stream> Get(string url, CancellationToken cancellationToken)
- {
- return Get(url, null, cancellationToken);
- }
-
- /// <summary>
- /// send as an asynchronous operation.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="httpMethod">The HTTP method.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- /// <exception cref="HttpException">
- /// </exception>
- public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod)
- {
- if (options.CacheMode == CacheMode.None)
- {
- return await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
- }
-
- var url = options.Url;
- var urlHash = url.ToLower().GetMD5().ToString("N");
-
- var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
-
- var response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false);
- if (response != null)
- {
- return response;
- }
-
- response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
-
- if (response.StatusCode == HttpStatusCode.OK)
- {
- await CacheResponse(response, responseCachePath).ConfigureAwait(false);
- }
-
- return response;
- }
-
- private async Task<HttpResponseInfo> GetCachedResponse(string responseCachePath, TimeSpan cacheLength, string url)
- {
- _logger.Info("Checking for cache file {0}", responseCachePath);
-
- try
- {
- if (_fileSystem.GetLastWriteTimeUtc(responseCachePath).Add(cacheLength) > DateTime.UtcNow)
- {
- using (var stream = _fileSystem.GetFileStream(responseCachePath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true))
- {
- var memoryStream = _memoryStreamProvider.CreateNew();
-
- await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
- memoryStream.Position = 0;
-
- return new HttpResponseInfo
- {
- ResponseUrl = url,
- Content = memoryStream,
- StatusCode = HttpStatusCode.OK,
- ContentLength = memoryStream.Length
- };
- }
- }
- }
- catch (FileNotFoundException)
- {
-
- }
- catch (DirectoryNotFoundException)
- {
-
- }
-
- return null;
- }
-
- private async Task CacheResponse(HttpResponseInfo response, string responseCachePath)
- {
- _fileSystem.CreateDirectory(Path.GetDirectoryName(responseCachePath));
-
- using (var responseStream = response.Content)
- {
- var memoryStream = _memoryStreamProvider.CreateNew();
- await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false);
- memoryStream.Position = 0;
-
- using (var fileStream = _fileSystem.GetFileStream(responseCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true))
- {
- await memoryStream.CopyToAsync(fileStream).ConfigureAwait(false);
-
- memoryStream.Position = 0;
- response.Content = memoryStream;
- }
- }
- }
-
- private async Task<HttpResponseInfo> SendAsyncInternal(HttpRequestOptions options, string httpMethod)
- {
- ValidateParams(options);
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
-
- if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds)
- {
- throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url))
- {
- IsTimedOut = true
- };
- }
-
- var httpWebRequest = GetRequest(options, httpMethod);
-
- if (options.RequestContentBytes != null ||
- !string.IsNullOrEmpty(options.RequestContent) ||
- string.Equals(httpMethod, "post", StringComparison.OrdinalIgnoreCase))
- {
- var bytes = options.RequestContentBytes ??
- Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty);
-
- httpWebRequest.ContentType = options.RequestContentType ?? "application/x-www-form-urlencoded";
-
- httpWebRequest.ContentLength = bytes.Length;
- httpWebRequest.GetRequestStream().Write(bytes, 0, bytes.Length);
- }
-
- if (options.ResourcePool != null)
- {
- await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
- }
-
- if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds)
- {
- if (options.ResourcePool != null)
- {
- options.ResourcePool.Release();
- }
-
- throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true };
- }
-
- if (options.LogRequest)
- {
- _logger.Info("HttpClientManager {0}: {1}", httpMethod.ToUpper(), options.Url);
- }
-
- try
- {
- options.CancellationToken.ThrowIfCancellationRequested();
-
- if (!options.BufferContent)
- {
- var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false);
-
- var httpResponse = (HttpWebResponse)response;
-
- EnsureSuccessStatusCode(client, httpResponse, options);
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse), httpResponse);
- }
-
- using (var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false))
- {
- var httpResponse = (HttpWebResponse)response;
-
- EnsureSuccessStatusCode(client, httpResponse, options);
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- using (var stream = httpResponse.GetResponseStream())
- {
- var memoryStream = _memoryStreamProvider.CreateNew();
-
- await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
- memoryStream.Position = 0;
-
- return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length, null);
- }
- }
- }
- catch (OperationCanceledException ex)
- {
- throw GetCancellationException(options, client, options.CancellationToken, ex);
- }
- catch (Exception ex)
- {
- throw GetException(ex, options, client);
- }
- finally
- {
- if (options.ResourcePool != null)
- {
- options.ResourcePool.Release();
- }
- }
- }
-
- private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength, IDisposable disposable)
- {
- var responseInfo = new HttpResponseInfo(disposable)
- {
- Content = content,
-
- StatusCode = httpResponse.StatusCode,
-
- ContentType = httpResponse.ContentType,
-
- ContentLength = contentLength,
-
- ResponseUrl = httpResponse.ResponseUri.ToString()
- };
-
- if (httpResponse.Headers != null)
- {
- SetHeaders(httpResponse.Headers, responseInfo);
- }
-
- return responseInfo;
- }
-
- private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, string tempFile, long? contentLength)
- {
- var responseInfo = new HttpResponseInfo
- {
- TempFilePath = tempFile,
-
- StatusCode = httpResponse.StatusCode,
-
- ContentType = httpResponse.ContentType,
-
- ContentLength = contentLength
- };
-
- if (httpResponse.Headers != null)
- {
- SetHeaders(httpResponse.Headers, responseInfo);
- }
-
- return responseInfo;
- }
-
- private void SetHeaders(WebHeaderCollection headers, HttpResponseInfo responseInfo)
- {
- foreach (var key in headers.AllKeys)
- {
- responseInfo.Headers[key] = headers[key];
- }
- }
-
- public Task<HttpResponseInfo> Post(HttpRequestOptions options)
- {
- return SendAsync(options, "POST");
- }
-
- /// <summary>
- /// Performs a POST request
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="postData">Params to add to the POST data.</param>
- /// <returns>stream on success, null on failure</returns>
- public async Task<Stream> Post(HttpRequestOptions options, Dictionary<string, string> postData)
- {
- options.SetPostData(postData);
-
- var response = await Post(options).ConfigureAwait(false);
-
- return response.Content;
- }
-
- /// <summary>
- /// Performs a POST request
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="postData">Params to add to the POST data.</param>
- /// <param name="resourcePool">The resource pool.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>stream on success, null on failure</returns>
- public Task<Stream> Post(string url, Dictionary<string, string> postData, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
- {
- return Post(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = resourcePool,
- CancellationToken = cancellationToken,
- BufferContent = resourcePool != null
-
- }, postData);
- }
-
- /// <summary>
- /// Downloads the contents of a given url into a temporary location
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{System.String}.</returns>
- public async Task<string> GetTempFile(HttpRequestOptions options)
- {
- var response = await GetTempFileResponse(options).ConfigureAwait(false);
-
- return response.TempFilePath;
- }
-
- public async Task<HttpResponseInfo> GetTempFileResponse(HttpRequestOptions options)
- {
- ValidateParams(options);
-
- _fileSystem.CreateDirectory(_appPaths.TempDirectory);
-
- var tempFile = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp");
-
- if (options.Progress == null)
- {
- throw new ArgumentNullException("progress");
- }
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- var httpWebRequest = GetRequest(options, "GET");
-
- if (options.ResourcePool != null)
- {
- await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
- }
-
- options.Progress.Report(0);
-
- if (options.LogRequest)
- {
- _logger.Info("HttpClientManager.GetTempFileResponse url: {0}", options.Url);
- }
-
- var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
-
- try
- {
- options.CancellationToken.ThrowIfCancellationRequested();
-
- using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false))
- {
- var httpResponse = (HttpWebResponse)response;
-
- EnsureSuccessStatusCode(client, httpResponse, options);
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- var contentLength = GetContentLength(httpResponse);
-
- if (!contentLength.HasValue)
- {
- // We're not able to track progress
- using (var stream = httpResponse.GetResponseStream())
- {
- using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
- {
- await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
- }
- }
- }
- else
- {
- using (var stream = ProgressStream.CreateReadProgressStream(httpResponse.GetResponseStream(), options.Progress.Report, contentLength.Value))
- {
- using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
- {
- await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
- }
- }
- }
-
- options.Progress.Report(100);
-
- return GetResponseInfo(httpResponse, tempFile, contentLength);
- }
- }
- catch (Exception ex)
- {
- DeleteTempFile(tempFile);
- throw GetException(ex, options, client);
- }
- finally
- {
- if (options.ResourcePool != null)
- {
- options.ResourcePool.Release();
- }
- }
- }
-
- private long? GetContentLength(HttpWebResponse response)
- {
- var length = response.ContentLength;
-
- if (length == 0)
- {
- return null;
- }
-
- return length;
- }
-
- protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- private Exception GetException(Exception ex, HttpRequestOptions options, HttpClientInfo client)
- {
- if (ex is HttpException)
- {
- return ex;
- }
-
- var webException = ex as WebException
- ?? ex.InnerException as WebException;
-
- if (webException != null)
- {
- if (options.LogErrors)
- {
- _logger.ErrorException("Error getting response from " + options.Url, ex);
- }
-
- var exception = new HttpException(ex.Message, ex);
-
- var response = webException.Response as HttpWebResponse;
- if (response != null)
- {
- exception.StatusCode = response.StatusCode;
-
- if ((int)response.StatusCode == 429)
- {
- client.LastTimeout = DateTime.UtcNow;
- }
- }
-
- return exception;
- }
-
- var operationCanceledException = ex as OperationCanceledException
- ?? ex.InnerException as OperationCanceledException;
-
- if (operationCanceledException != null)
- {
- return GetCancellationException(options, client, options.CancellationToken, operationCanceledException);
- }
-
- if (options.LogErrors)
- {
- _logger.ErrorException("Error getting response from " + options.Url, ex);
- }
-
- return ex;
- }
-
- private void DeleteTempFile(string file)
- {
- try
- {
- _fileSystem.DeleteFile(file);
- }
- catch (IOException)
- {
- // Might not have been created at all. No need to worry.
- }
- }
-
- private void ValidateParams(HttpRequestOptions options)
- {
- if (string.IsNullOrEmpty(options.Url))
- {
- throw new ArgumentNullException("options");
- }
- }
-
- /// <summary>
- /// Gets the host from URL.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <returns>System.String.</returns>
- private string GetHostFromUrl(string url)
- {
- var index = url.IndexOf("://", StringComparison.OrdinalIgnoreCase);
-
- if (index != -1)
- {
- url = url.Substring(index + 3);
- var host = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
-
- if (!string.IsNullOrWhiteSpace(host))
- {
- return host;
- }
- }
-
- return url;
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- _httpClients.Clear();
- }
- }
-
- /// <summary>
- /// Throws the cancellation exception.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="client">The client.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="exception">The exception.</param>
- /// <returns>Exception.</returns>
- private Exception GetCancellationException(HttpRequestOptions options, HttpClientInfo client, CancellationToken cancellationToken, OperationCanceledException exception)
- {
- // If the HttpClient's timeout is reached, it will cancel the Task internally
- if (!cancellationToken.IsCancellationRequested)
- {
- var msg = string.Format("Connection to {0} timed out", options.Url);
-
- if (options.LogErrors)
- {
- _logger.Error(msg);
- }
-
- client.LastTimeout = DateTime.UtcNow;
-
- // Throw an HttpException so that the caller doesn't think it was cancelled by user code
- return new HttpException(msg, exception)
- {
- IsTimedOut = true
- };
- }
-
- return exception;
- }
-
- private void EnsureSuccessStatusCode(HttpClientInfo client, HttpWebResponse response, HttpRequestOptions options)
- {
- var statusCode = response.StatusCode;
-
- var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299;
-
- if (!isSuccessful)
- {
- if (options.LogErrorResponseBody)
- {
- try
- {
- using (var stream = response.GetResponseStream())
- {
- if (stream != null)
- {
- using (var reader = new StreamReader(stream))
- {
- var msg = reader.ReadToEnd();
-
- _logger.Error(msg);
- }
- }
- }
- }
- catch
- {
-
- }
- }
- throw new HttpException(response.StatusDescription)
- {
- StatusCode = response.StatusCode
- };
- }
- }
-
- /// <summary>
- /// Posts the specified URL.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="postData">The post data.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{Stream}.</returns>
- public Task<Stream> Post(string url, Dictionary<string, string> postData, CancellationToken cancellationToken)
- {
- return Post(url, postData, null, cancellationToken);
- }
-
- private Task<WebResponse> GetResponseAsync(WebRequest request, TimeSpan timeout)
- {
- var taskCompletion = new TaskCompletionSource<WebResponse>();
-
- Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
-
- ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, TimeoutCallback, request, timeout, true);
- var callback = new TaskCallback { taskCompletion = taskCompletion };
- asyncTask.ContinueWith(callback.OnSuccess, TaskContinuationOptions.NotOnFaulted);
-
- // Handle errors
- asyncTask.ContinueWith(callback.OnError, TaskContinuationOptions.OnlyOnFaulted);
-
- return taskCompletion.Task;
- }
-
- private static void TimeoutCallback(object state, bool timedOut)
- {
- if (timedOut)
- {
- WebRequest request = (WebRequest)state;
- if (state != null)
- {
- request.Abort();
- }
- }
- }
-
- private class TaskCallback
- {
- public TaskCompletionSource<WebResponse> taskCompletion;
-
- public void OnSuccess(Task<WebResponse> task)
- {
- taskCompletion.TrySetResult(task.Result);
- }
-
- public void OnError(Task<WebResponse> task)
- {
- if (task.Exception != null)
- {
- taskCompletion.TrySetException(task.Exception);
- }
- else
- {
- taskCompletion.TrySetException(new List<Exception>());
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/IO/IsoManager.cs b/MediaBrowser.Common.Implementations/IO/IsoManager.cs
deleted file mode 100644
index de88ddada..000000000
--- a/MediaBrowser.Common.Implementations/IO/IsoManager.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using MediaBrowser.Model.IO;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Common.Implementations.IO
-{
- /// <summary>
- /// Class IsoManager
- /// </summary>
- public class IsoManager : IIsoManager
- {
- /// <summary>
- /// The _mounters
- /// </summary>
- private readonly List<IIsoMounter> _mounters = new List<IIsoMounter>();
-
- /// <summary>
- /// Mounts the specified iso path.
- /// </summary>
- /// <param name="isoPath">The iso path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>IsoMount.</returns>
- /// <exception cref="System.ArgumentNullException">isoPath</exception>
- /// <exception cref="System.ArgumentException"></exception>
- public Task<IIsoMount> Mount(string isoPath, CancellationToken cancellationToken)
- {
- if (string.IsNullOrEmpty(isoPath))
- {
- throw new ArgumentNullException("isoPath");
- }
-
- var mounter = _mounters.FirstOrDefault(i => i.CanMount(isoPath));
-
- if (mounter == null)
- {
- throw new ArgumentException(string.Format("No mounters are able to mount {0}", isoPath));
- }
-
- return mounter.Mount(isoPath, cancellationToken);
- }
-
- /// <summary>
- /// Determines whether this instance can mount the specified path.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if this instance can mount the specified path; otherwise, <c>false</c>.</returns>
- public bool CanMount(string path)
- {
- return _mounters.Any(i => i.CanMount(path));
- }
-
- /// <summary>
- /// Adds the parts.
- /// </summary>
- /// <param name="mounters">The mounters.</param>
- public void AddParts(IEnumerable<IIsoMounter> mounters)
- {
- _mounters.AddRange(mounters);
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- foreach (var mounter in _mounters)
- {
- mounter.Dispose();
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/IO/ManagedFileSystem.cs b/MediaBrowser.Common.Implementations/IO/ManagedFileSystem.cs
deleted file mode 100644
index 4f6c34cb7..000000000
--- a/MediaBrowser.Common.Implementations/IO/ManagedFileSystem.cs
+++ /dev/null
@@ -1,705 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Common.Implementations.IO
-{
- /// <summary>
- /// Class ManagedFileSystem
- /// </summary>
- public class ManagedFileSystem : IFileSystem
- {
- protected ILogger Logger;
-
- private readonly bool _supportsAsyncFileStreams;
- private char[] _invalidFileNameChars;
- private readonly List<IShortcutHandler> _shortcutHandlers = new List<IShortcutHandler>();
- protected bool EnableFileSystemRequestConcat = true;
-
- public ManagedFileSystem(ILogger logger, bool supportsAsyncFileStreams, bool enableManagedInvalidFileNameChars)
- {
- Logger = logger;
- _supportsAsyncFileStreams = supportsAsyncFileStreams;
- SetInvalidFileNameChars(enableManagedInvalidFileNameChars);
- }
-
- public void AddShortcutHandler(IShortcutHandler handler)
- {
- _shortcutHandlers.Add(handler);
- }
-
- protected void SetInvalidFileNameChars(bool enableManagedInvalidFileNameChars)
- {
- if (enableManagedInvalidFileNameChars)
- {
- _invalidFileNameChars = Path.GetInvalidFileNameChars();
- }
- else
- {
- // GetInvalidFileNameChars is less restrictive in Linux/Mac than Windows, this mimic Windows behavior for mono under Linux/Mac.
- _invalidFileNameChars = new char[41] { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
- '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12',
- '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D',
- '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' };
- }
- }
-
- public char DirectorySeparatorChar
- {
- get
- {
- return Path.DirectorySeparatorChar;
- }
- }
-
- public string GetFullPath(string path)
- {
- return Path.GetFullPath(path);
- }
-
- /// <summary>
- /// Determines whether the specified filename is shortcut.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns>
- /// <exception cref="System.ArgumentNullException">filename</exception>
- public virtual bool IsShortcut(string filename)
- {
- if (string.IsNullOrEmpty(filename))
- {
- throw new ArgumentNullException("filename");
- }
-
- var extension = Path.GetExtension(filename);
- return _shortcutHandlers.Any(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
- }
-
- /// <summary>
- /// Resolves the shortcut.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentNullException">filename</exception>
- public virtual string ResolveShortcut(string filename)
- {
- if (string.IsNullOrEmpty(filename))
- {
- throw new ArgumentNullException("filename");
- }
-
- var extension = Path.GetExtension(filename);
- var handler = _shortcutHandlers.FirstOrDefault(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
-
- if (handler != null)
- {
- return handler.Resolve(filename);
- }
-
- return null;
- }
-
- /// <summary>
- /// Creates the shortcut.
- /// </summary>
- /// <param name="shortcutPath">The shortcut path.</param>
- /// <param name="target">The target.</param>
- /// <exception cref="System.ArgumentNullException">
- /// shortcutPath
- /// or
- /// target
- /// </exception>
- public void CreateShortcut(string shortcutPath, string target)
- {
- if (string.IsNullOrEmpty(shortcutPath))
- {
- throw new ArgumentNullException("shortcutPath");
- }
-
- if (string.IsNullOrEmpty(target))
- {
- throw new ArgumentNullException("target");
- }
-
- var extension = Path.GetExtension(shortcutPath);
- var handler = _shortcutHandlers.FirstOrDefault(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
-
- if (handler != null)
- {
- handler.Create(shortcutPath, target);
- }
- else
- {
- throw new NotImplementedException();
- }
- }
-
- /// <summary>
- /// Returns a <see cref="FileSystemMetadata"/> object for the specified file or directory path.
- /// </summary>
- /// <param name="path">A path to a file or directory.</param>
- /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
- /// <remarks>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's
- /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and all other properties will reflect the properties of the directory.</remarks>
- public FileSystemMetadata GetFileSystemInfo(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- // Take a guess to try and avoid two file system hits, but we'll double-check by calling Exists
- if (Path.HasExtension(path))
- {
- var fileInfo = new FileInfo(path);
-
- if (fileInfo.Exists)
- {
- return GetFileSystemMetadata(fileInfo);
- }
-
- return GetFileSystemMetadata(new DirectoryInfo(path));
- }
- else
- {
- var fileInfo = new DirectoryInfo(path);
-
- if (fileInfo.Exists)
- {
- return GetFileSystemMetadata(fileInfo);
- }
-
- return GetFileSystemMetadata(new FileInfo(path));
- }
- }
-
- /// <summary>
- /// Returns a <see cref="FileSystemMetadata"/> object for the specified file path.
- /// </summary>
- /// <param name="path">A path to a file.</param>
- /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
- /// <remarks><para>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's
- /// <see cref="FileSystemMetadata.IsDirectory"/> property and the <see cref="FileSystemMetadata.Exists"/> property will both be set to false.</para>
- /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks>
- public FileSystemMetadata GetFileInfo(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var fileInfo = new FileInfo(path);
-
- return GetFileSystemMetadata(fileInfo);
- }
-
- /// <summary>
- /// Returns a <see cref="FileSystemMetadata"/> object for the specified directory path.
- /// </summary>
- /// <param name="path">A path to a directory.</param>
- /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
- /// <remarks><para>If the specified path points to a file, the returned <see cref="FileSystemMetadata"/> object's
- /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and the <see cref="FileSystemMetadata.Exists"/> property will be set to false.</para>
- /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks>
- public FileSystemMetadata GetDirectoryInfo(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var fileInfo = new DirectoryInfo(path);
-
- return GetFileSystemMetadata(fileInfo);
- }
-
- private FileSystemMetadata GetFileSystemMetadata(FileSystemInfo info)
- {
- var result = new FileSystemMetadata();
-
- result.Exists = info.Exists;
- result.FullName = info.FullName;
- result.Extension = info.Extension;
- result.Name = info.Name;
-
- if (result.Exists)
- {
- var attributes = info.Attributes;
- result.IsDirectory = info is DirectoryInfo || (attributes & FileAttributes.Directory) == FileAttributes.Directory;
- result.IsHidden = (attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
- result.IsReadOnly = (attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly;
-
- var fileInfo = info as FileInfo;
- if (fileInfo != null)
- {
- result.Length = fileInfo.Length;
- result.DirectoryName = fileInfo.DirectoryName;
- }
-
- result.CreationTimeUtc = GetCreationTimeUtc(info);
- result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
- }
- else
- {
- result.IsDirectory = info is DirectoryInfo;
- }
-
- return result;
- }
-
- /// <summary>
- /// The space char
- /// </summary>
- private const char SpaceChar = ' ';
-
- /// <summary>
- /// Takes a filename and removes invalid characters
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentNullException">filename</exception>
- public string GetValidFilename(string filename)
- {
- if (string.IsNullOrEmpty(filename))
- {
- throw new ArgumentNullException("filename");
- }
-
- var builder = new StringBuilder(filename);
-
- foreach (var c in _invalidFileNameChars)
- {
- builder = builder.Replace(c, SpaceChar);
- }
-
- return builder.ToString();
- }
-
- /// <summary>
- /// Gets the creation time UTC.
- /// </summary>
- /// <param name="info">The info.</param>
- /// <returns>DateTime.</returns>
- public DateTime GetCreationTimeUtc(FileSystemInfo info)
- {
- // This could throw an error on some file systems that have dates out of range
- try
- {
- return info.CreationTimeUtc;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error determining CreationTimeUtc for {0}", ex, info.FullName);
- return DateTime.MinValue;
- }
- }
-
- /// <summary>
- /// Gets the creation time UTC.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>DateTime.</returns>
- public DateTime GetCreationTimeUtc(string path)
- {
- return GetCreationTimeUtc(GetFileSystemInfo(path));
- }
-
- public DateTime GetCreationTimeUtc(FileSystemMetadata info)
- {
- return info.CreationTimeUtc;
- }
-
- public DateTime GetLastWriteTimeUtc(FileSystemMetadata info)
- {
- return info.LastWriteTimeUtc;
- }
-
- /// <summary>
- /// Gets the creation time UTC.
- /// </summary>
- /// <param name="info">The info.</param>
- /// <returns>DateTime.</returns>
- public DateTime GetLastWriteTimeUtc(FileSystemInfo info)
- {
- // This could throw an error on some file systems that have dates out of range
- try
- {
- return info.LastWriteTimeUtc;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error determining LastAccessTimeUtc for {0}", ex, info.FullName);
- return DateTime.MinValue;
- }
- }
-
- /// <summary>
- /// Gets the last write time UTC.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>DateTime.</returns>
- public DateTime GetLastWriteTimeUtc(string path)
- {
- return GetLastWriteTimeUtc(GetFileSystemInfo(path));
- }
-
- /// <summary>
- /// Gets the file stream.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="mode">The mode.</param>
- /// <param name="access">The access.</param>
- /// <param name="share">The share.</param>
- /// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
- /// <returns>FileStream.</returns>
- public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false)
- {
- if (_supportsAsyncFileStreams && isAsync)
- {
- return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144, true);
- }
-
- return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144);
- }
-
- private FileMode GetFileMode(FileOpenMode mode)
- {
- switch (mode)
- {
- case FileOpenMode.Append:
- return FileMode.Append;
- case FileOpenMode.Create:
- return FileMode.Create;
- case FileOpenMode.CreateNew:
- return FileMode.CreateNew;
- case FileOpenMode.Open:
- return FileMode.Open;
- case FileOpenMode.OpenOrCreate:
- return FileMode.OpenOrCreate;
- case FileOpenMode.Truncate:
- return FileMode.Truncate;
- default:
- throw new Exception("Unrecognized FileOpenMode");
- }
- }
-
- private FileAccess GetFileAccess(FileAccessMode mode)
- {
- var val = (int)mode;
-
- return (FileAccess)val;
- }
-
- private FileShare GetFileShare(FileShareMode mode)
- {
- var val = (int)mode;
-
- return (FileShare)val;
- }
-
- public void SetHidden(string path, bool isHidden)
- {
- var info = GetFileInfo(path);
-
- if (info.Exists && info.IsHidden != isHidden)
- {
- if (isHidden)
- {
- FileAttributes attributes = File.GetAttributes(path);
- attributes = RemoveAttribute(attributes, FileAttributes.Hidden);
- File.SetAttributes(path, attributes);
- }
- else
- {
- File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Hidden);
- }
- }
- }
-
- private static FileAttributes RemoveAttribute(FileAttributes attributes, FileAttributes attributesToRemove)
- {
- return attributes & ~attributesToRemove;
- }
-
- /// <summary>
- /// Swaps the files.
- /// </summary>
- /// <param name="file1">The file1.</param>
- /// <param name="file2">The file2.</param>
- public void SwapFiles(string file1, string file2)
- {
- if (string.IsNullOrEmpty(file1))
- {
- throw new ArgumentNullException("file1");
- }
-
- if (string.IsNullOrEmpty(file2))
- {
- throw new ArgumentNullException("file2");
- }
-
- var temp1 = Path.GetTempFileName();
- var temp2 = Path.GetTempFileName();
-
- // Copying over will fail against hidden files
- RemoveHiddenAttribute(file1);
- RemoveHiddenAttribute(file2);
-
- CopyFile(file1, temp1, true);
- CopyFile(file2, temp2, true);
-
- CopyFile(temp1, file2, true);
- CopyFile(temp2, file1, true);
-
- DeleteFile(temp1);
- DeleteFile(temp2);
- }
-
- /// <summary>
- /// Removes the hidden attribute.
- /// </summary>
- /// <param name="path">The path.</param>
- private void RemoveHiddenAttribute(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var currentFile = new FileInfo(path);
-
- // This will fail if the file is hidden
- if (currentFile.Exists)
- {
- if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- {
- currentFile.Attributes &= ~FileAttributes.Hidden;
- }
- }
- }
-
- public bool ContainsSubPath(string parentPath, string path)
- {
- if (string.IsNullOrEmpty(parentPath))
- {
- throw new ArgumentNullException("parentPath");
- }
-
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- return path.IndexOf(parentPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) != -1;
- }
-
- public bool IsRootPath(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var parent = Path.GetDirectoryName(path);
-
- if (!string.IsNullOrEmpty(parent))
- {
- return false;
- }
-
- return true;
- }
-
- public string NormalizePath(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- if (path.EndsWith(":\\", StringComparison.OrdinalIgnoreCase))
- {
- return path;
- }
-
- return path.TrimEnd(Path.DirectorySeparatorChar);
- }
-
- public string GetFileNameWithoutExtension(FileSystemMetadata info)
- {
- if (info.IsDirectory)
- {
- return info.Name;
- }
-
- return Path.GetFileNameWithoutExtension(info.FullName);
- }
-
- public string GetFileNameWithoutExtension(string path)
- {
- return Path.GetFileNameWithoutExtension(path);
- }
-
- public bool IsPathFile(string path)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\
-
- if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 &&
- !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- return true;
-
- //return Path.IsPathRooted(path);
- }
-
- public void DeleteFile(string path)
- {
- File.Delete(path);
- }
-
- public void DeleteDirectory(string path, bool recursive)
- {
- Directory.Delete(path, recursive);
- }
-
- public void CreateDirectory(string path)
- {
- Directory.CreateDirectory(path);
- }
-
- public IEnumerable<FileSystemMetadata> GetDirectories(string path, bool recursive = false)
- {
- var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
-
- return ToMetadata(path, new DirectoryInfo(path).EnumerateDirectories("*", searchOption));
- }
-
- public IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false)
- {
- var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
-
- return ToMetadata(path, new DirectoryInfo(path).EnumerateFiles("*", searchOption));
- }
-
- public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false)
- {
- var directoryInfo = new DirectoryInfo(path);
- var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
-
- if (EnableFileSystemRequestConcat)
- {
- return ToMetadata(path, directoryInfo.EnumerateDirectories("*", searchOption))
- .Concat(ToMetadata(path, directoryInfo.EnumerateFiles("*", searchOption)));
- }
-
- return ToMetadata(path, directoryInfo.EnumerateFileSystemInfos("*", searchOption));
- }
-
- private IEnumerable<FileSystemMetadata> ToMetadata(string parentPath, IEnumerable<FileSystemInfo> infos)
- {
- return infos.Select(i =>
- {
- try
- {
- return GetFileSystemMetadata(i);
- }
- catch (PathTooLongException)
- {
- // Can't log using the FullName because it will throw the PathTooLongExceptiona again
- //Logger.Warn("Path too long: {0}", i.FullName);
- Logger.Warn("File or directory path too long. Parent folder: {0}", parentPath);
- return null;
- }
-
- }).Where(i => i != null);
- }
-
- public Stream OpenRead(string path)
- {
- return File.OpenRead(path);
- }
-
- public void CopyFile(string source, string target, bool overwrite)
- {
- File.Copy(source, target, overwrite);
- }
-
- public void MoveFile(string source, string target)
- {
- File.Move(source, target);
- }
-
- public void MoveDirectory(string source, string target)
- {
- Directory.Move(source, target);
- }
-
- public bool DirectoryExists(string path)
- {
- return Directory.Exists(path);
- }
-
- public bool FileExists(string path)
- {
- return File.Exists(path);
- }
-
- public string ReadAllText(string path)
- {
- return File.ReadAllText(path);
- }
-
- public byte[] ReadAllBytes(string path)
- {
- return File.ReadAllBytes(path);
- }
-
- public void WriteAllText(string path, string text, Encoding encoding)
- {
- File.WriteAllText(path, text, encoding);
- }
-
- public void WriteAllText(string path, string text)
- {
- File.WriteAllText(path, text);
- }
-
- public void WriteAllBytes(string path, byte[] bytes)
- {
- File.WriteAllBytes(path, bytes);
- }
-
- public string ReadAllText(string path, Encoding encoding)
- {
- return File.ReadAllText(path, encoding);
- }
-
- public IEnumerable<string> GetDirectoryPaths(string path, bool recursive = false)
- {
- var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
- return Directory.EnumerateDirectories(path, "*", searchOption);
- }
-
- public IEnumerable<string> GetFilePaths(string path, bool recursive = false)
- {
- var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
- return Directory.EnumerateFiles(path, "*", searchOption);
- }
-
- public IEnumerable<string> GetFileSystemEntryPaths(string path, bool recursive = false)
- {
- var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
- return Directory.EnumerateFileSystemEntries(path, "*", searchOption);
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/IO/WindowsFileSystem.cs b/MediaBrowser.Common.Implementations/IO/WindowsFileSystem.cs
deleted file mode 100644
index db386c682..000000000
--- a/MediaBrowser.Common.Implementations/IO/WindowsFileSystem.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Common.Implementations.IO
-{
- public class WindowsFileSystem : ManagedFileSystem
- {
- public WindowsFileSystem(ILogger logger)
- : base(logger, true, true)
- {
- EnableFileSystemRequestConcat = false;
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
deleted file mode 100644
index 89e9427ae..000000000
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>MediaBrowser.Common.Implementations</RootNamespace>
- <AssemblyName>MediaBrowser.Common.Implementations</AssemblyName>
- <FileAlignment>512</FileAlignment>
- <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <ProductVersion>10.0.0</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
- <TargetFrameworkProfile />
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>none</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Mono|AnyCPU' ">
- <DebugType>none</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release Mono\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup>
- <RunPostBuildEvent>Always</RunPostBuildEvent>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Configuration" />
- <Reference Include="System.Core" />
- <Reference Include="Microsoft.CSharp" />
- <Reference Include="System.Net" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="..\SharedVersion.cs">
- <Link>Properties\SharedVersion.cs</Link>
- </Compile>
- <Compile Include="BaseApplicationHost.cs" />
- <Compile Include="BaseApplicationPaths.cs" />
- <Compile Include="Configuration\BaseConfigurationManager.cs" />
- <Compile Include="Configuration\ConfigurationHelper.cs" />
- <Compile Include="Cryptography\CryptographyProvider.cs" />
- <Compile Include="Devices\DeviceId.cs" />
- <Compile Include="HttpClientManager\HttpClientInfo.cs" />
- <Compile Include="HttpClientManager\HttpClientManager.cs" />
- <Compile Include="IO\IsoManager.cs" />
- <Compile Include="IO\ManagedFileSystem.cs" />
- <Compile Include="IO\WindowsFileSystem.cs" />
- <Compile Include="Networking\BaseNetworkManager.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="ScheduledTasks\DailyTrigger.cs" />
- <Compile Include="ScheduledTasks\IntervalTrigger.cs" />
- <Compile Include="ScheduledTasks\ScheduledTaskWorker.cs" />
- <Compile Include="ScheduledTasks\StartupTrigger.cs" />
- <Compile Include="ScheduledTasks\SystemEventTrigger.cs" />
- <Compile Include="ScheduledTasks\TaskManager.cs" />
- <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" />
- <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" />
- <Compile Include="ScheduledTasks\Tasks\ReloadLoggerFileTask.cs" />
- <Compile Include="ScheduledTasks\WeeklyTrigger.cs" />
- <Compile Include="Serialization\XmlSerializer.cs" />
- <Compile Include="Updates\GithubUpdater.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
- <Name>MediaBrowser.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
- <Name>MediaBrowser.Model</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup />
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <PropertyGroup>
- <PostBuildEvent />
- </PropertyGroup>
- <PropertyGroup>
- <PostBuildEvent />
- </PropertyGroup>
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
deleted file mode 100644
index 5e00514d5..000000000
--- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
+++ /dev/null
@@ -1,385 +0,0 @@
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Net;
-using System.Net.NetworkInformation;
-using System.Net.Sockets;
-using MediaBrowser.Model.Extensions;
-
-namespace MediaBrowser.Common.Implementations.Networking
-{
- public abstract class BaseNetworkManager
- {
- protected ILogger Logger { get; private set; }
- private DateTime _lastRefresh;
-
- protected BaseNetworkManager(ILogger logger)
- {
- Logger = logger;
- }
-
- private List<IPAddress> _localIpAddresses;
- private readonly object _localIpAddressSyncLock = new object();
-
- /// <summary>
- /// Gets the machine's local ip address
- /// </summary>
- /// <returns>IPAddress.</returns>
- public IEnumerable<IPAddress> GetLocalIpAddresses()
- {
- const int cacheMinutes = 5;
-
- lock (_localIpAddressSyncLock)
- {
- var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes;
-
- if (_localIpAddresses == null || forceRefresh)
- {
- var addresses = GetLocalIpAddressesInternal().ToList();
-
- _localIpAddresses = addresses;
- _lastRefresh = DateTime.UtcNow;
-
- return addresses;
- }
- }
-
- return _localIpAddresses;
- }
-
- private IEnumerable<IPAddress> GetLocalIpAddressesInternal()
- {
- var list = GetIPsDefault()
- .ToList();
-
- if (list.Count == 0)
- {
- list.AddRange(GetLocalIpAddressesFallback());
- }
-
- return list.Where(FilterIpAddress).DistinctBy(i => i.ToString());
- }
-
- private bool FilterIpAddress(IPAddress address)
- {
- var addressString = address.ToString ();
-
- if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
-
- return true;
- }
-
- public bool IsInPrivateAddressSpace(string endpoint)
- {
- if (string.Equals(endpoint, "::1", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- // Handle ipv4 mapped to ipv6
- endpoint = endpoint.Replace("::ffff:", string.Empty);
-
- // Private address space:
- // http://en.wikipedia.org/wiki/Private_network
-
- if (endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase))
- {
- return Is172AddressPrivate(endpoint);
- }
-
- return
-
- endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
- }
-
- private bool Is172AddressPrivate(string endpoint)
- {
- for (var i = 16; i <= 31; i++)
- {
- if (endpoint.StartsWith("172." + i.ToString(CultureInfo.InvariantCulture) + ".", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- return false;
- }
-
- public bool IsInLocalNetwork(string endpoint)
- {
- return IsInLocalNetworkInternal(endpoint, true);
- }
-
- public bool IsInLocalNetworkInternal(string endpoint, bool resolveHost)
- {
- if (string.IsNullOrWhiteSpace(endpoint))
- {
- throw new ArgumentNullException("endpoint");
- }
-
- IPAddress address;
- if (IPAddress.TryParse(endpoint, out address))
- {
- var addressString = address.ToString();
-
- int lengthMatch = 100;
- if (address.AddressFamily == AddressFamily.InterNetwork)
- {
- lengthMatch = 4;
- if (IsInPrivateAddressSpace(addressString))
- {
- return true;
- }
- }
- else if (address.AddressFamily == AddressFamily.InterNetworkV6)
- {
- lengthMatch = 10;
- if (IsInPrivateAddressSpace(endpoint))
- {
- return true;
- }
- }
-
- // Should be even be doing this with ipv6?
- if (addressString.Length >= lengthMatch)
- {
- var prefix = addressString.Substring(0, lengthMatch);
-
- if (GetLocalIpAddresses().Any(i => i.ToString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
- {
- return true;
- }
- }
- }
- else if (resolveHost)
- {
- Uri uri;
- if (Uri.TryCreate(endpoint, UriKind.RelativeOrAbsolute, out uri))
- {
- try
- {
- var host = uri.DnsSafeHost;
- Logger.Debug("Resolving host {0}", host);
-
- address = GetIpAddresses(host).FirstOrDefault();
-
- if (address != null)
- {
- Logger.Debug("{0} resolved to {1}", host, address);
-
- return IsInLocalNetworkInternal(address.ToString(), false);
- }
- }
- catch (InvalidOperationException)
- {
- // Can happen with reverse proxy or IIS url rewriting
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error resovling hostname", ex);
- }
- }
- }
-
- return false;
- }
-
- public IEnumerable<IPAddress> GetIpAddresses(string hostName)
- {
- return Dns.GetHostAddresses(hostName);
- }
-
- private List<IPAddress> GetIPsDefault()
- {
- NetworkInterface[] interfaces;
-
- try
- {
- interfaces = NetworkInterface.GetAllNetworkInterfaces();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error in GetAllNetworkInterfaces", ex);
- return new List<IPAddress>();
- }
-
- return interfaces.SelectMany(network => {
-
- try
- {
- Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus);
-
- var properties = network.GetIPProperties();
-
- return properties.UnicastAddresses
- .Where(i => i.IsDnsEligible)
- .Select(i => i.Address)
- .Where(i => i.AddressFamily == AddressFamily.InterNetwork)
- .ToList();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error querying network interface", ex);
- return new List<IPAddress>();
- }
-
- }).DistinctBy(i => i.ToString())
- .ToList();
- }
-
- private IEnumerable<IPAddress> GetLocalIpAddressesFallback()
- {
- var host = Dns.GetHostEntry(Dns.GetHostName());
-
- // Reverse them because the last one is usually the correct one
- // It's not fool-proof so ultimately the consumer will have to examine them and decide
- return host.AddressList
- .Where(i => i.AddressFamily == AddressFamily.InterNetwork)
- .Reverse();
- }
-
- /// <summary>
- /// Gets a random port number that is currently available
- /// </summary>
- /// <returns>System.Int32.</returns>
- public int GetRandomUnusedPort()
- {
- var listener = new TcpListener(IPAddress.Any, 0);
- listener.Start();
- var port = ((IPEndPoint)listener.LocalEndpoint).Port;
- listener.Stop();
- return port;
- }
-
- /// <summary>
- /// Returns MAC Address from first Network Card in Computer
- /// </summary>
- /// <returns>[string] MAC Address</returns>
- public string GetMacAddress()
- {
- return NetworkInterface.GetAllNetworkInterfaces()
- .Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback)
- .Select(i => BitConverter.ToString(i.GetPhysicalAddress().GetAddressBytes()))
- .FirstOrDefault();
- }
-
- /// <summary>
- /// Parses the specified endpointstring.
- /// </summary>
- /// <param name="endpointstring">The endpointstring.</param>
- /// <returns>IPEndPoint.</returns>
- public IPEndPoint Parse(string endpointstring)
- {
- return Parse(endpointstring, -1);
- }
-
- /// <summary>
- /// Parses the specified endpointstring.
- /// </summary>
- /// <param name="endpointstring">The endpointstring.</param>
- /// <param name="defaultport">The defaultport.</param>
- /// <returns>IPEndPoint.</returns>
- /// <exception cref="System.ArgumentException">Endpoint descriptor may not be empty.</exception>
- /// <exception cref="System.FormatException"></exception>
- private static IPEndPoint Parse(string endpointstring, int defaultport)
- {
- if (String.IsNullOrEmpty(endpointstring)
- || endpointstring.Trim().Length == 0)
- {
- throw new ArgumentException("Endpoint descriptor may not be empty.");
- }
-
- if (defaultport != -1 &&
- (defaultport < IPEndPoint.MinPort
- || defaultport > IPEndPoint.MaxPort))
- {
- throw new ArgumentException(String.Format("Invalid default port '{0}'", defaultport));
- }
-
- string[] values = endpointstring.Split(new char[] { ':' });
- IPAddress ipaddy;
- int port = -1;
-
- //check if we have an IPv6 or ports
- if (values.Length <= 2) // ipv4 or hostname
- {
- port = values.Length == 1 ? defaultport : GetPort(values[1]);
-
- //try to use the address as IPv4, otherwise get hostname
- if (!IPAddress.TryParse(values[0], out ipaddy))
- ipaddy = GetIPfromHost(values[0]);
- }
- else if (values.Length > 2) //ipv6
- {
- //could [a:b:c]:d
- if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]"))
- {
- string ipaddressstring = String.Join(":", values.Take(values.Length - 1).ToArray());
- ipaddy = IPAddress.Parse(ipaddressstring);
- port = GetPort(values[values.Length - 1]);
- }
- else //[a:b:c] or a:b:c
- {
- ipaddy = IPAddress.Parse(endpointstring);
- port = defaultport;
- }
- }
- else
- {
- throw new FormatException(String.Format("Invalid endpoint ipaddress '{0}'", endpointstring));
- }
-
- if (port == -1)
- throw new ArgumentException(String.Format("No port specified: '{0}'", endpointstring));
-
- return new IPEndPoint(ipaddy, port);
- }
-
- protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Gets the port.
- /// </summary>
- /// <param name="p">The p.</param>
- /// <returns>System.Int32.</returns>
- /// <exception cref="System.FormatException"></exception>
- private static int GetPort(string p)
- {
- int port;
-
- if (!Int32.TryParse(p, out port)
- || port < IPEndPoint.MinPort
- || port > IPEndPoint.MaxPort)
- {
- throw new FormatException(String.Format("Invalid end point port '{0}'", p));
- }
-
- return port;
- }
-
- /// <summary>
- /// Gets the I pfrom host.
- /// </summary>
- /// <param name="p">The p.</param>
- /// <returns>IPAddress.</returns>
- /// <exception cref="System.ArgumentException"></exception>
- private static IPAddress GetIPfromHost(string p)
- {
- var hosts = Dns.GetHostAddresses(p);
-
- if (hosts == null || hosts.Length == 0)
- throw new ArgumentException(String.Format("Host not found: {0}", p));
-
- return hosts[0];
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs b/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs
deleted file mode 100644
index 63a83e003..000000000
--- a/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System.Reflection;
-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/DailyTrigger.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/DailyTrigger.cs
deleted file mode 100644
index ab1d8f02d..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/DailyTrigger.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System;
-using System.Globalization;
-using System.Threading;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks
-{
- /// <summary>
- /// Represents a task trigger that fires everyday
- /// </summary>
- public class DailyTrigger : ITaskTrigger
- {
- /// <summary>
- /// Get the time of day to trigger the task to run
- /// </summary>
- /// <value>The time of day.</value>
- public TimeSpan TimeOfDay { get; set; }
-
- /// <summary>
- /// Gets or sets the timer.
- /// </summary>
- /// <value>The timer.</value>
- private Timer Timer { get; set; }
-
- /// <summary>
- /// Gets the execution properties of this task.
- /// </summary>
- /// <value>
- /// The execution properties of this task.
- /// </value>
- public TaskExecutionOptions TaskOptions { get; set; }
-
- /// <summary>
- /// Stars waiting for the trigger action
- /// </summary>
- /// <param name="lastResult">The last result.</param>
- /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
- {
- DisposeTimer();
-
- var now = DateTime.Now;
-
- var triggerDate = now.TimeOfDay > TimeOfDay ? now.Date.AddDays(1) : now.Date;
- triggerDate = triggerDate.Add(TimeOfDay);
-
- var dueTime = triggerDate - now;
-
- logger.Info("Daily trigger for {0} set to fire at {1}, which is {2} minutes from now.", taskName, triggerDate.ToString(), dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture));
-
- Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
- }
-
- /// <summary>
- /// Stops waiting for the trigger action
- /// </summary>
- public void Stop()
- {
- DisposeTimer();
- }
-
- /// <summary>
- /// Disposes the timer.
- /// </summary>
- private void DisposeTimer()
- {
- if (Timer != null)
- {
- Timer.Dispose();
- }
- }
-
- /// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
-
- /// <summary>
- /// Called when [triggered].
- /// </summary>
- private void OnTriggered()
- {
- if (Triggered != null)
- {
- Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/IntervalTrigger.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/IntervalTrigger.cs
deleted file mode 100644
index 251e460cb..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/IntervalTrigger.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-using System;
-using System.Linq;
-using System.Threading;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks
-{
- /// <summary>
- /// Represents a task trigger that runs repeatedly on an interval
- /// </summary>
- public class IntervalTrigger : ITaskTrigger
- {
- /// <summary>
- /// Gets or sets the interval.
- /// </summary>
- /// <value>The interval.</value>
- public TimeSpan Interval { get; set; }
-
- /// <summary>
- /// Gets or sets the timer.
- /// </summary>
- /// <value>The timer.</value>
- private Timer Timer { get; set; }
-
- /// <summary>
- /// Gets the execution properties of this task.
- /// </summary>
- /// <value>
- /// The execution properties of this task.
- /// </value>
- public TaskExecutionOptions TaskOptions { get; set; }
-
- private DateTime _lastStartDate;
-
- /// <summary>
- /// Stars waiting for the trigger action
- /// </summary>
- /// <param name="lastResult">The last result.</param>
- /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
- {
- DisposeTimer();
-
- DateTime triggerDate;
-
- if (lastResult == null)
- {
- // Task has never been completed before
- triggerDate = DateTime.UtcNow.AddHours(1);
- }
- else
- {
- triggerDate = new[] { lastResult.EndTimeUtc, _lastStartDate }.Max().Add(Interval);
- }
-
- if (DateTime.UtcNow > triggerDate)
- {
- triggerDate = DateTime.UtcNow.AddMinutes(1);
- }
-
- var dueTime = triggerDate - DateTime.UtcNow;
- var maxDueTime = TimeSpan.FromDays(7);
-
- if (dueTime > maxDueTime)
- {
- dueTime = maxDueTime;
- }
-
- Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
- }
-
- /// <summary>
- /// Stops waiting for the trigger action
- /// </summary>
- public void Stop()
- {
- DisposeTimer();
- }
-
- /// <summary>
- /// Disposes the timer.
- /// </summary>
- private void DisposeTimer()
- {
- if (Timer != null)
- {
- Timer.Dispose();
- }
- }
-
- /// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
-
- /// <summary>
- /// Called when [triggered].
- /// </summary>
- private void OnTriggered()
- {
- DisposeTimer();
-
- if (Triggered != null)
- {
- _lastStartDate = DateTime.UtcNow;
- Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
deleted file mode 100644
index 0d99283c3..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ /dev/null
@@ -1,781 +0,0 @@
-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;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks
-{
- /// <summary>
- /// Class ScheduledTaskWorker
- /// </summary>
- public class ScheduledTaskWorker : IScheduledTaskWorker
- {
- public event EventHandler<GenericEventArgs<double>> TaskProgress;
-
- /// <summary>
- /// Gets or sets the scheduled task.
- /// </summary>
- /// <value>The scheduled task.</value>
- public IScheduledTask ScheduledTask { get; private set; }
-
- /// <summary>
- /// Gets or sets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- private IJsonSerializer JsonSerializer { get; set; }
-
- /// <summary>
- /// Gets or sets the application paths.
- /// </summary>
- /// <value>The application paths.</value>
- private IApplicationPaths ApplicationPaths { get; set; }
-
- /// <summary>
- /// Gets the logger.
- /// </summary>
- /// <value>The logger.</value>
- private ILogger Logger { get; set; }
-
- /// <summary>
- /// Gets the task manager.
- /// </summary>
- /// <value>The task manager.</value>
- private ITaskManager TaskManager { get; set; }
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class.
- /// </summary>
- /// <param name="scheduledTask">The scheduled task.</param>
- /// <param name="applicationPaths">The application paths.</param>
- /// <param name="taskManager">The task manager.</param>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="logger">The logger.</param>
- /// <exception cref="System.ArgumentNullException">
- /// scheduledTask
- /// or
- /// applicationPaths
- /// or
- /// taskManager
- /// or
- /// jsonSerializer
- /// or
- /// logger
- /// </exception>
- public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger, IFileSystem fileSystem)
- {
- if (scheduledTask == null)
- {
- throw new ArgumentNullException("scheduledTask");
- }
- if (applicationPaths == null)
- {
- throw new ArgumentNullException("applicationPaths");
- }
- if (taskManager == null)
- {
- throw new ArgumentNullException("taskManager");
- }
- if (jsonSerializer == null)
- {
- throw new ArgumentNullException("jsonSerializer");
- }
- if (logger == null)
- {
- throw new ArgumentNullException("logger");
- }
-
- ScheduledTask = scheduledTask;
- ApplicationPaths = applicationPaths;
- TaskManager = taskManager;
- JsonSerializer = jsonSerializer;
- Logger = logger;
- _fileSystem = fileSystem;
-
- InitTriggerEvents();
- }
-
- private bool _readFromFile = false;
- /// <summary>
- /// The _last execution result
- /// </summary>
- private TaskResult _lastExecutionResult;
- /// <summary>
- /// The _last execution result sync lock
- /// </summary>
- private readonly object _lastExecutionResultSyncLock = new object();
- /// <summary>
- /// Gets the last execution result.
- /// </summary>
- /// <value>The last execution result.</value>
- public TaskResult LastExecutionResult
- {
- get
- {
- var path = GetHistoryFilePath();
-
- lock (_lastExecutionResultSyncLock)
- {
- if (_lastExecutionResult == null && !_readFromFile)
- {
- try
- {
- _lastExecutionResult = JsonSerializer.DeserializeFromFile<TaskResult>(path);
- }
- catch (DirectoryNotFoundException)
- {
- // File doesn't exist. No biggie
- }
- catch (FileNotFoundException)
- {
- // File doesn't exist. No biggie
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error deserializing {0}", ex, path);
- }
- _readFromFile = true;
- }
- }
-
- return _lastExecutionResult;
- }
- private set
- {
- _lastExecutionResult = value;
-
- var path = GetHistoryFilePath();
- _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
-
- lock (_lastExecutionResultSyncLock)
- {
- JsonSerializer.SerializeToFile(value, path);
- }
- }
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ScheduledTask.Name; }
- }
-
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
- public string Description
- {
- get { return ScheduledTask.Description; }
- }
-
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
- public string Category
- {
- get { return ScheduledTask.Category; }
- }
-
- /// <summary>
- /// Gets the current cancellation token
- /// </summary>
- /// <value>The current cancellation token source.</value>
- private CancellationTokenSource CurrentCancellationTokenSource { get; set; }
-
- /// <summary>
- /// Gets or sets the current execution start time.
- /// </summary>
- /// <value>The current execution start time.</value>
- private DateTime CurrentExecutionStartTime { get; set; }
-
- /// <summary>
- /// Gets the state.
- /// </summary>
- /// <value>The state.</value>
- public TaskState State
- {
- get
- {
- if (CurrentCancellationTokenSource != null)
- {
- return CurrentCancellationTokenSource.IsCancellationRequested
- ? TaskState.Cancelling
- : TaskState.Running;
- }
-
- return TaskState.Idle;
- }
- }
-
- /// <summary>
- /// Gets the current progress.
- /// </summary>
- /// <value>The current progress.</value>
- public double? CurrentProgress { get; private set; }
-
- /// <summary>
- /// The _triggers
- /// </summary>
- private Tuple<TaskTriggerInfo,ITaskTrigger>[] _triggers;
- /// <summary>
- /// Gets the triggers that define when the task will run
- /// </summary>
- /// <value>The triggers.</value>
- private Tuple<TaskTriggerInfo, ITaskTrigger>[] InternalTriggers
- {
- get
- {
- return _triggers;
- }
- set
- {
- if (value == null)
- {
- throw new ArgumentNullException("value");
- }
-
- // Cleanup current triggers
- if (_triggers != null)
- {
- DisposeTriggers();
- }
-
- _triggers = value.ToArray();
-
- ReloadTriggerEvents(false);
- }
- }
-
- /// <summary>
- /// Gets the triggers that define when the task will run
- /// </summary>
- /// <value>The triggers.</value>
- /// <exception cref="System.ArgumentNullException">value</exception>
- public TaskTriggerInfo[] Triggers
- {
- get
- {
- return InternalTriggers.Select(i => i.Item1).ToArray();
- }
- set
- {
- if (value == null)
- {
- throw new ArgumentNullException("value");
- }
-
- SaveTriggers(value);
-
- InternalTriggers = value.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
- }
- }
-
- /// <summary>
- /// The _id
- /// </summary>
- private string _id;
-
- /// <summary>
- /// Gets the unique id.
- /// </summary>
- /// <value>The unique id.</value>
- public string Id
- {
- get
- {
- if (_id == null)
- {
- _id = ScheduledTask.GetType().FullName.GetMD5().ToString("N");
- }
-
- return _id;
- }
- }
-
- private void InitTriggerEvents()
- {
- _triggers = LoadTriggers();
- ReloadTriggerEvents(true);
- }
-
- public void ReloadTriggerEvents()
- {
- ReloadTriggerEvents(false);
- }
-
- /// <summary>
- /// Reloads the trigger events.
- /// </summary>
- /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- private void ReloadTriggerEvents(bool isApplicationStartup)
- {
- foreach (var triggerInfo in InternalTriggers)
- {
- var trigger = triggerInfo.Item2;
-
- trigger.Stop();
-
- trigger.Triggered -= trigger_Triggered;
- trigger.Triggered += trigger_Triggered;
- trigger.Start(LastExecutionResult, Logger, Name, isApplicationStartup);
- }
- }
-
- /// <summary>
- /// Handles the Triggered event of the trigger control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- async void trigger_Triggered(object sender, GenericEventArgs<TaskExecutionOptions> e)
- {
- var trigger = (ITaskTrigger)sender;
-
- var configurableTask = ScheduledTask as IConfigurableScheduledTask;
-
- if (configurableTask != null && !configurableTask.IsEnabled)
- {
- return;
- }
-
- Logger.Info("{0} fired for task: {1}", trigger.GetType().Name, Name);
-
- trigger.Stop();
-
- TaskManager.QueueScheduledTask(ScheduledTask, e.Argument);
-
- await Task.Delay(1000).ConfigureAwait(false);
-
- trigger.Start(LastExecutionResult, Logger, Name, false);
- }
-
- private Task _currentTask;
-
- /// <summary>
- /// Executes the task
- /// </summary>
- /// <param name="options">Task options.</param>
- /// <returns>Task.</returns>
- /// <exception cref="System.InvalidOperationException">Cannot execute a Task that is already running</exception>
- public async Task Execute(TaskExecutionOptions options)
- {
- var task = ExecuteInternal(options);
-
- _currentTask = task;
-
- try
- {
- await task.ConfigureAwait(false);
- }
- finally
- {
- _currentTask = null;
- }
- }
-
- private async Task ExecuteInternal(TaskExecutionOptions options)
- {
- // Cancel the current execution, if any
- if (CurrentCancellationTokenSource != null)
- {
- throw new InvalidOperationException("Cannot execute a Task that is already running");
- }
-
- var progress = new Progress<double>();
-
- CurrentCancellationTokenSource = new CancellationTokenSource();
-
- Logger.Info("Executing {0}", Name);
-
- ((TaskManager)TaskManager).OnTaskExecuting(this);
-
- progress.ProgressChanged += progress_ProgressChanged;
-
- TaskCompletionStatus status;
- CurrentExecutionStartTime = DateTime.UtcNow;
-
- Exception failureException = null;
-
- try
- {
- if (options != null && options.MaxRuntimeMs.HasValue)
- {
- CurrentCancellationTokenSource.CancelAfter(options.MaxRuntimeMs.Value);
- }
-
- var localTask = ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress);
-
- await localTask.ConfigureAwait(false);
-
- status = TaskCompletionStatus.Completed;
- }
- catch (OperationCanceledException)
- {
- status = TaskCompletionStatus.Cancelled;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error", ex);
-
- failureException = ex;
-
- status = TaskCompletionStatus.Failed;
- }
-
- var startTime = CurrentExecutionStartTime;
- var endTime = DateTime.UtcNow;
-
- progress.ProgressChanged -= progress_ProgressChanged;
- CurrentCancellationTokenSource.Dispose();
- CurrentCancellationTokenSource = null;
- CurrentProgress = null;
-
- OnTaskCompleted(startTime, endTime, status, failureException);
- }
-
- /// <summary>
- /// Progress_s the progress changed.
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The e.</param>
- void progress_ProgressChanged(object sender, double e)
- {
- CurrentProgress = e;
-
- EventHelper.FireEventIfNotNull(TaskProgress, this, new GenericEventArgs<double>
- {
- Argument = e
-
- }, Logger);
- }
-
- /// <summary>
- /// Stops the task if it is currently executing
- /// </summary>
- /// <exception cref="System.InvalidOperationException">Cannot cancel a Task unless it is in the Running state.</exception>
- public void Cancel()
- {
- if (State != TaskState.Running)
- {
- throw new InvalidOperationException("Cannot cancel a Task unless it is in the Running state.");
- }
-
- CancelIfRunning();
- }
-
- /// <summary>
- /// Cancels if running.
- /// </summary>
- public void CancelIfRunning()
- {
- if (State == TaskState.Running)
- {
- Logger.Info("Attempting to cancel Scheduled Task {0}", Name);
- CurrentCancellationTokenSource.Cancel();
- }
- }
-
- /// <summary>
- /// Gets the scheduled tasks configuration directory.
- /// </summary>
- /// <returns>System.String.</returns>
- private string GetScheduledTasksConfigurationDirectory()
- {
- return Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
- }
-
- /// <summary>
- /// Gets the scheduled tasks data directory.
- /// </summary>
- /// <returns>System.String.</returns>
- private string GetScheduledTasksDataDirectory()
- {
- return Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks");
- }
-
- /// <summary>
- /// Gets the history file path.
- /// </summary>
- /// <value>The history file path.</value>
- private string GetHistoryFilePath()
- {
- return Path.Combine(GetScheduledTasksDataDirectory(), new Guid(Id) + ".js");
- }
-
- /// <summary>
- /// Gets the configuration file path.
- /// </summary>
- /// <returns>System.String.</returns>
- private string GetConfigurationFilePath()
- {
- return Path.Combine(GetScheduledTasksConfigurationDirectory(), new Guid(Id) + ".js");
- }
-
- /// <summary>
- /// Loads the triggers.
- /// </summary>
- /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- private Tuple<TaskTriggerInfo, ITaskTrigger>[] LoadTriggers()
- {
- var settings = LoadTriggerSettings();
-
- return settings.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
- }
-
- private TaskTriggerInfo[] LoadTriggerSettings()
- {
- try
- {
- return JsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath())
- .ToArray();
- }
- catch (FileNotFoundException)
- {
- // File doesn't exist. No biggie. Return defaults.
- return ScheduledTask.GetDefaultTriggers().ToArray();
- }
- catch (DirectoryNotFoundException)
- {
- // File doesn't exist. No biggie. Return defaults.
- return ScheduledTask.GetDefaultTriggers().ToArray();
- }
- }
-
- /// <summary>
- /// Saves the triggers.
- /// </summary>
- /// <param name="triggers">The triggers.</param>
- private void SaveTriggers(TaskTriggerInfo[] triggers)
- {
- var path = GetConfigurationFilePath();
-
- _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
-
- JsonSerializer.SerializeToFile(triggers, path);
- }
-
- /// <summary>
- /// Called when [task completed].
- /// </summary>
- /// <param name="startTime">The start time.</param>
- /// <param name="endTime">The end time.</param>
- /// <param name="status">The status.</param>
- private void OnTaskCompleted(DateTime startTime, DateTime endTime, TaskCompletionStatus status, Exception ex)
- {
- 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
- };
-
- result.Key = ScheduledTask.Key;
-
- if (ex != null)
- {
- result.ErrorMessage = ex.Message;
- result.LongErrorMessage = ex.StackTrace;
- }
-
- LastExecutionResult = result;
-
- ((TaskManager)TaskManager).OnTaskCompleted(this, result);
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- DisposeTriggers();
-
- var wassRunning = State == TaskState.Running;
- var startTime = CurrentExecutionStartTime;
-
- var token = CurrentCancellationTokenSource;
- if (token != null)
- {
- try
- {
- Logger.Info(Name + ": Cancelling");
- token.Cancel();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error calling CancellationToken.Cancel();", ex);
- }
- }
- var task = _currentTask;
- if (task != null)
- {
- try
- {
- Logger.Info(Name + ": Waiting on Task");
- var exited = Task.WaitAll(new[] { task }, 2000);
-
- if (exited)
- {
- Logger.Info(Name + ": Task exited");
- }
- else
- {
- Logger.Info(Name + ": Timed out waiting for task to stop");
- }
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error calling Task.WaitAll();", ex);
- }
- }
-
- if (token != null)
- {
- try
- {
- Logger.Debug(Name + ": Disposing CancellationToken");
- token.Dispose();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error calling CancellationToken.Dispose();", ex);
- }
- }
- if (wassRunning)
- {
- OnTaskCompleted(startTime, DateTime.UtcNow, TaskCompletionStatus.Aborted, null);
- }
- }
- }
-
- /// <summary>
- /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger
- /// </summary>
- /// <param name="info">The info.</param>
- /// <returns>BaseTaskTrigger.</returns>
- /// <exception cref="System.ArgumentNullException"></exception>
- /// <exception cref="System.ArgumentException">Invalid trigger type: + info.Type</exception>
- public static ITaskTrigger GetTrigger(TaskTriggerInfo info)
- {
- var options = new TaskExecutionOptions
- {
- MaxRuntimeMs = info.MaxRuntimeMs
- };
-
- if (info.Type.Equals(typeof(DailyTrigger).Name, StringComparison.OrdinalIgnoreCase))
- {
- if (!info.TimeOfDayTicks.HasValue)
- {
- throw new ArgumentNullException();
- }
-
- return new DailyTrigger
- {
- TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value),
- TaskOptions = options
- };
- }
-
- if (info.Type.Equals(typeof(WeeklyTrigger).Name, StringComparison.OrdinalIgnoreCase))
- {
- if (!info.TimeOfDayTicks.HasValue)
- {
- throw new ArgumentNullException();
- }
-
- if (!info.DayOfWeek.HasValue)
- {
- throw new ArgumentNullException();
- }
-
- return new WeeklyTrigger
- {
- TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value),
- DayOfWeek = info.DayOfWeek.Value,
- TaskOptions = options
- };
- }
-
- if (info.Type.Equals(typeof(IntervalTrigger).Name, StringComparison.OrdinalIgnoreCase))
- {
- if (!info.IntervalTicks.HasValue)
- {
- throw new ArgumentNullException();
- }
-
- return new IntervalTrigger
- {
- Interval = TimeSpan.FromTicks(info.IntervalTicks.Value),
- TaskOptions = options
- };
- }
-
- if (info.Type.Equals(typeof(SystemEventTrigger).Name, StringComparison.OrdinalIgnoreCase))
- {
- if (!info.SystemEvent.HasValue)
- {
- throw new ArgumentNullException();
- }
-
- return new SystemEventTrigger
- {
- SystemEvent = info.SystemEvent.Value,
- TaskOptions = options
- };
- }
-
- if (info.Type.Equals(typeof(StartupTrigger).Name, StringComparison.OrdinalIgnoreCase))
- {
- return new StartupTrigger();
- }
-
- throw new ArgumentException("Unrecognized trigger type: " + info.Type);
- }
-
- /// <summary>
- /// Disposes each trigger
- /// </summary>
- private void DisposeTriggers()
- {
- foreach (var triggerInfo in InternalTriggers)
- {
- var trigger = triggerInfo.Item2;
- trigger.Triggered -= trigger_Triggered;
- trigger.Stop();
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/StartupTrigger.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/StartupTrigger.cs
deleted file mode 100644
index c96a41ac8..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/StartupTrigger.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks
-{
- /// <summary>
- /// Class StartupTaskTrigger
- /// </summary>
- public class StartupTrigger : ITaskTrigger
- {
- public int DelayMs { get; set; }
-
- /// <summary>
- /// Gets the execution properties of this task.
- /// </summary>
- /// <value>
- /// The execution properties of this task.
- /// </value>
- public TaskExecutionOptions TaskOptions { get; set; }
-
- public StartupTrigger()
- {
- DelayMs = 3000;
- }
-
- /// <summary>
- /// Stars waiting for the trigger action
- /// </summary>
- /// <param name="lastResult">The last result.</param>
- /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public async void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
- {
- if (isApplicationStartup)
- {
- await Task.Delay(DelayMs).ConfigureAwait(false);
-
- OnTriggered();
- }
- }
-
- /// <summary>
- /// Stops waiting for the trigger action
- /// </summary>
- public void Stop()
- {
- }
-
- /// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
-
- /// <summary>
- /// Called when [triggered].
- /// </summary>
- private void OnTriggered()
- {
- if (Triggered != null)
- {
- Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/SystemEventTrigger.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/SystemEventTrigger.cs
deleted file mode 100644
index 9972dc804..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/SystemEventTrigger.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Tasks;
-using Microsoft.Win32;
-using System;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Common.ScheduledTasks
-{
- /// <summary>
- /// Class SystemEventTrigger
- /// </summary>
- public class SystemEventTrigger : ITaskTrigger
- {
- /// <summary>
- /// Gets or sets the system event.
- /// </summary>
- /// <value>The system event.</value>
- public SystemEvent SystemEvent { get; set; }
-
- /// <summary>
- /// Gets the execution properties of this task.
- /// </summary>
- /// <value>
- /// The execution properties of this task.
- /// </value>
- public TaskExecutionOptions TaskOptions { get; set; }
-
- /// <summary>
- /// Stars waiting for the trigger action
- /// </summary>
- /// <param name="lastResult">The last result.</param>
- /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
- {
- switch (SystemEvent)
- {
- case SystemEvent.WakeFromSleep:
- SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
- break;
- }
- }
-
- /// <summary>
- /// Stops waiting for the trigger action
- /// </summary>
- public void Stop()
- {
- SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
- }
-
- /// <summary>
- /// Handles the PowerModeChanged event of the SystemEvents control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="PowerModeChangedEventArgs" /> instance containing the event data.</param>
- async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
- {
- if (e.Mode == PowerModes.Resume && SystemEvent == SystemEvent.WakeFromSleep)
- {
- // This value is a bit arbitrary, but add a delay to help ensure network connections have been restored before running the task
- await Task.Delay(10000).ConfigureAwait(false);
-
- OnTriggered();
- }
- }
-
- /// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
-
- /// <summary>
- /// Called when [triggered].
- /// </summary>
- private void OnTriggered()
- {
- if (Triggered != null)
- {
- Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
deleted file mode 100644
index 5c721d915..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
+++ /dev/null
@@ -1,361 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Tasks;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.System;
-using Microsoft.Win32;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks
-{
- /// <summary>
- /// Class TaskManager
- /// </summary>
- public class TaskManager : ITaskManager
- {
- public event EventHandler<GenericEventArgs<IScheduledTaskWorker>> TaskExecuting;
- public event EventHandler<TaskCompletionEventArgs> TaskCompleted;
-
- /// <summary>
- /// Gets the list of Scheduled Tasks
- /// </summary>
- /// <value>The scheduled tasks.</value>
- public IScheduledTaskWorker[] ScheduledTasks { get; private set; }
-
- /// <summary>
- /// The _task queue
- /// </summary>
- private readonly ConcurrentQueue<Tuple<Type, TaskExecutionOptions>> _taskQueue =
- new ConcurrentQueue<Tuple<Type, TaskExecutionOptions>>();
-
- /// <summary>
- /// Gets or sets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- private IJsonSerializer JsonSerializer { get; set; }
-
- /// <summary>
- /// Gets or sets the application paths.
- /// </summary>
- /// <value>The application paths.</value>
- private IApplicationPaths ApplicationPaths { get; set; }
-
- private readonly ISystemEvents _systemEvents;
-
- /// <summary>
- /// Gets the logger.
- /// </summary>
- /// <value>The logger.</value>
- private ILogger Logger { get; set; }
- private readonly IFileSystem _fileSystem;
-
- private bool _suspendTriggers;
-
- public bool SuspendTriggers
- {
- get { return _suspendTriggers; }
- set
- {
- Logger.Info("Setting SuspendTriggers to {0}", value);
- var executeQueued = _suspendTriggers && !value;
-
- _suspendTriggers = value;
-
- if (executeQueued)
- {
- ExecuteQueuedTasks();
- }
- }
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="TaskManager" /> class.
- /// </summary>
- /// <param name="applicationPaths">The application paths.</param>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="logger">The logger.</param>
- /// <exception cref="System.ArgumentException">kernel</exception>
- public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger, IFileSystem fileSystem, ISystemEvents systemEvents)
- {
- ApplicationPaths = applicationPaths;
- JsonSerializer = jsonSerializer;
- Logger = logger;
- _fileSystem = fileSystem;
- _systemEvents = systemEvents;
-
- ScheduledTasks = new IScheduledTaskWorker[] { };
- }
-
- private void BindToSystemEvent()
- {
- _systemEvents.Resume += _systemEvents_Resume;
- }
-
- private void _systemEvents_Resume(object sender, EventArgs e)
- {
- foreach (var task in ScheduledTasks)
- {
- task.ReloadTriggerEvents();
- }
- }
-
- /// <summary>
- /// Cancels if running and queue.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="options">Task options.</param>
- public void CancelIfRunningAndQueue<T>(TaskExecutionOptions options)
- where T : IScheduledTask
- {
- var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
- ((ScheduledTaskWorker)task).CancelIfRunning();
-
- QueueScheduledTask<T>(options);
- }
-
- public void CancelIfRunningAndQueue<T>()
- where T : IScheduledTask
- {
- CancelIfRunningAndQueue<T>(new TaskExecutionOptions());
- }
-
- /// <summary>
- /// Cancels if running
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public void CancelIfRunning<T>()
- where T : IScheduledTask
- {
- var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
- ((ScheduledTaskWorker)task).CancelIfRunning();
- }
-
- /// <summary>
- /// Queues the scheduled task.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="options">Task options</param>
- public void QueueScheduledTask<T>(TaskExecutionOptions options)
- where T : IScheduledTask
- {
- var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T));
-
- if (scheduledTask == null)
- {
- Logger.Error("Unable to find scheduled task of type {0} in QueueScheduledTask.", typeof(T).Name);
- }
- else
- {
- QueueScheduledTask(scheduledTask, options);
- }
- }
-
- public void QueueScheduledTask<T>()
- where T : IScheduledTask
- {
- QueueScheduledTask<T>(new TaskExecutionOptions());
- }
-
- public void QueueIfNotRunning<T>()
- where T : IScheduledTask
- {
- var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
-
- if (task.State != TaskState.Running)
- {
- QueueScheduledTask<T>(new TaskExecutionOptions());
- }
- }
-
- public void Execute<T>()
- where T : IScheduledTask
- {
- var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T));
-
- if (scheduledTask == null)
- {
- Logger.Error("Unable to find scheduled task of type {0} in Execute.", typeof(T).Name);
- }
- else
- {
- var type = scheduledTask.ScheduledTask.GetType();
-
- Logger.Info("Queueing task {0}", type.Name);
-
- lock (_taskQueue)
- {
- if (scheduledTask.State == TaskState.Idle)
- {
- Execute(scheduledTask, new TaskExecutionOptions());
- }
- }
- }
- }
-
- /// <summary>
- /// Queues the scheduled task.
- /// </summary>
- /// <param name="task">The task.</param>
- /// <param name="options">The task options.</param>
- public void QueueScheduledTask(IScheduledTask task, TaskExecutionOptions options)
- {
- var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == task.GetType());
-
- if (scheduledTask == null)
- {
- Logger.Error("Unable to find scheduled task of type {0} in QueueScheduledTask.", task.GetType().Name);
- }
- else
- {
- QueueScheduledTask(scheduledTask, options);
- }
- }
-
- /// <summary>
- /// Queues the scheduled task.
- /// </summary>
- /// <param name="task">The task.</param>
- /// <param name="options">The task options.</param>
- private void QueueScheduledTask(IScheduledTaskWorker task, TaskExecutionOptions options)
- {
- var type = task.ScheduledTask.GetType();
-
- Logger.Info("Queueing task {0}", type.Name);
-
- lock (_taskQueue)
- {
- if (task.State == TaskState.Idle && !SuspendTriggers)
- {
- Execute(task, options);
- return;
- }
-
- _taskQueue.Enqueue(new Tuple<Type, TaskExecutionOptions>(type, options));
- }
- }
-
- /// <summary>
- /// Adds the tasks.
- /// </summary>
- /// <param name="tasks">The tasks.</param>
- public void AddTasks(IEnumerable<IScheduledTask> tasks)
- {
- var myTasks = ScheduledTasks.ToList();
-
- var list = tasks.ToList();
- myTasks.AddRange(list.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, _fileSystem)));
-
- ScheduledTasks = myTasks.ToArray();
-
- BindToSystemEvent();
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- foreach (var task in ScheduledTasks)
- {
- task.Dispose();
- }
- }
-
- public void Cancel(IScheduledTaskWorker task)
- {
- ((ScheduledTaskWorker)task).Cancel();
- }
-
- public Task Execute(IScheduledTaskWorker task, TaskExecutionOptions options)
- {
- return ((ScheduledTaskWorker)task).Execute(options);
- }
-
- /// <summary>
- /// Called when [task executing].
- /// </summary>
- /// <param name="task">The task.</param>
- internal void OnTaskExecuting(IScheduledTaskWorker task)
- {
- EventHelper.FireEventIfNotNull(TaskExecuting, this, new GenericEventArgs<IScheduledTaskWorker>
- {
- Argument = task
-
- }, Logger);
- }
-
- /// <summary>
- /// Called when [task completed].
- /// </summary>
- /// <param name="task">The task.</param>
- /// <param name="result">The result.</param>
- internal void OnTaskCompleted(IScheduledTaskWorker task, TaskResult result)
- {
- EventHelper.FireEventIfNotNull(TaskCompleted, task, new TaskCompletionEventArgs
- {
- Result = result,
- Task = task
-
- }, Logger);
-
- ExecuteQueuedTasks();
- }
-
- /// <summary>
- /// Executes the queued tasks.
- /// </summary>
- private void ExecuteQueuedTasks()
- {
- if (SuspendTriggers)
- {
- return;
- }
-
- Logger.Info("ExecuteQueuedTasks");
-
- // Execute queued tasks
- lock (_taskQueue)
- {
- var list = new List<Tuple<Type, TaskExecutionOptions>>();
-
- Tuple<Type, TaskExecutionOptions> item;
- while (_taskQueue.TryDequeue(out item))
- {
- if (list.All(i => i.Item1 != item.Item1))
- {
- list.Add(item);
- }
- }
-
- foreach (var enqueuedType in list)
- {
- var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == enqueuedType.Item1);
-
- if (scheduledTask.State == TaskState.Idle)
- {
- Execute(scheduledTask, enqueuedType.Item2);
- }
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
deleted file mode 100644
index 2cd3f4c0f..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ /dev/null
@@ -1,217 +0,0 @@
-using MediaBrowser.Common.Configuration;
-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;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
-{
- /// <summary>
- /// Deletes old cache files
- /// </summary>
- public class DeleteCacheFileTask : IScheduledTask, IConfigurableScheduledTask
- {
- /// <summary>
- /// Gets or sets the application paths.
- /// </summary>
- /// <value>The application paths.</value>
- private IApplicationPaths ApplicationPaths { get; set; }
-
- private readonly ILogger _logger;
-
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
- /// </summary>
- public DeleteCacheFileTask(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
- {
- ApplicationPaths = appPaths;
- _logger = logger;
- _fileSystem = fileSystem;
- }
-
- /// <summary>
- /// Creates the triggers that define when the task will run
- /// </summary>
- /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
- {
- return new[] {
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
- };
- }
-
- /// <summary>
- /// Returns the task to be executed
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
- {
- var minDateModified = DateTime.UtcNow.AddDays(-30);
-
- try
- {
- DeleteCacheFilesFromDirectory(cancellationToken, ApplicationPaths.CachePath, minDateModified, progress);
- }
- catch (DirectoryNotFoundException)
- {
- // No biggie here. Nothing to delete
- }
-
- progress.Report(90);
-
- minDateModified = DateTime.UtcNow.AddDays(-1);
-
- try
- {
- DeleteCacheFilesFromDirectory(cancellationToken, ApplicationPaths.TempDirectory, minDateModified, progress);
- }
- catch (DirectoryNotFoundException)
- {
- // No biggie here. Nothing to delete
- }
-
- return Task.FromResult(true);
- }
-
-
- /// <summary>
- /// Deletes the cache files from directory with a last write time less than a given date
- /// </summary>
- /// <param name="cancellationToken">The task cancellation token.</param>
- /// <param name="directory">The directory.</param>
- /// <param name="minDateModified">The min date modified.</param>
- /// <param name="progress">The progress.</param>
- private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
- {
- var filesToDelete = _fileSystem.GetFiles(directory, true)
- .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
- .ToList();
-
- var index = 0;
-
- foreach (var file in filesToDelete)
- {
- double percent = index;
- percent /= filesToDelete.Count;
-
- progress.Report(100 * percent);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- DeleteFile(file.FullName);
-
- index++;
- }
-
- DeleteEmptyFolders(directory);
-
- progress.Report(100);
- }
-
- private void DeleteEmptyFolders(string parent)
- {
- foreach (var directory in _fileSystem.GetDirectoryPaths(parent))
- {
- DeleteEmptyFolders(directory);
- if (!_fileSystem.GetFileSystemEntryPaths(directory).Any())
- {
- try
- {
- _fileSystem.DeleteDirectory(directory, false);
- }
- catch (UnauthorizedAccessException ex)
- {
- _logger.ErrorException("Error deleting directory {0}", ex, directory);
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error deleting directory {0}", ex, directory);
- }
- }
- }
- }
-
- private void DeleteFile(string path)
- {
- try
- {
- _fileSystem.DeleteFile(path);
- }
- catch (UnauthorizedAccessException ex)
- {
- _logger.ErrorException("Error deleting file {0}", ex, path);
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error deleting file {0}", ex, path);
- }
- }
-
- /// <summary>
- /// Gets the name of the task
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return "Cache file cleanup"; }
- }
-
- public string Key
- {
- get { return "DeleteCacheFiles"; }
- }
-
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
- public string Description
- {
- get { return "Deletes cache files no longer needed by the system"; }
- }
-
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
- public string Category
- {
- get
- {
- return "Maintenance";
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance is hidden.
- /// </summary>
- /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
- public bool IsHidden
- {
- get { return true; }
- }
-
- public bool IsEnabled
- {
- get { return true; }
- }
-
- public bool IsLogged
- {
- get { return true; }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
deleted file mode 100644
index 336f91f96..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.ScheduledTasks;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
-{
- /// <summary>
- /// Deletes old log files
- /// </summary>
- public class DeleteLogFileTask : IScheduledTask, IConfigurableScheduledTask
- {
- /// <summary>
- /// Gets or sets the configuration manager.
- /// </summary>
- /// <value>The configuration manager.</value>
- private IConfigurationManager ConfigurationManager { get; set; }
-
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DeleteLogFileTask" /> class.
- /// </summary>
- /// <param name="configurationManager">The configuration manager.</param>
- public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem)
- {
- ConfigurationManager = configurationManager;
- _fileSystem = fileSystem;
- }
-
- /// <summary>
- /// Creates the triggers that define when the task will run
- /// </summary>
- /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
- {
- return new[] {
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
- };
- }
-
- /// <summary>
- /// Returns the task to be executed
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
- {
- // Delete log files more than n days old
- var minDateModified = DateTime.UtcNow.AddDays(-ConfigurationManager.CommonConfiguration.LogFileRetentionDays);
-
- var filesToDelete = _fileSystem.GetFiles(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, true)
- .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
- .ToList();
-
- var index = 0;
-
- foreach (var file in filesToDelete)
- {
- double percent = index;
- percent /= filesToDelete.Count;
-
- progress.Report(100 * percent);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- _fileSystem.DeleteFile(file.FullName);
-
- index++;
- }
-
- progress.Report(100);
-
- return Task.FromResult(true);
- }
-
- public string Key
- {
- get { return "CleanLogFiles"; }
- }
-
- /// <summary>
- /// Gets the name of the task
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return "Log file cleanup"; }
- }
-
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
- public string Description
- {
- get { return string.Format("Deletes log files that are more than {0} days old.", ConfigurationManager.CommonConfiguration.LogFileRetentionDays); }
- }
-
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
- public string Category
- {
- get
- {
- return "Maintenance";
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance is hidden.
- /// </summary>
- /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
- public bool IsHidden
- {
- get { return true; }
- }
-
- public bool IsEnabled
- {
- get { return true; }
- }
-
- public bool IsLogged
- {
- get { return true; }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs
deleted file mode 100644
index 3c33df832..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
-{
- /// <summary>
- /// Class ReloadLoggerFileTask
- /// </summary>
- public class ReloadLoggerFileTask : IScheduledTask, IConfigurableScheduledTask
- {
- /// <summary>
- /// Gets or sets the log manager.
- /// </summary>
- /// <value>The log manager.</value>
- private ILogManager LogManager { get; set; }
- /// <summary>
- /// Gets or sets the configuration manager.
- /// </summary>
- /// <value>The configuration manager.</value>
- private IConfigurationManager ConfigurationManager { get; set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ReloadLoggerFileTask" /> class.
- /// </summary>
- /// <param name="logManager">The logManager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- public ReloadLoggerFileTask(ILogManager logManager, IConfigurationManager configurationManager)
- {
- LogManager = logManager;
- ConfigurationManager = configurationManager;
- }
-
- /// <summary>
- /// Gets the default triggers.
- /// </summary>
- /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
- {
- var trigger = new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerDaily, TimeOfDayTicks = TimeSpan.FromHours(0).Ticks }; //12am
-
- return new[] { trigger };
- }
-
- /// <summary>
- /// Executes the internal.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- progress.Report(0);
-
- LogManager.ReloadLogger(ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging
- ? LogSeverity.Debug
- : LogSeverity.Info);
-
- return Task.FromResult(true);
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return "Start new log file"; }
- }
-
- public string Key { get; }
-
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
- public string Description
- {
- get { return "Moves logging to a new file to help reduce log file sizes."; }
- }
-
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
- public string Category
- {
- get { return "Application"; }
- }
-
- public bool IsHidden
- {
- get { return true; }
- }
-
- public bool IsEnabled
- {
- get { return true; }
- }
-
- public bool IsLogged
- {
- get { return true; }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/WeeklyTrigger.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/WeeklyTrigger.cs
deleted file mode 100644
index 0d8af4e9c..000000000
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/WeeklyTrigger.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-using System;
-using System.Threading;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Common.Implementations.ScheduledTasks
-{
- /// <summary>
- /// Represents a task trigger that fires on a weekly basis
- /// </summary>
- public class WeeklyTrigger : ITaskTrigger
- {
- /// <summary>
- /// Get the time of day to trigger the task to run
- /// </summary>
- /// <value>The time of day.</value>
- public TimeSpan TimeOfDay { get; set; }
-
- /// <summary>
- /// Gets or sets the day of week.
- /// </summary>
- /// <value>The day of week.</value>
- public DayOfWeek DayOfWeek { get; set; }
-
- /// <summary>
- /// Gets the execution properties of this task.
- /// </summary>
- /// <value>
- /// The execution properties of this task.
- /// </value>
- public TaskExecutionOptions TaskOptions { get; set; }
-
- /// <summary>
- /// Gets or sets the timer.
- /// </summary>
- /// <value>The timer.</value>
- private Timer Timer { get; set; }
-
- /// <summary>
- /// Stars waiting for the trigger action
- /// </summary>
- /// <param name="lastResult">The last result.</param>
- /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
- {
- DisposeTimer();
-
- var triggerDate = GetNextTriggerDateTime();
-
- Timer = new Timer(state => OnTriggered(), null, triggerDate - DateTime.Now, TimeSpan.FromMilliseconds(-1));
- }
-
- /// <summary>
- /// Gets the next trigger date time.
- /// </summary>
- /// <returns>DateTime.</returns>
- private DateTime GetNextTriggerDateTime()
- {
- var now = DateTime.Now;
-
- // If it's on the same day
- if (now.DayOfWeek == DayOfWeek)
- {
- // It's either later today, or a week from now
- return now.TimeOfDay < TimeOfDay ? now.Date.Add(TimeOfDay) : now.Date.AddDays(7).Add(TimeOfDay);
- }
-
- var triggerDate = now.Date;
-
- // Walk the date forward until we get to the trigger day
- while (triggerDate.DayOfWeek != DayOfWeek)
- {
- triggerDate = triggerDate.AddDays(1);
- }
-
- // Return the trigger date plus the time offset
- return triggerDate.Add(TimeOfDay);
- }
-
- /// <summary>
- /// Stops waiting for the trigger action
- /// </summary>
- public void Stop()
- {
- DisposeTimer();
- }
-
- /// <summary>
- /// Disposes the timer.
- /// </summary>
- private void DisposeTimer()
- {
- if (Timer != null)
- {
- Timer.Dispose();
- }
- }
-
- /// <summary>
- /// Occurs when [triggered].
- /// </summary>
- public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
-
- /// <summary>
- /// Called when [triggered].
- /// </summary>
- private void OnTriggered()
- {
- if (Triggered != null)
- {
- Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
deleted file mode 100644
index f48681304..000000000
--- a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Xml;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Common.Implementations.Serialization
-{
- /// <summary>
- /// Provides a wrapper around third party xml serialization.
- /// </summary>
- public class XmlSerializer : IXmlSerializer
- {
- private readonly IFileSystem _fileSystem;
- private readonly ILogger _logger;
-
- public XmlSerializer(IFileSystem fileSystem, ILogger logger)
- {
- _fileSystem = fileSystem;
- _logger = logger;
- }
-
- // Need to cache these
- // http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html
- private readonly Dictionary<string, System.Xml.Serialization.XmlSerializer> _serializers =
- new Dictionary<string, System.Xml.Serialization.XmlSerializer>();
-
- private System.Xml.Serialization.XmlSerializer GetSerializer(Type type)
- {
- var key = type.FullName;
- lock (_serializers)
- {
- System.Xml.Serialization.XmlSerializer serializer;
- if (!_serializers.TryGetValue(key, out serializer))
- {
- serializer = new System.Xml.Serialization.XmlSerializer(type);
- _serializers[key] = serializer;
- }
- return serializer;
- }
- }
-
- /// <summary>
- /// Serializes to writer.
- /// </summary>
- /// <param name="obj">The obj.</param>
- /// <param name="writer">The writer.</param>
- private void SerializeToWriter(object obj, XmlTextWriter writer)
- {
- writer.Formatting = Formatting.Indented;
- var netSerializer = GetSerializer(obj.GetType());
- netSerializer.Serialize(writer, obj);
- }
-
- /// <summary>
- /// Deserializes from stream.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="stream">The stream.</param>
- /// <returns>System.Object.</returns>
- public object DeserializeFromStream(Type type, Stream stream)
- {
- using (var reader = new XmlTextReader(stream))
- {
- var netSerializer = GetSerializer(type);
- return netSerializer.Deserialize(reader);
- }
- }
-
- /// <summary>
- /// Serializes to stream.
- /// </summary>
- /// <param name="obj">The obj.</param>
- /// <param name="stream">The stream.</param>
- public void SerializeToStream(object obj, Stream stream)
- {
- using (var writer = new XmlTextWriter(stream, null))
- {
- SerializeToWriter(obj, writer);
- }
- }
-
- /// <summary>
- /// Serializes to file.
- /// </summary>
- /// <param name="obj">The obj.</param>
- /// <param name="file">The file.</param>
- public void SerializeToFile(object obj, string file)
- {
- _logger.Debug("Serializing to file {0}", file);
- using (var stream = new FileStream(file, FileMode.Create))
- {
- SerializeToStream(obj, stream);
- }
- }
-
- /// <summary>
- /// Deserializes from file.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="file">The file.</param>
- /// <returns>System.Object.</returns>
- public object DeserializeFromFile(Type type, string file)
- {
- _logger.Debug("Deserializing file {0}", file);
- using (var stream = _fileSystem.OpenRead(file))
- {
- return DeserializeFromStream(type, stream);
- }
- }
-
- /// <summary>
- /// Deserializes from bytes.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="buffer">The buffer.</param>
- /// <returns>System.Object.</returns>
- public object DeserializeFromBytes(Type type, byte[] buffer)
- {
- using (var stream = new MemoryStream(buffer))
- {
- return DeserializeFromStream(type, stream);
- }
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs b/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs
deleted file mode 100644
index 371c2ea11..000000000
--- a/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs
+++ /dev/null
@@ -1,269 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Updates;
-
-namespace MediaBrowser.Common.Implementations.Updates
-{
- public class GithubUpdater
- {
- private readonly IHttpClient _httpClient;
- private readonly IJsonSerializer _jsonSerializer;
-
- public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer)
- {
- _httpClient = httpClient;
- _jsonSerializer = jsonSerializer;
- }
-
- public async Task<CheckForUpdateResult> CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, TimeSpan cacheLength, CancellationToken cancellationToken)
- {
- var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
-
- var options = new HttpRequestOptions
- {
- Url = url,
- EnableKeepAlive = false,
- CancellationToken = cancellationToken,
- UserAgent = "Emby/3.0",
- BufferContent = false
- };
-
- if (cacheLength.Ticks > 0)
- {
- options.CacheMode = CacheMode.Unconditional;
- options.CacheLength = cacheLength;
- }
-
- using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
- {
- var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);
-
- return CheckForUpdateResult(obj, minVersion, updateLevel, assetFilename, packageName, targetFilename);
- }
- }
-
- private CheckForUpdateResult CheckForUpdateResult(RootObject[] obj, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename)
- {
- if (updateLevel == PackageVersionClass.Release)
- {
- // Technically all we need to do is check that it's not pre-release
- // But let's addititional checks for -beta and -dev to handle builds that might be temporarily tagged incorrectly.
- obj = obj.Where(i => !i.prerelease && !i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) && !i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray();
- }
- else if (updateLevel == PackageVersionClass.Beta)
- {
- obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase)).ToArray();
- }
- else if (updateLevel == PackageVersionClass.Dev)
- {
- obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) || i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray();
- }
-
- var availableUpdate = obj
- .Select(i => CheckForUpdateResult(i, minVersion, assetFilename, packageName, targetFilename))
- .Where(i => i != null)
- .OrderByDescending(i => Version.Parse(i.AvailableVersion))
- .FirstOrDefault();
-
- return availableUpdate ?? new CheckForUpdateResult
- {
- IsUpdateAvailable = false
- };
- }
-
- private bool MatchesUpdateLevel(RootObject i, PackageVersionClass updateLevel)
- {
- if (updateLevel == PackageVersionClass.Beta)
- {
- return !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase);
- }
- if (updateLevel == PackageVersionClass.Dev)
- {
- return !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) ||
- i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase);
- }
-
- // Technically all we need to do is check that it's not pre-release
- // But let's addititional checks for -beta and -dev to handle builds that might be temporarily tagged incorrectly.
- return !i.prerelease && !i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) &&
- !i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase);
- }
-
- public async Task<List<RootObject>> GetLatestReleases(string organzation, string repository, string assetFilename, CancellationToken cancellationToken)
- {
- var list = new List<RootObject>();
-
- var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
-
- var options = new HttpRequestOptions
- {
- Url = url,
- EnableKeepAlive = false,
- CancellationToken = cancellationToken,
- UserAgent = "Emby/3.0",
- BufferContent = false
- };
-
- using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
- {
- var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);
-
- obj = obj.Where(i => (i.assets ?? new List<Asset>()).Any(a => IsAsset(a, assetFilename))).ToArray();
-
- list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Release)).OrderByDescending(GetVersion).Take(1));
- list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Beta)).OrderByDescending(GetVersion).Take(1));
- list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Dev)).OrderByDescending(GetVersion).Take(1));
-
- return list;
- }
- }
-
- public Version GetVersion(RootObject obj)
- {
- Version version;
- if (!Version.TryParse(obj.tag_name, out version))
- {
- return new Version(1, 0);
- }
-
- return version;
- }
-
- private CheckForUpdateResult CheckForUpdateResult(RootObject obj, Version minVersion, string assetFilename, string packageName, string targetFilename)
- {
- Version version;
- if (!Version.TryParse(obj.tag_name, out version))
- {
- return null;
- }
-
- if (version < minVersion)
- {
- return null;
- }
-
- var asset = (obj.assets ?? new List<Asset>()).FirstOrDefault(i => IsAsset(i, assetFilename));
-
- if (asset == null)
- {
- return null;
- }
-
- return new CheckForUpdateResult
- {
- AvailableVersion = version.ToString(),
- IsUpdateAvailable = version > minVersion,
- Package = new PackageVersionInfo
- {
- classification = obj.prerelease ?
- (obj.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase) ? PackageVersionClass.Dev : PackageVersionClass.Beta) :
- PackageVersionClass.Release,
- name = packageName,
- sourceUrl = asset.browser_download_url,
- targetFilename = targetFilename,
- versionStr = version.ToString(),
- requiredVersionStr = "1.0.0",
- description = obj.body,
- infoUrl = obj.html_url
- }
- };
- }
-
- private bool IsAsset(Asset asset, string assetFilename)
- {
- var downloadFilename = Path.GetFileName(asset.browser_download_url) ?? string.Empty;
-
- if (downloadFilename.IndexOf(assetFilename, StringComparison.OrdinalIgnoreCase) != -1)
- {
- return true;
- }
-
- return string.Equals(assetFilename, downloadFilename, StringComparison.OrdinalIgnoreCase);
- }
-
- public class Uploader
- {
- public string login { get; set; }
- public int id { get; set; }
- public string avatar_url { get; set; }
- public string gravatar_id { get; set; }
- public string url { get; set; }
- public string html_url { get; set; }
- public string followers_url { get; set; }
- public string following_url { get; set; }
- public string gists_url { get; set; }
- public string starred_url { get; set; }
- public string subscriptions_url { get; set; }
- public string organizations_url { get; set; }
- public string repos_url { get; set; }
- public string events_url { get; set; }
- public string received_events_url { get; set; }
- public string type { get; set; }
- public bool site_admin { get; set; }
- }
-
- public class Asset
- {
- public string url { get; set; }
- public int id { get; set; }
- public string name { get; set; }
- public object label { get; set; }
- public Uploader uploader { get; set; }
- public string content_type { get; set; }
- public string state { get; set; }
- public int size { get; set; }
- public int download_count { get; set; }
- public string created_at { get; set; }
- public string updated_at { get; set; }
- public string browser_download_url { get; set; }
- }
-
- public class Author
- {
- public string login { get; set; }
- public int id { get; set; }
- public string avatar_url { get; set; }
- public string gravatar_id { get; set; }
- public string url { get; set; }
- public string html_url { get; set; }
- public string followers_url { get; set; }
- public string following_url { get; set; }
- public string gists_url { get; set; }
- public string starred_url { get; set; }
- public string subscriptions_url { get; set; }
- public string organizations_url { get; set; }
- public string repos_url { get; set; }
- public string events_url { get; set; }
- public string received_events_url { get; set; }
- public string type { get; set; }
- public bool site_admin { get; set; }
- }
-
- public class RootObject
- {
- public string url { get; set; }
- public string assets_url { get; set; }
- public string upload_url { get; set; }
- public string html_url { get; set; }
- public int id { get; set; }
- public string tag_name { get; set; }
- public string target_commitish { get; set; }
- public string name { get; set; }
- public bool draft { get; set; }
- public Author author { get; set; }
- public bool prerelease { get; set; }
- public string created_at { get; set; }
- public string published_at { get; set; }
- public List<Asset> assets { get; set; }
- public string tarball_url { get; set; }
- public string zipball_url { get; set; }
- public string body { get; set; }
- }
- }
-}