diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-10-29 16:02:21 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-10-29 16:02:21 -0400 |
| commit | da20e8dcd2867df0a9a6ebc1081edb2db2eebdef (patch) | |
| tree | 0c00e59c5def4263126353e63bd79b9464b60b10 /MediaBrowser.Common.Implementations | |
| parent | e5d71c1014cc2d78e5004d0736e321b350b7bb64 (diff) | |
continue with .net core targeting
Diffstat (limited to 'MediaBrowser.Common.Implementations')
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; } - } - } -} |
