diff --git a/Kyoo.Authentication/AuthenticationModule.cs b/Kyoo.Authentication/AuthenticationModule.cs index b9e575c5..4260512c 100644 --- a/Kyoo.Authentication/AuthenticationModule.cs +++ b/Kyoo.Authentication/AuthenticationModule.cs @@ -105,6 +105,7 @@ namespace Kyoo.Authentication .AddInMemoryIdentityResources(IdentityContext.GetIdentityResources()) .AddInMemoryApiScopes(IdentityContext.GetScopes()) .AddInMemoryApiResources(IdentityContext.GetApis()) + .AddInMemoryClients(IdentityContext.GetClients()) // .AddProfileService() .AddSigninKeys(certificateOptions); diff --git a/Kyoo.Postgresql/Kyoo.Postgresql.csproj b/Kyoo.Postgresql/Kyoo.Postgresql.csproj index b870c769..65f2f5e5 100644 --- a/Kyoo.Postgresql/Kyoo.Postgresql.csproj +++ b/Kyoo.Postgresql/Kyoo.Postgresql.csproj @@ -7,6 +7,7 @@ false false false + true SDG Zoe Roux diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs index 72d5a9ad..7c1be980 100644 --- a/Kyoo/Controllers/PluginManager.cs +++ b/Kyoo/Controllers/PluginManager.cs @@ -145,6 +145,7 @@ namespace Kyoo.Controllers 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))) diff --git a/Kyoo/Controllers/TaskManager.cs b/Kyoo/Controllers/TaskManager.cs index 89cff352..437b8b14 100644 --- a/Kyoo/Controllers/TaskManager.cs +++ b/Kyoo/Controllers/TaskManager.cs @@ -24,7 +24,7 @@ namespace Kyoo.Controllers /// private readonly IUnityContainer _container; /// - /// The configuration instance used to get schedule informations + /// The configuration instance used to get schedule information /// private readonly IConfiguration _configuration; /// @@ -37,7 +37,7 @@ namespace Kyoo.Controllers /// private List<(ITask task, DateTime scheduledDate)> _tasks; /// - /// The queue of tasks that should be runned as soon as possible. + /// The queue of tasks that should be run as soon as possible. /// private readonly Queue<(ITask, Dictionary)> _queuedTasks = new(); /// @@ -108,27 +108,11 @@ namespace Kyoo.Controllers _runningTask = task; try { - ICollection all = task.GetParameters(); - TaskParameters args = new(arguments - .Select(x => (value: x, arg: all - .FirstOrDefault(y => string.Equals(y.Name, x.Key, StringComparison.OrdinalIgnoreCase)))) - .Select(x => - { - if (x.arg == null) - throw new ArgumentException($"Invalid argument name: {x.value.Key}"); - return x.arg.CreateValue(x.value.Value); - })); - - - _logger.LogInformation("Task starting: {Task}", task.Name); - InjectServices(task); - await task.Run(args, _taskToken.Token); - _logger.LogInformation("Task finished: {Task}", task.Name); + await RunTask(task, arguments); } catch (Exception e) { - _logger.LogError("An unhandled exception occured while running the task {Task}.\n" + - "Inner exception: {Exception}\n\n", task.Name, e.Message); + _logger.LogError(e, "An unhandled exception occured while running the task {Task}", task.Name); } } else @@ -139,14 +123,51 @@ namespace Kyoo.Controllers } } + /// + /// Parse parameters, inject a task and run it. + /// + /// The task to run + /// The arguments to pass to the function + /// There was an invalid argument or a required argument was not found. + private async Task RunTask(ITask task, Dictionary arguments) + { + _logger.LogInformation("Task starting: {Task}", task.Name); + + ICollection all = task.GetParameters(); + + ICollection invalids = arguments.Keys + .Where(x => all.Any(y => x != y.Name)) + .ToArray(); + if (invalids.Any()) + { + string invalidsStr = string.Join(", ", invalids); + throw new ArgumentException($"{invalidsStr} are invalid arguments for the task {task.Name}"); + } + + TaskParameters args = new(all + .Select(x => + { + object value = arguments + .FirstOrDefault(y => string.Equals(y.Key, x.Name, StringComparison.OrdinalIgnoreCase)) + .Value; + if (value == null && x.IsRequired) + throw new ArgumentException($"The argument {x.Name} is required to run {task.Name}" + + " but it was not specified."); + return x.CreateValue(value ?? x.DefaultValue); + })); + + InjectServices(task); + await task.Run(args, _taskToken.Token); + _logger.LogInformation("Task finished: {Task}", task.Name); + } + /// /// Inject services into the marked properties of the given object. /// /// The object to inject - /// The type of the object. - private void InjectServices(T obj) + private void InjectServices(ITask obj) { - IEnumerable properties = typeof(T).GetProperties() + IEnumerable properties = obj.GetType().GetProperties() .Where(x => x.GetCustomAttribute() != null) .Where(x => x.CanWrite); @@ -180,7 +201,7 @@ namespace Kyoo.Controllers .Where(x => x.RunOnStartup && x.Priority != int.MaxValue) .OrderByDescending(x => x.Priority); foreach (ITask task in startupTasks) - _queuedTasks.Enqueue((task, null)); + _queuedTasks.Enqueue((task, new Dictionary())); } /// diff --git a/Kyoo/Program.cs b/Kyoo/Program.cs index beba3b0d..2c73f2db 100644 --- a/Kyoo/Program.cs +++ b/Kyoo/Program.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Unity; +using Unity.Microsoft.DependencyInjection; namespace Kyoo { @@ -99,7 +100,8 @@ namespace Kyoo if (context.HostingEnvironment.IsDevelopment()) StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration); }) - .UseUnityProvider(container) + // .UseUnityProvider(container) + .UseUnityServiceProvider(container) .ConfigureServices(x => x.AddRouting()) .UseKestrel(options => { options.AddServerHeader = false; }) .UseIIS() diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index 925d25e1..d0fac3d6 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -3,11 +3,13 @@ using System.IO; using Kyoo.Controllers; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.SpaServices.AngularCli; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Unity; using Unity.Lifetime; @@ -19,11 +21,13 @@ namespace Kyoo public class Startup { private readonly IConfiguration _configuration; + private readonly ILoggerFactory _loggerFactory; - public Startup(IConfiguration configuration) + public Startup(IConfiguration configuration, ILoggerFactory loggerFactory, IServiceProvider provider) { _configuration = configuration; + _loggerFactory = loggerFactory; } public void ConfigureServices(IServiceCollection services) @@ -60,11 +64,20 @@ namespace Kyoo // }); // services.AddAuthentication() + + // container.Resolve(); + services.AddSingleton(); services.AddHostedService(x => x.GetService() as TaskManager); } - public void ConfigureContainer(UnityContainer container) { } + public void ConfigureContainer(IUnityContainer container) + { + container.RegisterType(new SingletonLifetimeManager()); + container.RegisterInstance(_configuration); + PluginManager pluginManager = new(container, _configuration, _loggerFactory.CreateLogger()); + pluginManager.ReloadPlugins(); + } public void Configure(IUnityContainer container, IApplicationBuilder app, IWebHostEnvironment env) { @@ -103,18 +116,15 @@ namespace Kyoo }); app.UseResponseCompression(); - // app.UseSpa(spa => - // { - // spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp"); - // - // if (env.IsDevelopment()) - // spa.UseAngularCliServer("start"); - // }); - // - container.RegisterType(new SingletonLifetimeManager()); - // container.Resolve(); + app.UseSpa(spa => + { + spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp"); + + if (env.IsDevelopment()) + spa.UseAngularCliServer("start"); + }); + IPluginManager pluginManager = container.Resolve(); - pluginManager.ReloadPlugins(); foreach (IPlugin plugin in pluginManager.GetAllPlugins()) plugin.ConfigureAspNet(app); diff --git a/Kyoo/settings.json b/Kyoo/settings.json index bcfc92d3..8cd453e2 100644 --- a/Kyoo/settings.json +++ b/Kyoo/settings.json @@ -18,6 +18,8 @@ "logging": { "logLevel": { "default": "Trace", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", "Kyoo": "Trace" } },