diff options
| author | Luke <luke.pulverenti@gmail.com> | 2016-10-30 03:29:27 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-10-30 03:29:27 -0400 |
| commit | d31b0f7be4b14e4ada999c97e675b856ad68352b (patch) | |
| tree | a4619513efbb3be62a6204c996526df606cb62c5 /MediaBrowser.Common.Implementations | |
| parent | b19f75fcae017cb51f1e58eb2d54ca84620b6ee0 (diff) | |
| parent | 3094cd7ff3e51578808ce1b6f56b141930c18004 (diff) | |
Merge pull request #2258 from MediaBrowser/dev
Dev
Diffstat (limited to 'MediaBrowser.Common.Implementations')
38 files changed, 0 insertions, 8809 deletions
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs deleted file mode 100644 index 3b14994190..0000000000 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ /dev/null @@ -1,892 +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.Security; -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 ServiceStack; -using SimpleInjector; -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.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, IDependencyContainer - 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 container - /// </summary> - protected readonly Container Container = new Container(); - - /// <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 security manager. - /// </summary> - /// <value>The security manager.</value> - protected ISecurityManager SecurityManager { 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; } - - /// <summary> - /// Gets or sets the installation manager. - /// </summary> - /// <value>The installation manager.</value> - protected IInstallationManager InstallationManager { get; private set; } - - protected IFileSystem FileSystemManager { get; private set; } - - protected IIsoManager IsoManager { 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) - { - try - { - // https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4 - Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0="); - } - catch - { - // Failing under mono - } - progress.Report(1); - - JsonSerializer = CreateJsonSerializer(); - - MemoryStreamProvider = CreateMemoryStreamProvider(); - - 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 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 virtual IJsonSerializer CreateJsonSerializer() - { - return new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer")); - } - - 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() - { - RegisterModules(); - - 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); - - RegisterSingleInstance(JsonSerializer); - RegisterSingleInstance(XmlSerializer); - RegisterSingleInstance(MemoryStreamProvider); - - 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); - - SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager); - RegisterSingleInstance(SecurityManager); - - InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager); - RegisterSingleInstance(InstallationManager); - - IsoManager = new IsoManager(); - RegisterSingleInstance(IsoManager); - - return Task.FromResult(true); - } - - private void RegisterModules() - { - var moduleTypes = GetExportTypes<IDependencyModule>(); - - foreach (var type in moduleTypes) - { - try - { - var instance = Activator.CreateInstance(type) as IDependencyModule; - if (instance != null) - instance.BindDependencies(this); - } - catch (Exception ex) - { - Logger.ErrorException("Error setting up dependency bindings for " + type.Name, ex); - } - } - } - - /// <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 object CreateInstance(Type type) - { - try - { - return Container.GetInstance(type); - } - catch (Exception ex) - { - Logger.ErrorException("Error creating {0}", ex, type.FullName); - - throw; - } - } - - /// <summary> - /// Creates the instance safe. - /// </summary> - /// <param name="type">The type.</param> - /// <returns>System.Object.</returns> - protected object CreateInstanceSafe(Type type) - { - try - { - return Container.GetInstance(type); - } - catch (Exception ex) - { - Logger.ErrorException("Error creating {0}", ex, type.FullName); - // Don't blow up in release mode - return null; - } - } - - void IDependencyContainer.RegisterSingleInstance<T>(T obj, bool manageLifetime) - { - RegisterSingleInstance(obj, manageLifetime); - } - - /// <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 void RegisterSingleInstance<T>(T obj, bool manageLifetime = true) - where T : class - { - Container.RegisterSingleton(obj); - - if (manageLifetime) - { - var disposable = obj as IDisposable; - - if (disposable != null) - { - DisposableParts.Add(disposable); - } - } - } - - void IDependencyContainer.RegisterSingleInstance<T>(Func<T> func) - { - RegisterSingleInstance(func); - } - - /// <summary> - /// Registers the single instance. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="func">The func.</param> - protected void RegisterSingleInstance<T>(Func<T> func) - where T : class - { - Container.RegisterSingleton(func); - } - - void IDependencyContainer.Register(Type typeInterface, Type typeImplementation) - { - Container.Register(typeInterface, typeImplementation); - } - - /// <summary> - /// Resolves this instance. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <returns>``0.</returns> - public T Resolve<T>() - { - return (T)Container.GetRegistration(typeof(T), true).GetInstance(); - } - - /// <summary> - /// Resolves this instance. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <returns>``0.</returns> - public T TryResolve<T>() - { - var result = Container.GetRegistration(typeof(T), false); - - if (result == null) - { - return default(T); - } - return (T)result.GetInstance(); - } - - /// <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 9ba2effd3a..0000000000 --- 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 dd7a10b1ac..0000000000 --- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs +++ /dev/null @@ -1,329 +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; -using MediaBrowser.Common.IO; - -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)); - 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; - - Directory.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 (!Directory.Exists(newPath)) - { - throw new DirectoryNotFoundException(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 (DirectoryNotFoundException) - { - 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); - Directory.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 419b85fa73..0000000000 --- a/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs +++ /dev/null @@ -1,59 +0,0 @@ -using MediaBrowser.Model.Serialization; -using System; -using System.IO; -using System.Linq; - -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) - { - object configuration; - - byte[] buffer = null; - - // Use try/catch to avoid the extra file system lookup using File.Exists - try - { - buffer = File.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)) - { - Directory.CreateDirectory(Path.GetDirectoryName(path)); - - // Save it after load in case we got new items - File.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 67dbd76d24..0000000000 --- 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 a43697c7be..0000000000 --- a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs +++ /dev/null @@ -1,110 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Logging; -using System; -using System.IO; -using System.Text; -using MediaBrowser.Common.IO; -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 8af6ef6c6e..0000000000 --- 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 b18178ead2..0000000000 --- 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 de88ddadab..0000000000 --- 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/LnkShortcutHandler.cs b/MediaBrowser.Common.Implementations/IO/LnkShortcutHandler.cs deleted file mode 100644 index 441e6939f3..0000000000 --- a/MediaBrowser.Common.Implementations/IO/LnkShortcutHandler.cs +++ /dev/null @@ -1,399 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; -using MediaBrowser.Model.IO; - -namespace MediaBrowser.Common.Implementations.IO -{ - public class LnkShortcutHandler :IShortcutHandler - { - public string Extension - { - get { return ".lnk"; } - } - - public string Resolve(string shortcutPath) - { - var link = new ShellLink(); - ((IPersistFile)link).Load(shortcutPath, NativeMethods.STGM_READ); - // ((IShellLinkW)link).Resolve(hwnd, 0) - var sb = new StringBuilder(NativeMethods.MAX_PATH); - WIN32_FIND_DATA data; - ((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0); - return sb.ToString(); - } - - public void Create(string shortcutPath, string targetPath) - { - throw new NotImplementedException(); - } - } - - /// <summary> - /// Class NativeMethods - /// </summary> - [SuppressUnmanagedCodeSecurity] - public static class NativeMethods - { - /// <summary> - /// The MA x_ PATH - /// </summary> - public const int MAX_PATH = 260; - /// <summary> - /// The MA x_ ALTERNATE - /// </summary> - public const int MAX_ALTERNATE = 14; - /// <summary> - /// The INVALI d_ HANDL e_ VALUE - /// </summary> - public static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); - /// <summary> - /// The STG m_ READ - /// </summary> - public const uint STGM_READ = 0; - } - - /// <summary> - /// Struct FILETIME - /// </summary> - [StructLayout(LayoutKind.Sequential)] - public struct FILETIME - { - /// <summary> - /// The dw low date time - /// </summary> - public uint dwLowDateTime; - /// <summary> - /// The dw high date time - /// </summary> - public uint dwHighDateTime; - } - - /// <summary> - /// Struct WIN32_FIND_DATA - /// </summary> - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct WIN32_FIND_DATA - { - /// <summary> - /// The dw file attributes - /// </summary> - public FileAttributes dwFileAttributes; - /// <summary> - /// The ft creation time - /// </summary> - public FILETIME ftCreationTime; - /// <summary> - /// The ft last access time - /// </summary> - public FILETIME ftLastAccessTime; - /// <summary> - /// The ft last write time - /// </summary> - public FILETIME ftLastWriteTime; - /// <summary> - /// The n file size high - /// </summary> - public int nFileSizeHigh; - /// <summary> - /// The n file size low - /// </summary> - public int nFileSizeLow; - /// <summary> - /// The dw reserved0 - /// </summary> - public int dwReserved0; - /// <summary> - /// The dw reserved1 - /// </summary> - public int dwReserved1; - - /// <summary> - /// The c file name - /// </summary> - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeMethods.MAX_PATH)] - public string cFileName; - - /// <summary> - /// This will always be null when FINDEX_INFO_LEVELS = basic - /// </summary> - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeMethods.MAX_ALTERNATE)] - public string cAlternate; - - /// <summary> - /// Gets or sets the path. - /// </summary> - /// <value>The path.</value> - public string Path { get; set; } - - /// <summary> - /// Returns a <see cref="System.String" /> that represents this instance. - /// </summary> - /// <returns>A <see cref="System.String" /> that represents this instance.</returns> - public override string ToString() - { - return Path ?? string.Empty; - } - } - - /// <summary> - /// Enum SLGP_FLAGS - /// </summary> - [Flags] - public enum SLGP_FLAGS - { - /// <summary> - /// Retrieves the standard short (8.3 format) file name - /// </summary> - SLGP_SHORTPATH = 0x1, - /// <summary> - /// Retrieves the Universal Naming Convention (UNC) path name of the file - /// </summary> - SLGP_UNCPRIORITY = 0x2, - /// <summary> - /// Retrieves the raw path name. A raw path is something that might not exist and may include environment variables that need to be expanded - /// </summary> - SLGP_RAWPATH = 0x4 - } - /// <summary> - /// Enum SLR_FLAGS - /// </summary> - [Flags] - public enum SLR_FLAGS - { - /// <summary> - /// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set, - /// the high-order word of fFlags can be set to a time-out value that specifies the - /// maximum amount of time to be spent resolving the link. The function returns if the - /// link cannot be resolved within the time-out duration. If the high-order word is set - /// to zero, the time-out duration will be set to the default value of 3,000 milliseconds - /// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out - /// duration, in milliseconds. - /// </summary> - SLR_NO_UI = 0x1, - /// <summary> - /// Obsolete and no longer used - /// </summary> - SLR_ANY_MATCH = 0x2, - /// <summary> - /// If the link object has changed, update its path and list of identifiers. - /// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine - /// whether or not the link object has changed. - /// </summary> - SLR_UPDATE = 0x4, - /// <summary> - /// Do not update the link information - /// </summary> - SLR_NOUPDATE = 0x8, - /// <summary> - /// Do not execute the search heuristics - /// </summary> - SLR_NOSEARCH = 0x10, - /// <summary> - /// Do not use distributed link tracking - /// </summary> - SLR_NOTRACK = 0x20, - /// <summary> - /// Disable distributed link tracking. By default, distributed link tracking tracks - /// removable media across multiple devices based on the volume name. It also uses the - /// Universal Naming Convention (UNC) path to track remote file systems whose drive letter - /// has changed. Setting SLR_NOLINKINFO disables both types of tracking. - /// </summary> - SLR_NOLINKINFO = 0x40, - /// <summary> - /// Call the Microsoft Windows Installer - /// </summary> - SLR_INVOKE_MSI = 0x80 - } - - /// <summary> - /// The IShellLink interface allows Shell links to be created, modified, and resolved - /// </summary> - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")] - public interface IShellLinkW - { - /// <summary> - /// Retrieves the path and file name of a Shell link object - /// </summary> - /// <param name="pszFile">The PSZ file.</param> - /// <param name="cchMaxPath">The CCH max path.</param> - /// <param name="pfd">The PFD.</param> - /// <param name="fFlags">The f flags.</param> - void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATA pfd, SLGP_FLAGS fFlags); - /// <summary> - /// Retrieves the list of item identifiers for a Shell link object - /// </summary> - /// <param name="ppidl">The ppidl.</param> - void GetIDList(out IntPtr ppidl); - /// <summary> - /// Sets the pointer to an item identifier list (PIDL) for a Shell link object. - /// </summary> - /// <param name="pidl">The pidl.</param> - void SetIDList(IntPtr pidl); - /// <summary> - /// Retrieves the description string for a Shell link object - /// </summary> - /// <param name="pszName">Name of the PSZ.</param> - /// <param name="cchMaxName">Name of the CCH max.</param> - void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); - /// <summary> - /// Sets the description for a Shell link object. The description can be any application-defined string - /// </summary> - /// <param name="pszName">Name of the PSZ.</param> - void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); - /// <summary> - /// Retrieves the name of the working directory for a Shell link object - /// </summary> - /// <param name="pszDir">The PSZ dir.</param> - /// <param name="cchMaxPath">The CCH max path.</param> - void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); - /// <summary> - /// Sets the name of the working directory for a Shell link object - /// </summary> - /// <param name="pszDir">The PSZ dir.</param> - void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); - /// <summary> - /// Retrieves the command-line arguments associated with a Shell link object - /// </summary> - /// <param name="pszArgs">The PSZ args.</param> - /// <param name="cchMaxPath">The CCH max path.</param> - void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); - /// <summary> - /// Sets the command-line arguments for a Shell link object - /// </summary> - /// <param name="pszArgs">The PSZ args.</param> - void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); - /// <summary> - /// Retrieves the hot key for a Shell link object - /// </summary> - /// <param name="pwHotkey">The pw hotkey.</param> - void GetHotkey(out short pwHotkey); - /// <summary> - /// Sets a hot key for a Shell link object - /// </summary> - /// <param name="wHotkey">The w hotkey.</param> - void SetHotkey(short wHotkey); - /// <summary> - /// Retrieves the show command for a Shell link object - /// </summary> - /// <param name="piShowCmd">The pi show CMD.</param> - void GetShowCmd(out int piShowCmd); - /// <summary> - /// Sets the show command for a Shell link object. The show command sets the initial show state of the window. - /// </summary> - /// <param name="iShowCmd">The i show CMD.</param> - void SetShowCmd(int iShowCmd); - /// <summary> - /// Retrieves the location (path and index) of the icon for a Shell link object - /// </summary> - /// <param name="pszIconPath">The PSZ icon path.</param> - /// <param name="cchIconPath">The CCH icon path.</param> - /// <param name="piIcon">The pi icon.</param> - void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, - int cchIconPath, out int piIcon); - /// <summary> - /// Sets the location (path and index) of the icon for a Shell link object - /// </summary> - /// <param name="pszIconPath">The PSZ icon path.</param> - /// <param name="iIcon">The i icon.</param> - void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); - /// <summary> - /// Sets the relative path to the Shell link object - /// </summary> - /// <param name="pszPathRel">The PSZ path rel.</param> - /// <param name="dwReserved">The dw reserved.</param> - void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); - /// <summary> - /// Attempts to find the target of a Shell link, even if it has been moved or renamed - /// </summary> - /// <param name="hwnd">The HWND.</param> - /// <param name="fFlags">The f flags.</param> - void Resolve(IntPtr hwnd, SLR_FLAGS fFlags); - /// <summary> - /// Sets the path and file name of a Shell link object - /// </summary> - /// <param name="pszFile">The PSZ file.</param> - void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); - - } - - /// <summary> - /// Interface IPersist - /// </summary> - [ComImport, Guid("0000010c-0000-0000-c000-000000000046"), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IPersist - { - /// <summary> - /// Gets the class ID. - /// </summary> - /// <param name="pClassID">The p class ID.</param> - [PreserveSig] - void GetClassID(out Guid pClassID); - } - - /// <summary> - /// Interface IPersistFile - /// </summary> - [ComImport, Guid("0000010b-0000-0000-C000-000000000046"), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IPersistFile : IPersist - { - /// <summary> - /// Gets the class ID. - /// </summary> - /// <param name="pClassID">The p class ID.</param> - new void GetClassID(out Guid pClassID); - /// <summary> - /// Determines whether this instance is dirty. - /// </summary> - [PreserveSig] - int IsDirty(); - - /// <summary> - /// Loads the specified PSZ file name. - /// </summary> - /// <param name="pszFileName">Name of the PSZ file.</param> - /// <param name="dwMode">The dw mode.</param> - [PreserveSig] - void Load([In, MarshalAs(UnmanagedType.LPWStr)] - string pszFileName, uint dwMode); - - /// <summary> - /// Saves the specified PSZ file name. - /// </summary> - /// <param name="pszFileName">Name of the PSZ file.</param> - /// <param name="remember">if set to <c>true</c> [remember].</param> - [PreserveSig] - void Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName, - [In, MarshalAs(UnmanagedType.Bool)] bool remember); - - /// <summary> - /// Saves the completed. - /// </summary> - /// <param name="pszFileName">Name of the PSZ file.</param> - [PreserveSig] - void SaveCompleted([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName); - - /// <summary> - /// Gets the cur file. - /// </summary> - /// <param name="ppszFileName">Name of the PPSZ file.</param> - [PreserveSig] - void GetCurFile([In, MarshalAs(UnmanagedType.LPWStr)] string ppszFileName); - } - - // CLSID_ShellLink from ShlGuid.h - /// <summary> - /// Class ShellLink - /// </summary> - [ - ComImport, - Guid("00021401-0000-0000-C000-000000000046") - ] - public class ShellLink - { - } -} diff --git a/MediaBrowser.Common.Implementations/IO/ManagedFileSystem.cs b/MediaBrowser.Common.Implementations/IO/ManagedFileSystem.cs deleted file mode 100644 index ffb1e42346..0000000000 --- a/MediaBrowser.Common.Implementations/IO/ManagedFileSystem.cs +++ /dev/null @@ -1,696 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using MediaBrowser.Common.IO; -using MediaBrowser.Model.IO; -using Patterns.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 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 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 e8f8de8aef..0000000000 --- a/MediaBrowser.Common.Implementations/IO/WindowsFileSystem.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Patterns.Logging; - -namespace MediaBrowser.Common.Implementations.IO -{ - public class WindowsFileSystem : ManagedFileSystem - { - public WindowsFileSystem(ILogger logger) - : base(logger, true, true) - { - AddShortcutHandler(new LnkShortcutHandler()); - EnableFileSystemRequestConcat = false; - } - } -} diff --git a/MediaBrowser.Common.Implementations/Logging/LogHelper.cs b/MediaBrowser.Common.Implementations/Logging/LogHelper.cs deleted file mode 100644 index 8080c2111c..0000000000 --- a/MediaBrowser.Common.Implementations/Logging/LogHelper.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Text; - -namespace MediaBrowser.Common.Implementations.Logging -{ - /// <summary> - /// Class LogHelper - /// </summary> - public static class LogHelper - { - /// <summary> - /// Gets the log message. - /// </summary> - /// <param name="exception">The exception.</param> - /// <returns>StringBuilder.</returns> - public static StringBuilder GetLogMessage(Exception exception) - { - if (exception == null) - { - throw new ArgumentNullException("exception"); - } - - var messageText = new StringBuilder(); - - messageText.AppendLine(exception.Message); - - messageText.AppendLine(exception.GetType().FullName); - - LogExceptionData(messageText, exception); - - messageText.AppendLine(exception.StackTrace ?? "No Stack Trace Available"); - - // Log the InnerExceptions, if any - AppendInnerExceptions(messageText, exception); - - messageText.AppendLine(string.Empty); - - return messageText; - } - - /// <summary> - /// Appends the inner exceptions. - /// </summary> - /// <param name="messageText">The message text.</param> - /// <param name="e">The e.</param> - private static void AppendInnerExceptions(StringBuilder messageText, Exception e) - { - var aggregate = e as AggregateException; - - if (aggregate != null && aggregate.InnerExceptions != null) - { - foreach (var ex in aggregate.InnerExceptions) - { - AppendInnerException(messageText, ex); - AppendInnerExceptions(messageText, ex); - } - } - - else if (e.InnerException != null) - { - AppendInnerException(messageText, e.InnerException); - AppendInnerExceptions(messageText, e.InnerException); - } - } - - /// <summary> - /// Appends the inner exception. - /// </summary> - /// <param name="messageText">The message text.</param> - /// <param name="e">The e.</param> - private static void AppendInnerException(StringBuilder messageText, Exception e) - { - messageText.AppendLine("InnerException: " + e.GetType().FullName); - messageText.AppendLine(e.Message); - - LogExceptionData(messageText, e); - - if (e.StackTrace != null) - { - messageText.AppendLine(e.StackTrace); - } - } - - /// <summary> - /// Logs the exception data. - /// </summary> - /// <param name="messageText">The message text.</param> - /// <param name="e">The e.</param> - private static void LogExceptionData(StringBuilder messageText, Exception e) - { - foreach (var key in e.Data.Keys) - { - messageText.AppendLine(key + ": " + e.Data[key]); - } - } - } -} diff --git a/MediaBrowser.Common.Implementations/Logging/NLogger.cs b/MediaBrowser.Common.Implementations/Logging/NLogger.cs deleted file mode 100644 index 11f41261a2..0000000000 --- a/MediaBrowser.Common.Implementations/Logging/NLogger.cs +++ /dev/null @@ -1,224 +0,0 @@ -using MediaBrowser.Model.Logging; -using System; -using System.Text; - -namespace MediaBrowser.Common.Implementations.Logging -{ - /// <summary> - /// Class NLogger - /// </summary> - public class NLogger : ILogger - { - /// <summary> - /// The _logger - /// </summary> - private readonly NLog.Logger _logger; - - private readonly ILogManager _logManager; - - /// <summary> - /// The _lock object - /// </summary> - private static readonly object LockObject = new object(); - - /// <summary> - /// Initializes a new instance of the <see cref="NLogger" /> class. - /// </summary> - /// <param name="name">The name.</param> - /// <param name="logManager">The log manager.</param> - public NLogger(string name, ILogManager logManager) - { - _logManager = logManager; - lock (LockObject) - { - _logger = NLog.LogManager.GetLogger(name); - } - } - - /// <summary> - /// Infoes the specified message. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="paramList">The param list.</param> - public void Info(string message, params object[] paramList) - { - _logger.Info(message, paramList); - } - - /// <summary> - /// Errors the specified message. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="paramList">The param list.</param> - public void Error(string message, params object[] paramList) - { - _logger.Error(message, paramList); - } - - /// <summary> - /// Warns the specified message. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="paramList">The param list.</param> - public void Warn(string message, params object[] paramList) - { - _logger.Warn(message, paramList); - } - - /// <summary> - /// Debugs the specified message. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="paramList">The param list.</param> - public void Debug(string message, params object[] paramList) - { - if (_logManager.LogSeverity == LogSeverity.Info) - { - return; - } - - _logger.Debug(message, paramList); - } - - /// <summary> - /// Logs the exception. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="exception">The exception.</param> - /// <param name="paramList">The param list.</param> - /// <exception cref="System.NotImplementedException"></exception> - public void ErrorException(string message, Exception exception, params object[] paramList) - { - LogException(LogSeverity.Error, message, exception, paramList); - } - - /// <summary> - /// Logs the exception. - /// </summary> - /// <param name="level">The level.</param> - /// <param name="message">The message.</param> - /// <param name="exception">The exception.</param> - /// <param name="paramList">The param list.</param> - private void LogException(LogSeverity level, string message, Exception exception, params object[] paramList) - { - message = FormatMessage(message, paramList).Replace(Environment.NewLine, ". "); - - var messageText = LogHelper.GetLogMessage(exception); - - var prefix = _logManager.ExceptionMessagePrefix; - - if (!string.IsNullOrWhiteSpace(prefix)) - { - messageText.Insert(0, prefix); - } - - LogMultiline(message, level, messageText); - } - - /// <summary> - /// Formats the message. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="paramList">The param list.</param> - /// <returns>System.String.</returns> - private static string FormatMessage(string message, params object[] paramList) - { - if (paramList != null) - { - for (var i = 0; i < paramList.Length; i++) - { - var obj = paramList[i]; - - message = message.Replace("{" + i + "}", (obj == null ? "null" : obj.ToString())); - } - } - - return message; - } - - /// <summary> - /// Logs the multiline. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="severity">The severity.</param> - /// <param name="additionalContent">Content of the additional.</param> - public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent) - { - if (severity == LogSeverity.Debug && _logManager.LogSeverity == LogSeverity.Info) - { - return; - } - - additionalContent.Insert(0, message + Environment.NewLine); - - const char tabChar = '\t'; - - var text = additionalContent.ToString() - .Replace(Environment.NewLine, Environment.NewLine + tabChar) - .TrimEnd(tabChar); - - if (text.EndsWith(Environment.NewLine)) - { - text = text.Substring(0, text.LastIndexOf(Environment.NewLine, StringComparison.OrdinalIgnoreCase)); - } - - _logger.Log(GetLogLevel(severity), text); - } - - /// <summary> - /// Gets the log level. - /// </summary> - /// <param name="severity">The severity.</param> - /// <returns>NLog.LogLevel.</returns> - private NLog.LogLevel GetLogLevel(LogSeverity severity) - { - switch (severity) - { - case LogSeverity.Debug: - return NLog.LogLevel.Debug; - case LogSeverity.Error: - return NLog.LogLevel.Error; - case LogSeverity.Warn: - return NLog.LogLevel.Warn; - case LogSeverity.Fatal: - return NLog.LogLevel.Fatal; - case LogSeverity.Info: - return NLog.LogLevel.Info; - default: - throw new ArgumentException("Unknown LogSeverity: " + severity.ToString()); - } - } - - /// <summary> - /// Logs the specified severity. - /// </summary> - /// <param name="severity">The severity.</param> - /// <param name="message">The message.</param> - /// <param name="paramList">The param list.</param> - public void Log(LogSeverity severity, string message, params object[] paramList) - { - _logger.Log(GetLogLevel(severity), message, paramList); - } - - /// <summary> - /// Fatals the specified message. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="paramList">The param list.</param> - public void Fatal(string message, params object[] paramList) - { - _logger.Fatal(message, paramList); - } - - /// <summary> - /// Fatals the exception. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="exception">The exception.</param> - /// <param name="paramList">The param list.</param> - public void FatalException(string message, Exception exception, params object[] paramList) - { - LogException(LogSeverity.Fatal, message, exception, paramList); - } - } -} diff --git a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs deleted file mode 100644 index 1bbcccd884..0000000000 --- a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs +++ /dev/null @@ -1,264 +0,0 @@ -using MediaBrowser.Model.Logging; -using NLog; -using NLog.Config; -using NLog.Targets; -using NLog.Targets.Wrappers; -using System; -using System.IO; -using System.Linq; - -namespace MediaBrowser.Common.Implementations.Logging -{ - /// <summary> - /// Class NlogManager - /// </summary> - public class NlogManager : ILogManager - { - /// <summary> - /// Occurs when [logger loaded]. - /// </summary> - public event EventHandler LoggerLoaded; - /// <summary> - /// Gets or sets the log directory. - /// </summary> - /// <value>The log directory.</value> - private string LogDirectory { get; set; } - /// <summary> - /// Gets or sets the log file prefix. - /// </summary> - /// <value>The log file prefix.</value> - private string LogFilePrefix { get; set; } - /// <summary> - /// Gets the log file path. - /// </summary> - /// <value>The log file path.</value> - public string LogFilePath { get; private set; } - - /// <summary> - /// Gets or sets the exception message prefix. - /// </summary> - /// <value>The exception message prefix.</value> - public string ExceptionMessagePrefix { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="NlogManager" /> class. - /// </summary> - /// <param name="logDirectory">The log directory.</param> - /// <param name="logFileNamePrefix">The log file name prefix.</param> - public NlogManager(string logDirectory, string logFileNamePrefix) - { - LogDirectory = logDirectory; - LogFilePrefix = logFileNamePrefix; - - LogManager.Configuration = new LoggingConfiguration (); - } - - private LogSeverity _severity = LogSeverity.Debug; - public LogSeverity LogSeverity - { - get - { - return _severity; - } - set - { - var changed = _severity != value; - - _severity = value; - - if (changed) - { - UpdateLogLevel(value); - } - } - } - - private void UpdateLogLevel(LogSeverity newLevel) - { - var level = GetLogLevel(newLevel); - - var rules = LogManager.Configuration.LoggingRules; - - foreach (var rule in rules) - { - if (!rule.IsLoggingEnabledForLevel(level)) - { - rule.EnableLoggingForLevel(level); - } - foreach (var lev in rule.Levels.ToArray()) - { - if (lev < level) - { - rule.DisableLoggingForLevel(lev); - } - } - } - } - - /// <summary> - /// Adds the file target. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="level">The level.</param> - private void AddFileTarget(string path, LogSeverity level) - { - RemoveTarget("ApplicationLogFileWrapper"); - - var wrapper = new AsyncTargetWrapper (); - wrapper.Name = "ApplicationLogFileWrapper"; - - var logFile = new FileTarget - { - FileName = path, - Layout = "${longdate} ${level} ${logger}: ${message}" - }; - - logFile.Name = "ApplicationLogFile"; - - wrapper.WrappedTarget = logFile; - - AddLogTarget(wrapper, level); - } - - /// <summary> - /// Adds the log target. - /// </summary> - /// <param name="target">The target.</param> - /// <param name="level">The level.</param> - public void AddLogTarget(Target target, LogSeverity level) - { - var config = LogManager.Configuration; - config.AddTarget(target.Name, target); - - var rule = new LoggingRule("*", GetLogLevel(level), target); - config.LoggingRules.Add(rule); - - LogManager.Configuration = config; - } - - /// <summary> - /// Removes the target. - /// </summary> - /// <param name="name">The name.</param> - public void RemoveTarget(string name) - { - var config = LogManager.Configuration; - - var target = config.FindTargetByName(name); - - if (target != null) - { - foreach (var rule in config.LoggingRules.ToList()) - { - var contains = rule.Targets.Contains(target); - - rule.Targets.Remove(target); - - if (contains) - { - config.LoggingRules.Remove(rule); - } - } - - config.RemoveTarget(name); - LogManager.Configuration = config; - } - } - - /// <summary> - /// Gets the logger. - /// </summary> - /// <param name="name">The name.</param> - /// <returns>ILogger.</returns> - public Model.Logging.ILogger GetLogger(string name) - { - return new NLogger(name, this); - } - - /// <summary> - /// Gets the log level. - /// </summary> - /// <param name="severity">The severity.</param> - /// <returns>LogLevel.</returns> - /// <exception cref="System.ArgumentException">Unrecognized LogSeverity</exception> - private LogLevel GetLogLevel(LogSeverity severity) - { - switch (severity) - { - case LogSeverity.Debug: - return LogLevel.Debug; - case LogSeverity.Error: - return LogLevel.Error; - case LogSeverity.Fatal: - return LogLevel.Fatal; - case LogSeverity.Info: - return LogLevel.Info; - case LogSeverity.Warn: - return LogLevel.Warn; - default: - throw new ArgumentException("Unrecognized LogSeverity"); - } - } - - /// <summary> - /// Reloads the logger. - /// </summary> - /// <param name="level">The level.</param> - public void ReloadLogger(LogSeverity level) - { - LogFilePath = Path.Combine(LogDirectory, LogFilePrefix + "-" + decimal.Round(DateTime.Now.Ticks / 10000000) + ".txt"); - - Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath)); - - AddFileTarget(LogFilePath, level); - - LogSeverity = level; - - if (LoggerLoaded != null) - { - try - { - LoggerLoaded(this, EventArgs.Empty); - } - catch (Exception ex) - { - GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex); - } - } - } - - /// <summary> - /// Flushes this instance. - /// </summary> - public void Flush() - { - LogManager.Flush(); - } - - - public void AddConsoleOutput() - { - RemoveTarget("ConsoleTargetWrapper"); - - var wrapper = new AsyncTargetWrapper (); - wrapper.Name = "ConsoleTargetWrapper"; - - var target = new ConsoleTarget() - { - Layout = "${level}, ${logger}, ${message}", - Error = false - }; - - target.Name = "ConsoleTarget"; - - wrapper.WrappedTarget = target; - - AddLogTarget(wrapper, LogSeverity); - } - - public void RemoveConsoleOutput() - { - RemoveTarget("ConsoleTargetWrapper"); - } - } -} diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj deleted file mode 100644 index ce776b2452..0000000000 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ /dev/null @@ -1,138 +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="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> - <HintPath>..\packages\NLog.4.3.10\lib\net45\NLog.dll</HintPath> - <Private>True</Private> - </Reference> - <Reference Include="Patterns.Logging"> - <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath> - </Reference> - <Reference Include="SimpleInjector, Version=3.2.4.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL"> - <HintPath>..\packages\SimpleInjector.3.2.4\lib\net45\SimpleInjector.dll</HintPath> - <Private>True</Private> - </Reference> - <Reference Include="System" /> - <Reference Include="System.Configuration" /> - <Reference Include="System.Core" /> - <Reference Include="Microsoft.CSharp" /> - <Reference Include="System.Net" /> - <Reference Include="System.Xml" /> - <Reference Include="ServiceStack.Text"> - <HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath> - </Reference> - </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\LnkShortcutHandler.cs" /> - <Compile Include="IO\ManagedFileSystem.cs" /> - <Compile Include="IO\WindowsFileSystem.cs" /> - <Compile Include="Logging\LogHelper.cs" /> - <Compile Include="Logging\NLogger.cs" /> - <Compile Include="Logging\NlogManager.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="Security\MbAdmin.cs" /> - <Compile Include="Security\MBLicenseFile.cs" /> - <Compile Include="Security\PluginSecurityManager.cs" /> - <Compile Include="Security\RegRecord.cs" /> - <Compile Include="Security\SuppporterInfoResponse.cs" /> - <Compile Include="Serialization\JsonSerializer.cs" /> - <Compile Include="Serialization\XmlSerializer.cs" /> - <Compile Include="Updates\GithubUpdater.cs" /> - <Compile Include="Updates\InstallationManager.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> - <None Include="packages.config" /> - </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 5e00514d55..0000000000 --- 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 63a83e0034..0000000000 --- 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 3d33e958de..0000000000 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/DailyTrigger.cs +++ /dev/null @@ -1,91 +0,0 @@ -using MediaBrowser.Model.Events; -using MediaBrowser.Model.Tasks; -using System; -using System.Globalization; -using System.Threading; -using MediaBrowser.Model.Logging; - -namespace MediaBrowser.Common.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 8038d5551d..0000000000 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/IntervalTrigger.cs +++ /dev/null @@ -1,112 +0,0 @@ -using MediaBrowser.Model.Events; -using MediaBrowser.Model.Tasks; -using System; -using System.Linq; -using System.Threading; -using MediaBrowser.Model.Logging; - -namespace MediaBrowser.Common.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 0d99283c3d..0000000000 --- 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 41f58a7ad5..0000000000 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/StartupTrigger.cs +++ /dev/null @@ -1,67 +0,0 @@ -using MediaBrowser.Model.Events; -using MediaBrowser.Model.Tasks; -using System; -using System.Threading.Tasks; -using MediaBrowser.Model.Logging; - -namespace MediaBrowser.Common.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 9972dc8044..0000000000 --- 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 9a0221deab..0000000000 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs +++ /dev/null @@ -1,364 +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 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; } - - /// <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) - { - ApplicationPaths = applicationPaths; - JsonSerializer = jsonSerializer; - Logger = logger; - _fileSystem = fileSystem; - - ScheduledTasks = new IScheduledTaskWorker[] { }; - } - - private void BindToSystemEvent() - { - try - { - SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; - } - catch - { - - } - } - - void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs 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 2cd3f4c0f5..0000000000 --- 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 336f91f963..0000000000 --- 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 3c33df832e..0000000000 --- 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 318802e07d..0000000000 --- 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.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/Security/MBLicenseFile.cs b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs deleted file mode 100644 index 78515cd141..0000000000 --- a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs +++ /dev/null @@ -1,157 +0,0 @@ -using MediaBrowser.Common.Configuration; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; - -namespace MediaBrowser.Common.Implementations.Security -{ - internal class MBLicenseFile - { - private readonly IApplicationPaths _appPaths; - - public string RegKey - { - get { return _regKey; } - set - { - if (value != _regKey) - { - //if key is changed - clear out our saved validations - _updateRecords.Clear(); - _regKey = value; - } - } - } - - private string Filename - { - get - { - return Path.Combine(_appPaths.ConfigurationDirectoryPath, "mb.lic"); - } - } - - private readonly ConcurrentDictionary<Guid, DateTime> _updateRecords = new ConcurrentDictionary<Guid, DateTime>(); - private readonly object _fileLock = new object(); - private string _regKey; - - public MBLicenseFile(IApplicationPaths appPaths) - { - _appPaths = appPaths; - - Load(); - } - - private void SetUpdateRecord(Guid key, DateTime value) - { - _updateRecords.AddOrUpdate(key, value, (k, v) => value); - } - - public void AddRegCheck(string featureId) - { - using (var provider = new MD5CryptoServiceProvider()) - { - var key = new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId))); - var value = DateTime.UtcNow; - - SetUpdateRecord(key, value); - Save(); - } - - } - - public void RemoveRegCheck(string featureId) - { - using (var provider = new MD5CryptoServiceProvider()) - { - var key = new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId))); - DateTime val; - - _updateRecords.TryRemove(key, out val); - - Save(); - } - - } - - public DateTime LastChecked(string featureId) - { - using (var provider = new MD5CryptoServiceProvider()) - { - DateTime last; - _updateRecords.TryGetValue(new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId))), out last); - - // guard agains people just putting a large number in the file - return last < DateTime.UtcNow ? last : DateTime.MinValue; - } - } - - private void Load() - { - string[] contents = null; - var licenseFile = Filename; - lock (_fileLock) - { - try - { - contents = File.ReadAllLines(licenseFile); - } - catch (DirectoryNotFoundException) - { - File.Create(licenseFile).Close(); - } - catch (FileNotFoundException) - { - File.Create(licenseFile).Close(); - } - } - if (contents != null && contents.Length > 0) - { - //first line is reg key - RegKey = contents[0]; - - //next is legacy key - if (contents.Length > 1) - { - // Don't need this anymore - } - - //the rest of the lines should be pairs of features and timestamps - for (var i = 2; i < contents.Length; i = i + 2) - { - var feat = Guid.Parse(contents[i]); - - SetUpdateRecord(feat, new DateTime(Convert.ToInt64(contents[i + 1]))); - } - } - } - - public void Save() - { - //build our array - var lines = new List<string> - { - RegKey, - - // Legacy key - string.Empty - }; - - foreach (var pair in _updateRecords - .ToList()) - { - lines.Add(pair.Key.ToString()); - lines.Add(pair.Value.Ticks.ToString(CultureInfo.InvariantCulture)); - } - - var licenseFile = Filename; - Directory.CreateDirectory(Path.GetDirectoryName(licenseFile)); - lock (_fileLock) File.WriteAllLines(licenseFile, lines); - } - } -} diff --git a/MediaBrowser.Common.Implementations/Security/MbAdmin.cs b/MediaBrowser.Common.Implementations/Security/MbAdmin.cs deleted file mode 100644 index 76ff92c2eb..0000000000 --- a/MediaBrowser.Common.Implementations/Security/MbAdmin.cs +++ /dev/null @@ -1,13 +0,0 @@ - -namespace MediaBrowser.Common.Implementations.Security -{ - public class MbAdmin - { - public const string HttpUrl = "https://www.mb3admin.com/admin/"; - - /// <summary> - /// Leaving as http for now until we get it squared away - /// </summary> - public const string HttpsUrl = "https://www.mb3admin.com/admin/"; - } -} diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs deleted file mode 100644 index 5d440609ef..0000000000 --- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs +++ /dev/null @@ -1,337 +0,0 @@ -using System.IO; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Security; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Net; - -namespace MediaBrowser.Common.Implementations.Security -{ - /// <summary> - /// Class PluginSecurityManager - /// </summary> - public class PluginSecurityManager : ISecurityManager - { - private const string MBValidateUrl = MbAdmin.HttpsUrl + "service/registration/validate"; - private const string AppstoreRegUrl = /*MbAdmin.HttpsUrl*/ "https://mb3admin.com/admin/service/appstore/register"; - - /// <summary> - /// The _is MB supporter - /// </summary> - private bool? _isMbSupporter; - /// <summary> - /// The _is MB supporter initialized - /// </summary> - private bool _isMbSupporterInitialized; - /// <summary> - /// The _is MB supporter sync lock - /// </summary> - private object _isMbSupporterSyncLock = new object(); - - /// <summary> - /// Gets a value indicating whether this instance is MB supporter. - /// </summary> - /// <value><c>true</c> if this instance is MB supporter; otherwise, <c>false</c>.</value> - public bool IsMBSupporter - { - get - { - LazyInitializer.EnsureInitialized(ref _isMbSupporter, ref _isMbSupporterInitialized, ref _isMbSupporterSyncLock, () => GetSupporterRegistrationStatus().Result.IsRegistered); - return _isMbSupporter.Value; - } - } - - private MBLicenseFile _licenseFile; - private MBLicenseFile LicenseFile - { - get { return _licenseFile ?? (_licenseFile = new MBLicenseFile(_appPaths)); } - } - - private readonly IHttpClient _httpClient; - private readonly IJsonSerializer _jsonSerializer; - private readonly IApplicationHost _appHost; - private readonly ILogger _logger; - private readonly IApplicationPaths _appPaths; - - private IEnumerable<IRequiresRegistration> _registeredEntities; - protected IEnumerable<IRequiresRegistration> RegisteredEntities - { - get - { - return _registeredEntities ?? (_registeredEntities = _appHost.GetExports<IRequiresRegistration>()); - } - } - - /// <summary> - /// Initializes a new instance of the <see cref="PluginSecurityManager" /> class. - /// </summary> - public PluginSecurityManager(IApplicationHost appHost, IHttpClient httpClient, IJsonSerializer jsonSerializer, - IApplicationPaths appPaths, ILogManager logManager) - { - if (httpClient == null) - { - throw new ArgumentNullException("httpClient"); - } - - _appHost = appHost; - _httpClient = httpClient; - _jsonSerializer = jsonSerializer; - _appPaths = appPaths; - _logger = logManager.GetLogger("SecurityManager"); - } - - /// <summary> - /// Load all registration info for all entities that require registration - /// </summary> - /// <returns></returns> - public async Task LoadAllRegistrationInfo() - { - var tasks = new List<Task>(); - - ResetSupporterInfo(); - tasks.AddRange(RegisteredEntities.Select(i => i.LoadRegistrationInfoAsync())); - await Task.WhenAll(tasks); - } - - /// <summary> - /// Gets the registration status. - /// This overload supports existing plug-ins. - /// </summary> - /// <param name="feature">The feature.</param> - /// <param name="mb2Equivalent">The MB2 equivalent.</param> - /// <returns>Task{MBRegistrationRecord}.</returns> - public Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent = null) - { - return GetRegistrationStatusInternal(feature, mb2Equivalent); - } - - /// <summary> - /// Gets the registration status. - /// </summary> - /// <param name="feature">The feature.</param> - /// <param name="mb2Equivalent">The MB2 equivalent.</param> - /// <param name="version">The version of this feature</param> - /// <returns>Task{MBRegistrationRecord}.</returns> - public Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent, string version) - { - return GetRegistrationStatusInternal(feature, mb2Equivalent, version); - } - - private Task<MBRegistrationRecord> GetSupporterRegistrationStatus() - { - return GetRegistrationStatusInternal("MBSupporter", null, _appHost.ApplicationVersion.ToString()); - } - - /// <summary> - /// Gets or sets the supporter key. - /// </summary> - /// <value>The supporter key.</value> - public string SupporterKey - { - get - { - return LicenseFile.RegKey; - } - set - { - var newValue = value; - if (newValue != null) - { - newValue = newValue.Trim(); - } - - if (newValue != LicenseFile.RegKey) - { - LicenseFile.RegKey = newValue; - LicenseFile.Save(); - - // re-load registration info - Task.Run(() => LoadAllRegistrationInfo()); - } - } - } - - /// <summary> - /// Register an app store sale with our back-end. It will validate the transaction with the store - /// and then register the proper feature and then fill in the supporter key on success. - /// </summary> - /// <param name="parameters">Json parameters to send to admin server</param> - public async Task RegisterAppStoreSale(string parameters) - { - var options = new HttpRequestOptions() - { - Url = AppstoreRegUrl, - CancellationToken = CancellationToken.None, - BufferContent = false - }; - options.RequestHeaders.Add("X-Emby-Token", _appHost.SystemId); - options.RequestContent = parameters; - options.RequestContentType = "application/json"; - - try - { - using (var response = await _httpClient.Post(options).ConfigureAwait(false)) - { - var reg = _jsonSerializer.DeserializeFromStream<RegRecord>(response.Content); - - if (reg == null) - { - var msg = "Result from appstore registration was null."; - _logger.Error(msg); - throw new ApplicationException(msg); - } - if (!String.IsNullOrEmpty(reg.key)) - { - SupporterKey = reg.key; - } - } - - } - catch (ApplicationException) - { - SaveAppStoreInfo(parameters); - throw; - } - catch (HttpException e) - { - _logger.ErrorException("Error registering appstore purchase {0}", e, parameters ?? "NO PARMS SENT"); - - if (e.StatusCode.HasValue && e.StatusCode.Value == HttpStatusCode.PaymentRequired) - { - throw new PaymentRequiredException(); - } - throw new ApplicationException("Error registering store sale"); - } - catch (Exception e) - { - _logger.ErrorException("Error registering appstore purchase {0}", e, parameters ?? "NO PARMS SENT"); - SaveAppStoreInfo(parameters); - //TODO - could create a re-try routine on start-up if this file is there. For now we can handle manually. - throw new ApplicationException("Error registering store sale"); - } - - } - - private void SaveAppStoreInfo(string info) - { - // Save all transaction information to a file - - try - { - File.WriteAllText(Path.Combine(_appPaths.ProgramDataPath, "apptrans-error.txt"), info); - } - catch (IOException) - { - - } - } - - private async Task<MBRegistrationRecord> GetRegistrationStatusInternal(string feature, - string mb2Equivalent = null, - string version = null) - { - var lastChecked = LicenseFile.LastChecked(feature); - - //check the reg file first to alleviate strain on the MB admin server - must actually check in every 30 days tho - var reg = new RegRecord - { - // Cache the result for up to a week - registered = lastChecked > DateTime.UtcNow.AddDays(-7) - }; - - var success = reg.registered; - - if (!(lastChecked > DateTime.UtcNow.AddDays(-1))) - { - var data = new Dictionary<string, string> - { - { "feature", feature }, - { "key", SupporterKey }, - { "mac", _appHost.SystemId }, - { "systemid", _appHost.SystemId }, - { "mb2equiv", mb2Equivalent }, - { "ver", version }, - { "platform", _appHost.OperatingSystemDisplayName }, - { "isservice", _appHost.IsRunningAsService.ToString().ToLower() } - }; - - try - { - var options = new HttpRequestOptions - { - Url = MBValidateUrl, - - // Seeing block length errors - EnableHttpCompression = false, - BufferContent = false - }; - - options.SetPostData(data); - - using (var json = (await _httpClient.Post(options).ConfigureAwait(false)).Content) - { - reg = _jsonSerializer.DeserializeFromStream<RegRecord>(json); - success = true; - } - - if (reg.registered) - { - LicenseFile.AddRegCheck(feature); - } - else - { - LicenseFile.RemoveRegCheck(feature); - } - - } - catch (Exception e) - { - _logger.ErrorException("Error checking registration status of {0}", e, feature); - } - } - - var record = new MBRegistrationRecord - { - IsRegistered = reg.registered, - ExpirationDate = reg.expDate, - RegChecked = true, - RegError = !success - }; - - record.TrialVersion = IsInTrial(reg.expDate, record.RegChecked, record.IsRegistered); - record.IsValid = !record.RegChecked || record.IsRegistered || record.TrialVersion; - - return record; - } - - private bool IsInTrial(DateTime expirationDate, bool regChecked, bool isRegistered) - { - //don't set this until we've successfully obtained exp date - if (!regChecked) - { - return false; - } - - var isInTrial = expirationDate > DateTime.UtcNow; - - return isInTrial && !isRegistered; - } - - /// <summary> - /// Resets the supporter info. - /// </summary> - private void ResetSupporterInfo() - { - _isMbSupporter = null; - _isMbSupporterInitialized = false; - } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Common.Implementations/Security/RegRecord.cs b/MediaBrowser.Common.Implementations/Security/RegRecord.cs deleted file mode 100644 index ece70b7726..0000000000 --- a/MediaBrowser.Common.Implementations/Security/RegRecord.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace MediaBrowser.Common.Implementations.Security -{ - class RegRecord - { - public string featId { get; set; } - public bool registered { get; set; } - public DateTime expDate { get; set; } - public string key { get; set; } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Common.Implementations/Security/SuppporterInfoResponse.cs b/MediaBrowser.Common.Implementations/Security/SuppporterInfoResponse.cs deleted file mode 100644 index 49c5af8d82..0000000000 --- a/MediaBrowser.Common.Implementations/Security/SuppporterInfoResponse.cs +++ /dev/null @@ -1,14 +0,0 @@ - -namespace MediaBrowser.Common.Implementations.Security -{ - internal class SuppporterInfoResponse - { - public string email { get; set; } - public string supporterKey { get; set; } - public int totalRegs { get; set; } - public int totalMachines { get; set; } - public string expDate { get; set; } - public string regDate { get; set; } - public string planType { get; set; } - } -} diff --git a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs deleted file mode 100644 index 98d2967ac5..0000000000 --- a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs +++ /dev/null @@ -1,228 +0,0 @@ -using MediaBrowser.Model.Serialization; -using System; -using System.IO; -using MediaBrowser.Common.IO; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; - -namespace MediaBrowser.Common.Implementations.Serialization -{ - /// <summary> - /// Provides a wrapper around third party json serialization. - /// </summary> - public class JsonSerializer : IJsonSerializer - { - private readonly IFileSystem _fileSystem; - private readonly ILogger _logger; - - public JsonSerializer(IFileSystem fileSystem, ILogger logger) - { - _fileSystem = fileSystem; - _logger = logger; - Configure(); - } - - /// <summary> - /// Serializes to stream. - /// </summary> - /// <param name="obj">The obj.</param> - /// <param name="stream">The stream.</param> - /// <exception cref="System.ArgumentNullException">obj</exception> - public void SerializeToStream(object obj, Stream stream) - { - if (obj == null) - { - throw new ArgumentNullException("obj"); - } - - if (stream == null) - { - throw new ArgumentNullException("stream"); - } - - ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream); - } - - /// <summary> - /// Serializes to file. - /// </summary> - /// <param name="obj">The obj.</param> - /// <param name="file">The file.</param> - /// <exception cref="System.ArgumentNullException">obj</exception> - public void SerializeToFile(object obj, string file) - { - if (obj == null) - { - throw new ArgumentNullException("obj"); - } - - if (string.IsNullOrEmpty(file)) - { - throw new ArgumentNullException("file"); - } - - using (Stream stream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) - { - SerializeToStream(obj, stream); - } - } - - private Stream OpenFile(string path) - { - _logger.Debug("Deserializing file {0}", path); - return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 131072); - } - - /// <summary> - /// Deserializes from file. - /// </summary> - /// <param name="type">The type.</param> - /// <param name="file">The file.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">type</exception> - public object DeserializeFromFile(Type type, string file) - { - if (type == null) - { - throw new ArgumentNullException("type"); - } - - if (string.IsNullOrEmpty(file)) - { - throw new ArgumentNullException("file"); - } - - using (Stream stream = OpenFile(file)) - { - return DeserializeFromStream(stream, type); - } - } - - /// <summary> - /// Deserializes from file. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="file">The file.</param> - /// <returns>``0.</returns> - /// <exception cref="System.ArgumentNullException">file</exception> - public T DeserializeFromFile<T>(string file) - where T : class - { - if (string.IsNullOrEmpty(file)) - { - throw new ArgumentNullException("file"); - } - - using (Stream stream = OpenFile(file)) - { - return DeserializeFromStream<T>(stream); - } - } - - /// <summary> - /// Deserializes from stream. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="stream">The stream.</param> - /// <returns>``0.</returns> - /// <exception cref="System.ArgumentNullException">stream</exception> - public T DeserializeFromStream<T>(Stream stream) - { - if (stream == null) - { - throw new ArgumentNullException("stream"); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromStream<T>(stream); - } - - /// <summary> - /// Deserializes from string. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="text">The text.</param> - /// <returns>``0.</returns> - /// <exception cref="System.ArgumentNullException">text</exception> - public T DeserializeFromString<T>(string text) - { - if (string.IsNullOrEmpty(text)) - { - throw new ArgumentNullException("text"); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(text); - } - - /// <summary> - /// Deserializes from stream. - /// </summary> - /// <param name="stream">The stream.</param> - /// <param name="type">The type.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">stream</exception> - public object DeserializeFromStream(Stream stream, Type type) - { - if (stream == null) - { - throw new ArgumentNullException("stream"); - } - - if (type == null) - { - throw new ArgumentNullException("type"); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream); - } - - /// <summary> - /// Configures this instance. - /// </summary> - private void Configure() - { - ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.DateHandler.ISO8601; - ServiceStack.Text.JsConfig.ExcludeTypeInfo = true; - ServiceStack.Text.JsConfig.IncludeNullValues = false; - ServiceStack.Text.JsConfig.AlwaysUseUtc = true; - ServiceStack.Text.JsConfig.AssumeUtc = true; - } - - /// <summary> - /// Deserializes from string. - /// </summary> - /// <param name="json">The json.</param> - /// <param name="type">The type.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">json</exception> - public object DeserializeFromString(string json, Type type) - { - if (string.IsNullOrEmpty(json)) - { - throw new ArgumentNullException("json"); - } - - if (type == null) - { - throw new ArgumentNullException("type"); - } - - return ServiceStack.Text.JsonSerializer.DeserializeFromString(json, type); - } - - /// <summary> - /// Serializes to string. - /// </summary> - /// <param name="obj">The obj.</param> - /// <returns>System.String.</returns> - /// <exception cref="System.ArgumentNullException">obj</exception> - public string SerializeToString(object obj) - { - if (obj == null) - { - throw new ArgumentNullException("obj"); - } - - return ServiceStack.Text.JsonSerializer.SerializeToString(obj, obj.GetType()); - } - } -} diff --git a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs deleted file mode 100644 index f486813049..0000000000 --- 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 371c2ea113..0000000000 --- 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; } - } - } -} diff --git a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs deleted file mode 100644 index 934898f778..0000000000 --- a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs +++ /dev/null @@ -1,686 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Events; -using MediaBrowser.Common.Implementations.Security; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Plugins; -using MediaBrowser.Common.Progress; -using MediaBrowser.Common.Security; -using MediaBrowser.Common.Updates; -using MediaBrowser.Model.Events; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Updates; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Model.IO; - -namespace MediaBrowser.Common.Implementations.Updates -{ - /// <summary> - /// Manages all install, uninstall and update operations (both plugins and system) - /// </summary> - public class InstallationManager : IInstallationManager - { - public event EventHandler<InstallationEventArgs> PackageInstalling; - public event EventHandler<InstallationEventArgs> PackageInstallationCompleted; - public event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed; - public event EventHandler<InstallationEventArgs> PackageInstallationCancelled; - - /// <summary> - /// The current installations - /// </summary> - public List<Tuple<InstallationInfo, CancellationTokenSource>> CurrentInstallations { get; set; } - - /// <summary> - /// The completed installations - /// </summary> - public ConcurrentBag<InstallationInfo> CompletedInstallations { get; set; } - - #region PluginUninstalled Event - /// <summary> - /// Occurs when [plugin uninstalled]. - /// </summary> - public event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled; - - /// <summary> - /// Called when [plugin uninstalled]. - /// </summary> - /// <param name="plugin">The plugin.</param> - private void OnPluginUninstalled(IPlugin plugin) - { - EventHelper.FireEventIfNotNull(PluginUninstalled, this, new GenericEventArgs<IPlugin> { Argument = plugin }, _logger); - } - #endregion - - #region PluginUpdated Event - /// <summary> - /// Occurs when [plugin updated]. - /// </summary> - public event EventHandler<GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>>> PluginUpdated; - /// <summary> - /// Called when [plugin updated]. - /// </summary> - /// <param name="plugin">The plugin.</param> - /// <param name="newVersion">The new version.</param> - private void OnPluginUpdated(IPlugin plugin, PackageVersionInfo newVersion) - { - _logger.Info("Plugin updated: {0} {1} {2}", newVersion.name, newVersion.versionStr ?? string.Empty, newVersion.classification); - - EventHelper.FireEventIfNotNull(PluginUpdated, this, new GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>> { Argument = new Tuple<IPlugin, PackageVersionInfo>(plugin, newVersion) }, _logger); - - _applicationHost.NotifyPendingRestart(); - } - #endregion - - #region PluginInstalled Event - /// <summary> - /// Occurs when [plugin updated]. - /// </summary> - public event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled; - /// <summary> - /// Called when [plugin installed]. - /// </summary> - /// <param name="package">The package.</param> - private void OnPluginInstalled(PackageVersionInfo package) - { - _logger.Info("New plugin installed: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification); - - EventHelper.FireEventIfNotNull(PluginInstalled, this, new GenericEventArgs<PackageVersionInfo> { Argument = package }, _logger); - - _applicationHost.NotifyPendingRestart(); - } - #endregion - - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - - private readonly IApplicationPaths _appPaths; - private readonly IHttpClient _httpClient; - private readonly IJsonSerializer _jsonSerializer; - private readonly ISecurityManager _securityManager; - private readonly IConfigurationManager _config; - private readonly IFileSystem _fileSystem; - - /// <summary> - /// Gets the application host. - /// </summary> - /// <value>The application host.</value> - private readonly IApplicationHost _applicationHost; - - public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config, IFileSystem fileSystem) - { - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - CurrentInstallations = new List<Tuple<InstallationInfo, CancellationTokenSource>>(); - CompletedInstallations = new ConcurrentBag<InstallationInfo>(); - - _applicationHost = appHost; - _appPaths = appPaths; - _httpClient = httpClient; - _jsonSerializer = jsonSerializer; - _securityManager = securityManager; - _config = config; - _fileSystem = fileSystem; - _logger = logger; - } - - private Version GetPackageVersion(PackageVersionInfo version) - { - return new Version(ValueOrDefault(version.versionStr, "0.0.0.1")); - } - - private static string ValueOrDefault(string str, string def) - { - return string.IsNullOrEmpty(str) ? def : str; - } - - /// <summary> - /// Gets all available packages. - /// </summary> - /// <returns>Task{List{PackageInfo}}.</returns> - public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken, - bool withRegistration = true, - string packageType = null, - Version applicationVersion = null) - { - var data = new Dictionary<string, string> - { - { "key", _securityManager.SupporterKey }, - { "mac", _applicationHost.SystemId }, - { "systemid", _applicationHost.SystemId } - }; - - if (withRegistration) - { - using (var json = await _httpClient.Post(MbAdmin.HttpsUrl + "service/package/retrieveall", data, cancellationToken).ConfigureAwait(false)) - { - cancellationToken.ThrowIfCancellationRequested(); - - var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(json).ToList(); - - return FilterPackages(packages, packageType, applicationVersion); - } - } - else - { - var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); - - return FilterPackages(packages.ToList(), packageType, applicationVersion); - } - } - - private DateTime _lastPackageUpdateTime; - - /// <summary> - /// Gets all available packages. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{List{PackageInfo}}.</returns> - public async Task<IEnumerable<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken) - { - _logger.Info("Opening {0}", PackageCachePath); - try - { - using (var stream = _fileSystem.OpenRead(PackageCachePath)) - { - var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(stream).ToList(); - - if (DateTime.UtcNow - _lastPackageUpdateTime > GetCacheLength()) - { - UpdateCachedPackages(CancellationToken.None, false); - } - - return packages; - } - } - catch (Exception) - { - - } - - _lastPackageUpdateTime = DateTime.MinValue; - await UpdateCachedPackages(cancellationToken, true).ConfigureAwait(false); - using (var stream = _fileSystem.OpenRead(PackageCachePath)) - { - return _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(stream).ToList(); - } - } - - private string PackageCachePath - { - get { return Path.Combine(_appPaths.CachePath, "serverpackages.json"); } - } - - private readonly SemaphoreSlim _updateSemaphore = new SemaphoreSlim(1, 1); - private async Task UpdateCachedPackages(CancellationToken cancellationToken, bool throwErrors) - { - await _updateSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - if (DateTime.UtcNow - _lastPackageUpdateTime < GetCacheLength()) - { - return; - } - - var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions - { - Url = MbAdmin.HttpUrl + "service/MB3Packages.json", - CancellationToken = cancellationToken, - Progress = new Progress<Double>() - - }).ConfigureAwait(false); - - _fileSystem.CreateDirectory(Path.GetDirectoryName(PackageCachePath)); - - _fileSystem.CopyFile(tempFile, PackageCachePath, true); - _lastPackageUpdateTime = DateTime.UtcNow; - } - catch (Exception ex) - { - _logger.ErrorException("Error updating package cache", ex); - - if (throwErrors) - { - throw; - } - } - finally - { - _updateSemaphore.Release(); - } - } - - private TimeSpan GetCacheLength() - { - switch (_config.CommonConfiguration.SystemUpdateLevel) - { - case PackageVersionClass.Beta: - return TimeSpan.FromMinutes(30); - case PackageVersionClass.Dev: - return TimeSpan.FromMinutes(3); - default: - return TimeSpan.FromHours(24); - } - } - - protected IEnumerable<PackageInfo> FilterPackages(List<PackageInfo> packages) - { - foreach (var package in packages) - { - package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl)) - .OrderByDescending(GetPackageVersion).ToList(); - } - - // Remove packages with no versions - packages = packages.Where(p => p.versions.Any()).ToList(); - - return packages; - } - - protected IEnumerable<PackageInfo> FilterPackages(List<PackageInfo> packages, string packageType, Version applicationVersion) - { - foreach (var package in packages) - { - package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl)) - .OrderByDescending(GetPackageVersion).ToList(); - } - - if (!string.IsNullOrWhiteSpace(packageType)) - { - packages = packages.Where(p => string.Equals(p.type, packageType, StringComparison.OrdinalIgnoreCase)).ToList(); - } - - // If an app version was supplied, filter the versions for each package to only include supported versions - if (applicationVersion != null) - { - foreach (var package in packages) - { - package.versions = package.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToList(); - } - } - - // Remove packages with no versions - packages = packages.Where(p => p.versions.Any()).ToList(); - - return packages; - } - - /// <summary> - /// Determines whether [is package version up to date] [the specified package version info]. - /// </summary> - /// <param name="packageVersionInfo">The package version info.</param> - /// <param name="currentServerVersion">The current server version.</param> - /// <returns><c>true</c> if [is package version up to date] [the specified package version info]; otherwise, <c>false</c>.</returns> - private bool IsPackageVersionUpToDate(PackageVersionInfo packageVersionInfo, Version currentServerVersion) - { - if (string.IsNullOrEmpty(packageVersionInfo.requiredVersionStr)) - { - return true; - } - - Version requiredVersion; - - return Version.TryParse(packageVersionInfo.requiredVersionStr, out requiredVersion) && currentServerVersion >= requiredVersion; - } - - /// <summary> - /// Gets the package. - /// </summary> - /// <param name="name">The name.</param> - /// <param name="guid">The assembly guid</param> - /// <param name="classification">The classification.</param> - /// <param name="version">The version.</param> - /// <returns>Task{PackageVersionInfo}.</returns> - public async Task<PackageVersionInfo> GetPackage(string name, string guid, PackageVersionClass classification, Version version) - { - var packages = await GetAvailablePackages(CancellationToken.None).ConfigureAwait(false); - - var package = packages.FirstOrDefault(p => string.Equals(p.guid, guid ?? "none", StringComparison.OrdinalIgnoreCase)) - ?? packages.FirstOrDefault(p => p.name.Equals(name, StringComparison.OrdinalIgnoreCase)); - - if (package == null) - { - return null; - } - - return package.versions.FirstOrDefault(v => GetPackageVersion(v).Equals(version) && v.classification == classification); - } - - /// <summary> - /// Gets the latest compatible version. - /// </summary> - /// <param name="name">The name.</param> - /// <param name="guid">The assembly guid if this is a plug-in</param> - /// <param name="currentServerVersion">The current server version.</param> - /// <param name="classification">The classification.</param> - /// <returns>Task{PackageVersionInfo}.</returns> - public async Task<PackageVersionInfo> GetLatestCompatibleVersion(string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release) - { - var packages = await GetAvailablePackages(CancellationToken.None).ConfigureAwait(false); - - return GetLatestCompatibleVersion(packages, name, guid, currentServerVersion, classification); - } - - /// <summary> - /// Gets the latest compatible version. - /// </summary> - /// <param name="availablePackages">The available packages.</param> - /// <param name="name">The name.</param> - /// <param name="currentServerVersion">The current server version.</param> - /// <param name="classification">The classification.</param> - /// <returns>PackageVersionInfo.</returns> - public PackageVersionInfo GetLatestCompatibleVersion(IEnumerable<PackageInfo> availablePackages, string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release) - { - var package = availablePackages.FirstOrDefault(p => string.Equals(p.guid, guid ?? "none", StringComparison.OrdinalIgnoreCase)) - ?? availablePackages.FirstOrDefault(p => p.name.Equals(name, StringComparison.OrdinalIgnoreCase)); - - if (package == null) - { - return null; - } - - return package.versions - .OrderByDescending(GetPackageVersion) - .FirstOrDefault(v => v.classification <= classification && IsPackageVersionUpToDate(v, currentServerVersion)); - } - - /// <summary> - /// Gets the available plugin updates. - /// </summary> - /// <param name="applicationVersion">The current server version.</param> - /// <param name="withAutoUpdateEnabled">if set to <c>true</c> [with auto update enabled].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns> - public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken) - { - var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); - - var plugins = _applicationHost.Plugins.ToList(); - - if (withAutoUpdateEnabled) - { - plugins = plugins - .Where(p => _config.CommonConfiguration.EnableAutoUpdate) - .ToList(); - } - - // Figure out what needs to be installed - var packages = plugins.Select(p => - { - var latestPluginInfo = GetLatestCompatibleVersion(catalog, p.Name, p.Id.ToString(), applicationVersion, _config.CommonConfiguration.SystemUpdateLevel); - - return latestPluginInfo != null && GetPackageVersion(latestPluginInfo) > p.Version ? latestPluginInfo : null; - - }).Where(i => i != null).ToList(); - - return packages - .Where(p => !string.IsNullOrWhiteSpace(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase))); - } - - /// <summary> - /// Installs the package. - /// </summary> - /// <param name="package">The package.</param> - /// <param name="isPlugin">if set to <c>true</c> [is plugin].</param> - /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException">package</exception> - public async Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken) - { - if (package == null) - { - throw new ArgumentNullException("package"); - } - - if (progress == null) - { - throw new ArgumentNullException("progress"); - } - - var installationInfo = new InstallationInfo - { - Id = Guid.NewGuid().ToString("N"), - Name = package.name, - AssemblyGuid = package.guid, - UpdateClass = package.classification, - Version = package.versionStr - }; - - var innerCancellationTokenSource = new CancellationTokenSource(); - - var tuple = new Tuple<InstallationInfo, CancellationTokenSource>(installationInfo, innerCancellationTokenSource); - - // Add it to the in-progress list - lock (CurrentInstallations) - { - CurrentInstallations.Add(tuple); - } - - var innerProgress = new ActionableProgress<double>(); - - // Whenever the progress updates, update the outer progress object and InstallationInfo - innerProgress.RegisterAction(percent => - { - progress.Report(percent); - - installationInfo.PercentComplete = percent; - }); - - var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token; - - var installationEventArgs = new InstallationEventArgs - { - InstallationInfo = installationInfo, - PackageVersionInfo = package - }; - - EventHelper.FireEventIfNotNull(PackageInstalling, this, installationEventArgs, _logger); - - try - { - await InstallPackageInternal(package, isPlugin, innerProgress, linkedToken).ConfigureAwait(false); - - lock (CurrentInstallations) - { - CurrentInstallations.Remove(tuple); - } - - progress.Report(100); - - CompletedInstallations.Add(installationInfo); - - EventHelper.FireEventIfNotNull(PackageInstallationCompleted, this, installationEventArgs, _logger); - } - catch (OperationCanceledException) - { - lock (CurrentInstallations) - { - CurrentInstallations.Remove(tuple); - } - - _logger.Info("Package installation cancelled: {0} {1}", package.name, package.versionStr); - - EventHelper.FireEventIfNotNull(PackageInstallationCancelled, this, installationEventArgs, _logger); - - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Package installation failed", ex); - - lock (CurrentInstallations) - { - CurrentInstallations.Remove(tuple); - } - - EventHelper.FireEventIfNotNull(PackageInstallationFailed, this, new InstallationFailedEventArgs - { - InstallationInfo = installationInfo, - Exception = ex - - }, _logger); - - throw; - } - finally - { - // Dispose the progress object and remove the installation from the in-progress list - innerProgress.Dispose(); - tuple.Item2.Dispose(); - } - } - - /// <summary> - /// Installs the package internal. - /// </summary> - /// <param name="package">The package.</param> - /// <param name="isPlugin">if set to <c>true</c> [is plugin].</param> - /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - private async Task InstallPackageInternal(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken) - { - // Do the install - await PerformPackageInstallation(progress, package, cancellationToken).ConfigureAwait(false); - - // Do plugin-specific processing - if (isPlugin) - { - // Set last update time if we were installed before - var plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase)) - ?? _applicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase)); - - if (plugin != null) - { - OnPluginUpdated(plugin, package); - } - else - { - OnPluginInstalled(package); - } - } - } - - private async Task PerformPackageInstallation(IProgress<double> progress, PackageVersionInfo package, CancellationToken cancellationToken) - { - // Target based on if it is an archive or single assembly - // zip archives are assumed to contain directory structures relative to our ProgramDataPath - var extension = Path.GetExtension(package.targetFilename); - var isArchive = string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase); - var target = Path.Combine(isArchive ? _appPaths.TempUpdatePath : _appPaths.PluginsPath, package.targetFilename); - - // Download to temporary file so that, if interrupted, it won't destroy the existing installation - var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions - { - Url = package.sourceUrl, - CancellationToken = cancellationToken, - Progress = progress - - }).ConfigureAwait(false); - - cancellationToken.ThrowIfCancellationRequested(); - - // Validate with a checksum - var packageChecksum = string.IsNullOrWhiteSpace(package.checksum) ? Guid.Empty : new Guid(package.checksum); - if (packageChecksum != Guid.Empty) // support for legacy uploads for now - { - using (var crypto = new MD5CryptoServiceProvider()) - using (var stream = new BufferedStream(_fileSystem.OpenRead(tempFile), 100000)) - { - var check = Guid.Parse(BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", String.Empty)); - if (check != packageChecksum) - { - throw new ApplicationException(string.Format("Download validation failed for {0}. Probably corrupted during transfer.", package.name)); - } - } - } - - cancellationToken.ThrowIfCancellationRequested(); - - // Success - move it to the real target - try - { - _fileSystem.CreateDirectory(Path.GetDirectoryName(target)); - _fileSystem.CopyFile(tempFile, target, true); - //If it is an archive - write out a version file so we know what it is - if (isArchive) - { - File.WriteAllText(target + ".ver", package.versionStr); - } - } - catch (IOException e) - { - _logger.ErrorException("Error attempting to move file from {0} to {1}", e, tempFile, target); - throw; - } - - try - { - _fileSystem.DeleteFile(tempFile); - } - catch (IOException e) - { - // Don't fail because of this - _logger.ErrorException("Error deleting temp file {0]", e, tempFile); - } - } - - /// <summary> - /// Uninstalls a plugin - /// </summary> - /// <param name="plugin">The plugin.</param> - /// <exception cref="System.ArgumentException"></exception> - public void UninstallPlugin(IPlugin plugin) - { - plugin.OnUninstalling(); - - // Remove it the quick way for now - _applicationHost.RemovePlugin(plugin); - - _fileSystem.DeleteFile(plugin.AssemblyFilePath); - - OnPluginUninstalled(plugin); - - _applicationHost.NotifyPendingRestart(); - } - - /// <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) - { - lock (CurrentInstallations) - { - foreach (var tuple in CurrentInstallations) - { - tuple.Item2.Dispose(); - } - - CurrentInstallations.Clear(); - } - } - } - - public void Dispose() - { - Dispose(true); - } - } -} diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config deleted file mode 100644 index 4eacd0d725..0000000000 --- a/MediaBrowser.Common.Implementations/packages.config +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<packages> - <package id="NLog" version="4.3.10" targetFramework="net46" /> - <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" /> - <package id="SimpleInjector" version="3.2.4" targetFramework="net46" /> -</packages>
\ No newline at end of file |
