diff --git a/Kyoo.Authentication/AuthenticationModule.cs b/Kyoo.Authentication/AuthenticationModule.cs index 1e9dcd01..8e3ea475 100644 --- a/Kyoo.Authentication/AuthenticationModule.cs +++ b/Kyoo.Authentication/AuthenticationModule.cs @@ -37,20 +37,8 @@ namespace Kyoo.Authentication /// public string Description => "Enable OpenID authentication for Kyoo."; - - /// - public ICollection Provides => ArraySegment.Empty; - - /// - public ICollection ConditionalProvides => ArraySegment.Empty; - - /// - public ICollection Requires => new [] - { - typeof(IUserRepository) - }; - - + + /// /// The configuration to use. /// @@ -88,7 +76,7 @@ namespace Kyoo.Authentication } /// - public void Configure(IServiceCollection services, ICollection availableTypes) + public void Configure(IServiceCollection services) { string publicUrl = _configuration.GetPublicUrl(); diff --git a/Kyoo.Common/Controllers/IPlugin.cs b/Kyoo.Common/Controllers/IPlugin.cs index ea072c39..06670ff3 100644 --- a/Kyoo.Common/Controllers/IPlugin.cs +++ b/Kyoo.Common/Controllers/IPlugin.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using Autofac; using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; @@ -34,29 +32,15 @@ namespace Kyoo.Controllers string Description { get; } /// - /// A list of services that are provided by this service. This allow other plugins to declare dependencies + /// true if the plugin should be enabled, false otherwise. + /// If a plugin is not enabled, no configure method will be called. + /// This allow one to enable a plugin if a specific configuration value is set or if the environment contains + /// the right settings. /// /// - /// You should put the type's interface that will be register in configure. + /// By default, a plugin is always enabled. This method can be overriden to change this behavior. /// - ICollection Provides { get; } - - /// - /// A list of types that will be provided only if a condition is met. The condition can be an arbitrary method or - /// a condition based on other type availability. For more information, see . - /// - ICollection ConditionalProvides { get; } - - /// - /// A list of services that are required by this plugin. - /// You can put services that you provide conditionally here if you want. - /// Kyoo will warn the user that this plugin can't be loaded if a required service is not found. - /// - /// - /// Put here the most complete type that are needed for your plugin to work. If you need a LibraryManager, - /// put typeof(ILibraryManager). - /// - ICollection Requires { get; } + virtual bool Enabled => true; /// /// A configure method that will be run on plugin's startup. @@ -69,14 +53,11 @@ namespace Kyoo.Controllers /// /// A configure method that will be run on plugin's startup. + /// This is available for libraries that build upon a , for more precise + /// configuration use . /// /// A service container to register new services. - /// The list of types that are available for this instance. This can be used - /// for conditional type. See - /// or > - /// You can't simply check on the service collection because some dependencies might be registered after your plugin. - /// - void Configure(IServiceCollection services, ICollection availableTypes) + void Configure(IServiceCollection services) { // Skipped } @@ -105,143 +86,4 @@ namespace Kyoo.Controllers // Skipped } } - - /// - /// A type that will only be provided if a special condition is met. To check that your condition is met, - /// you can check the class. - /// - public class ConditionalProvide : Tuple - { - /// - /// Get the type that may be provided - /// - public Type Type => Item1; - - /// - /// Get the condition. - /// - public ProviderCondition Condition => Item2; - - /// - /// Create a from a type and a condition. - /// - /// The type to provide - /// The condition - public ConditionalProvide(Type type, ProviderCondition condition) - : base(type, condition) - { } - - /// - /// Create a from a tuple of (Type, ProviderCondition). - /// - /// The tuple to convert - public ConditionalProvide((Type type, ProviderCondition condition) tuple) - : base(tuple.type, tuple.condition) - { } - - /// - /// Implicitly convert a tuple to a . - /// - /// The tuple to convert - /// A new based on the given tuple. - public static implicit operator ConditionalProvide((Type, Type) tuple) => new (tuple); - } - - /// - /// A condition for a conditional type. - /// - public class ProviderCondition - { - /// - /// The condition as a method. If true is returned, the type will be provided. - /// - public Func Condition { get; } = () => true; - /// - /// The list of types that this method needs. - /// - public ICollection Needed { get; } = ArraySegment.Empty; - - - /// - /// Create a new from a raw function. - /// - /// The predicate that will be used as condition - public ProviderCondition(Func condition) - { - Condition = condition; - } - - /// - /// Create a new from a type. This allow you to inform that a type will - /// only be available if a dependency is met. - /// - /// The type that you need - public ProviderCondition(Type needed) - { - Needed = new[] {needed}; - } - - /// - /// Create a new from a list of type. This allow you to inform that a type will - /// only be available if a list of dependencies are met. - /// - /// The types that you need - public ProviderCondition(ICollection needed) - { - Needed = needed; - } - - /// - /// Create a new with a list of types as dependencies and a predicate - /// for arbitrary conditions. - /// - /// The list of dependencies - /// An arbitrary condition - public ProviderCondition(ICollection needed, Func condition) - { - Needed = needed; - Condition = condition; - } - - - /// - /// Implicitly convert a type to a . - /// - /// The type dependency - /// A that will return true if the given type is available. - public static implicit operator ProviderCondition(Type type) => new(type); - - /// - /// Implicitly convert a list of type to a . - /// - /// The list of type dependencies - /// A that will return true if the given types are available. - public static implicit operator ProviderCondition(Type[] types) => new(types); - - /// - public static implicit operator ProviderCondition(List types) => new(types); - - - /// - /// Check if a type is available. - /// - /// The type to check - /// The list of types - /// True if the dependency is met, false otherwise - public static bool Has(Type needed, ICollection available) - { - return available.Contains(needed); - } - - /// - /// Check if a list of type are available. - /// - /// The list of types to check - /// The list of types - /// True if the dependencies are met, false otherwise - public static bool Has(ICollection needed, ICollection available) - { - return needed.All(x => Has(x, available)); - } - } } \ No newline at end of file diff --git a/Kyoo.Postgresql/PostgresModule.cs b/Kyoo.Postgresql/PostgresModule.cs index 6b84bd93..b05c1ab7 100644 --- a/Kyoo.Postgresql/PostgresModule.cs +++ b/Kyoo.Postgresql/PostgresModule.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Kyoo.Controllers; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; @@ -24,19 +23,6 @@ namespace Kyoo.Postgresql /// public string Description => "A database context for postgresql."; - /// - public ICollection Provides => new[] - { - typeof(DatabaseContext) - }; - - /// - public ICollection ConditionalProvides => ArraySegment.Empty; - - /// - public ICollection Requires => ArraySegment.Empty; - - /// /// The configuration to use. The database connection string is pulled from it. /// @@ -59,7 +45,7 @@ namespace Kyoo.Postgresql } /// - public void Configure(IServiceCollection services, ICollection availableTypes) + public void Configure(IServiceCollection services) { services.AddDbContext(x => { diff --git a/Kyoo.SqLite/SqLiteModule.cs b/Kyoo.SqLite/SqLiteModule.cs index 96c29836..0aa378d7 100644 --- a/Kyoo.SqLite/SqLiteModule.cs +++ b/Kyoo.SqLite/SqLiteModule.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Kyoo.Controllers; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; @@ -23,19 +22,7 @@ namespace Kyoo.SqLite /// public string Description => "A database context for sqlite."; - /// - public ICollection Provides => new[] - { - typeof(DatabaseContext) - }; - - /// - public ICollection ConditionalProvides => ArraySegment.Empty; - - /// - public ICollection Requires => ArraySegment.Empty; - - + /// /// The configuration to use. The database connection string is pulled from it. /// @@ -59,7 +46,7 @@ namespace Kyoo.SqLite /// - public void Configure(IServiceCollection services, ICollection availableTypes) + public void Configure(IServiceCollection services) { services.AddDbContext(x => { diff --git a/Kyoo.TheMovieDb/PluginTmdb.cs b/Kyoo.TheMovieDb/PluginTmdb.cs index aaf5aa9c..c1d6d494 100644 --- a/Kyoo.TheMovieDb/PluginTmdb.cs +++ b/Kyoo.TheMovieDb/PluginTmdb.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using Autofac; using Kyoo.Controllers; using Kyoo.Models.Attributes; @@ -23,20 +21,8 @@ namespace Kyoo.TheMovieDb /// public string Description => "A metadata provider for TheMovieDB."; - - /// - public ICollection Provides => new [] - { - typeof(IMetadataProvider) - }; - - /// - public ICollection ConditionalProvides => ArraySegment.Empty; - - /// - public ICollection Requires => ArraySegment.Empty; - - + + /// /// The configuration to use. /// @@ -65,7 +51,7 @@ namespace Kyoo.TheMovieDb } /// - public void Configure(IServiceCollection services, ICollection availableTypes) + public void Configure(IServiceCollection services) { services.Configure(_configuration.GetSection(TheMovieDbOptions.Path)); } diff --git a/Kyoo.TheTvdb/PluginTvdb.cs b/Kyoo.TheTvdb/PluginTvdb.cs index e0b697ea..74f9483d 100644 --- a/Kyoo.TheTvdb/PluginTvdb.cs +++ b/Kyoo.TheTvdb/PluginTvdb.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using Autofac; using Kyoo.Controllers; using Kyoo.Models.Attributes; @@ -24,20 +22,7 @@ namespace Kyoo.TheTvdb /// public string Description => "A metadata provider for The TVDB."; - - /// - public ICollection Provides => new [] - { - typeof(IMetadataProvider) - }; - - /// - public ICollection ConditionalProvides => ArraySegment.Empty; - - /// - public ICollection Requires => ArraySegment.Empty; - - + /// /// The configuration to use. /// @@ -67,7 +52,7 @@ namespace Kyoo.TheTvdb } /// - public void Configure(IServiceCollection services, ICollection availableTypes) + public void Configure(IServiceCollection services) { services.Configure(_configuration.GetSection(TvdbOption.Path)); } diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs index 215b0c9b..4812883d 100644 --- a/Kyoo/Controllers/PluginManager.cs +++ b/Kyoo/Controllers/PluginManager.cs @@ -112,22 +112,11 @@ namespace Kyoo.Controllers _logger.LogTrace("Loading new plugins..."); string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories); - plugins = plugins.Concat(pluginsPaths.SelectMany(LoadPlugin)) + _plugins.AddRange(plugins + .Concat(pluginsPaths.SelectMany(LoadPlugin)) .GroupBy(x => x.Name) .Select(x => x.First()) - .ToList(); - - ICollection available = GetProvidedTypes(plugins); - _plugins.AddRange(plugins.Where(plugin => - { - Type missing = plugin.Requires.FirstOrDefault(x => available.All(y => !y.IsAssignableTo(x))); - if (missing == null) - return true; - - _logger.LogCritical("No {Dependency} available in Kyoo but the plugin {Plugin} requires it", - missing.Name, plugin.Name); - return false; - })); + ); if (!_plugins.Any()) _logger.LogInformation("No plugin enabled"); @@ -138,7 +127,10 @@ namespace Kyoo.Controllers /// public void LoadPlugins(params Type[] plugins) { - throw new NotImplementedException(); + LoadPlugins(plugins + .Select(x => (IPlugin)ActivatorUtilities.CreateInstance(_provider, x)) + .ToArray() + ); } /// @@ -151,9 +143,8 @@ namespace Kyoo.Controllers /// public void ConfigureServices(IServiceCollection services) { - ICollection available = GetProvidedTypes(_plugins); foreach (IPlugin plugin in _plugins) - plugin.Configure(services, available); + plugin.Configure(services); } /// @@ -168,53 +159,6 @@ namespace Kyoo.Controllers } } - /// - /// Get the list of types provided by the currently loaded plugins. - /// - /// The list of plugins that will be used as a plugin pool to get provided types. - /// The list of types available. - private ICollection GetProvidedTypes(ICollection plugins) - { - List available = plugins.SelectMany(x => x.Provides).ToList(); - List conditionals = plugins - .SelectMany(x => x.ConditionalProvides) - .Where(x => x.Condition.Condition()) - .ToList(); - - bool IsAvailable(ConditionalProvide conditional, bool log = false) - { - if (!conditional.Condition.Condition()) - return false; - - ICollection needed = conditional.Condition.Needed - .Where(y => !available.Contains(y)) - .ToList(); - // TODO handle circular dependencies, actually it might stack overflow. - needed = needed.Where(x => !conditionals - .Where(y => y.Type == x) - .Any(y => IsAvailable(y))) - .ToList(); - if (!needed.Any()) - return true; - if (log && available.All(x => x != conditional.Type)) - { - _logger.LogWarning("The type {Type} is not available, {Dependencies} could not be met", - conditional.Type.Name, - needed.Select(x => x.Name)); - } - return false; - } - - // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (ConditionalProvide conditional in conditionals) - { - if (IsAvailable(conditional, true)) - available.Add(conditional.Type); - } - return available; - } - - /// /// A custom to load plugin's dependency if they are on the same folder. /// diff --git a/Kyoo/CoreModule.cs b/Kyoo/CoreModule.cs index 51f4f94c..5fe9e977 100644 --- a/Kyoo/CoreModule.cs +++ b/Kyoo/CoreModule.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using Autofac; using Autofac.Core; @@ -31,53 +30,7 @@ namespace Kyoo /// public string Description => "The core module containing default implementations."; - /// - public ICollection Provides => new[] - { - typeof(IFileSystem), - typeof(ITranscoder), - typeof(IThumbnailsManager), - typeof(IMetadataProvider), - typeof(ITaskManager), - typeof(ILibraryManager), - typeof(IIdentifier), - typeof(AProviderComposite) - }; - /// - public ICollection ConditionalProvides => new ConditionalProvide[] - { - (typeof(ILibraryRepository), typeof(DatabaseContext)), - (typeof(ILibraryItemRepository), typeof(DatabaseContext)), - (typeof(ICollectionRepository), typeof(DatabaseContext)), - (typeof(IShowRepository), typeof(DatabaseContext)), - (typeof(ISeasonRepository), typeof(DatabaseContext)), - (typeof(IEpisodeRepository), typeof(DatabaseContext)), - (typeof(ITrackRepository), typeof(DatabaseContext)), - (typeof(IPeopleRepository), typeof(DatabaseContext)), - (typeof(IStudioRepository), typeof(DatabaseContext)), - (typeof(IGenreRepository), typeof(DatabaseContext)), - (typeof(IProviderRepository), typeof(DatabaseContext)), - (typeof(IUserRepository), typeof(DatabaseContext)) - }; - - /// - public ICollection Requires => new [] - { - typeof(ILibraryRepository), - typeof(ILibraryItemRepository), - typeof(ICollectionRepository), - typeof(IShowRepository), - typeof(ISeasonRepository), - typeof(IEpisodeRepository), - typeof(ITrackRepository), - typeof(IPeopleRepository), - typeof(IStudioRepository), - typeof(IGenreRepository), - typeof(IProviderRepository) - }; - - /// /// The configuration to use. /// @@ -142,7 +95,7 @@ namespace Kyoo } /// - public void Configure(IServiceCollection services, ICollection availableTypes) + public void Configure(IServiceCollection services) { string publicUrl = _configuration.GetPublicUrl(); diff --git a/Kyoo/PluginsStartup.cs b/Kyoo/PluginsStartup.cs index e279cb57..a28d118c 100644 --- a/Kyoo/PluginsStartup.cs +++ b/Kyoo/PluginsStartup.cs @@ -43,7 +43,7 @@ namespace Kyoo typeof(CoreModule), typeof(AuthenticationModule), typeof(PostgresModule), - typeof(SqLiteModule), + // typeof(SqLiteModule), typeof(PluginTvdb), typeof(PluginTmdb) ); diff --git a/Kyoo/Program.cs b/Kyoo/Program.cs index 4e618efc..064cb6e7 100644 --- a/Kyoo/Program.cs +++ b/Kyoo/Program.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading.Tasks; using Autofac.Extensions.DependencyInjection; -using Kyoo.Controllers; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection;