using System; using System.Collections.Generic; using System.Linq; using FluentValidation.Results; using Microsoft.Extensions.DependencyInjection; using NLog; using NzbDrone.Common.Composition; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.ThingiProvider { public abstract class ProviderFactory : IProviderFactory, IHandle where TProviderDefinition : ProviderDefinition, new() where TProvider : IProvider { private readonly IProviderRepository _providerRepository; private readonly IServiceProvider _container; private readonly IEventAggregator _eventAggregator; private readonly Logger _logger; protected readonly List _providers; protected ProviderFactory(IProviderRepository providerRepository, IEnumerable providers, IServiceProvider container, IEventAggregator eventAggregator, Logger logger) { _providerRepository = providerRepository; _container = container; _eventAggregator = eventAggregator; _providers = providers.ToList(); _logger = logger; } public List All() { return _providerRepository.All().ToList(); } public IEnumerable GetDefaultDefinitions() { foreach (var provider in _providers) { var definition = provider.DefaultDefinitions .OfType() .FirstOrDefault(v => v.Name == null || v.Name == provider.GetType().Name); if (definition == null) { definition = new TProviderDefinition() { Name = string.Empty, ConfigContract = provider.ConfigContract.Name, Implementation = provider.GetType().Name, Settings = (IProviderConfig)Activator.CreateInstance(provider.ConfigContract) }; } SetProviderCharacteristics(provider, definition); yield return definition; } } public IEnumerable GetPresetDefinitions(TProviderDefinition providerDefinition) { var provider = _providers.First(v => v.GetType().Name == providerDefinition.Implementation); var definitions = provider.DefaultDefinitions .OfType() .Where(v => v.Name != null && v.Name != provider.GetType().Name) .ToList(); return definitions; } public virtual ValidationResult Test(TProviderDefinition definition) { return GetInstance(definition).Test(); } public object RequestAction(TProviderDefinition definition, string action, IDictionary query) { return GetInstance(definition).RequestAction(action, query); } public List GetAvailableProviders() { return Active().Select(GetInstance).ToList(); } public bool Exists(int id) { return _providerRepository.Find(id) != null; } public TProviderDefinition Get(int id) { return _providerRepository.Get(id); } public TProviderDefinition Find(int id) { return _providerRepository.Find(id); } public virtual TProviderDefinition Create(TProviderDefinition definition) { var addedDefinition = _providerRepository.Insert(definition); _eventAggregator.PublishEvent(new ProviderAddedEvent(definition)); return addedDefinition; } public virtual void Update(TProviderDefinition definition) { _providerRepository.Update(definition); _eventAggregator.PublishEvent(new ProviderUpdatedEvent(definition)); } public void Delete(int id) { _providerRepository.Delete(id); _eventAggregator.PublishEvent(new ProviderDeletedEvent(id)); } public TProvider GetInstance(TProviderDefinition definition) { var type = GetImplementation(definition); var instance = (TProvider)_container.GetRequiredService(type); instance.Definition = definition; SetProviderCharacteristics(instance, definition); return instance; } private Type GetImplementation(TProviderDefinition definition) { return _providers.Select(c => c.GetType()).SingleOrDefault(c => c.Name.Equals(definition.Implementation, StringComparison.InvariantCultureIgnoreCase)); } public void Handle(ApplicationStartedEvent message) { _logger.Debug("Initializing Providers. Count {0}", _providers.Count); RemoveMissingImplementations(); InitializeProviders(); } protected virtual void InitializeProviders() { } protected virtual List Active() { return All().Where(c => c.Settings.Validate().IsValid).ToList(); } public void SetProviderCharacteristics(TProviderDefinition definition) { GetInstance(definition); } public virtual void SetProviderCharacteristics(TProvider provider, TProviderDefinition definition) { definition.ImplementationName = provider.Name; definition.Message = provider.Message; } // TODO: Remove providers even if the ConfigContract can't be deserialized (this will fail to remove providers if the settings can't be deserialized). private void RemoveMissingImplementations() { var storedProvider = _providerRepository.All(); foreach (var invalidDefinition in storedProvider.Where(def => GetImplementation(def) == null)) { _logger.Debug("Removing {0} ", invalidDefinition.Name); _providerRepository.Delete(invalidDefinition); } } public List AllForTag(int tagId) { return All().Where(p => p.Tags.Contains(tagId)) .ToList(); } } }