Fixing task arguments

This commit is contained in:
Zoe Roux 2021-05-03 23:33:48 +02:00
parent 7613efb4b4
commit a18f393926
7 changed files with 76 additions and 38 deletions

View File

@ -105,6 +105,7 @@ namespace Kyoo.Authentication
.AddInMemoryIdentityResources(IdentityContext.GetIdentityResources()) .AddInMemoryIdentityResources(IdentityContext.GetIdentityResources())
.AddInMemoryApiScopes(IdentityContext.GetScopes()) .AddInMemoryApiScopes(IdentityContext.GetScopes())
.AddInMemoryApiResources(IdentityContext.GetApis()) .AddInMemoryApiResources(IdentityContext.GetApis())
.AddInMemoryClients(IdentityContext.GetClients())
// .AddProfileService<AccountController>() // .AddProfileService<AccountController>()
.AddSigninKeys(certificateOptions); .AddSigninKeys(certificateOptions);

View File

@ -7,6 +7,7 @@
<ProduceReferenceAssembly>false</ProduceReferenceAssembly> <ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<GenerateDependencyFile>false</GenerateDependencyFile> <GenerateDependencyFile>false</GenerateDependencyFile>
<GenerateRuntimeConfigurationFiles>false</GenerateRuntimeConfigurationFiles> <GenerateRuntimeConfigurationFiles>false</GenerateRuntimeConfigurationFiles>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<Company>SDG</Company> <Company>SDG</Company>
<Authors>Zoe Roux</Authors> <Authors>Zoe Roux</Authors>

View File

@ -145,6 +145,7 @@ namespace Kyoo.Controllers
ICollection<Type> needed = conditional.Condition.Needed ICollection<Type> needed = conditional.Condition.Needed
.Where(y => !available.Contains(y)) .Where(y => !available.Contains(y))
.ToList(); .ToList();
// TODO handle circular dependencies, actually it might stack overflow.
needed = needed.Where(x => !conditionals needed = needed.Where(x => !conditionals
.Where(y => y.Type == x) .Where(y => y.Type == x)
.Any(y => IsAvailable(y))) .Any(y => IsAvailable(y)))

View File

@ -24,7 +24,7 @@ namespace Kyoo.Controllers
/// </summary> /// </summary>
private readonly IUnityContainer _container; private readonly IUnityContainer _container;
/// <summary> /// <summary>
/// The configuration instance used to get schedule informations /// The configuration instance used to get schedule information
/// </summary> /// </summary>
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
/// <summary> /// <summary>
@ -37,7 +37,7 @@ namespace Kyoo.Controllers
/// </summary> /// </summary>
private List<(ITask task, DateTime scheduledDate)> _tasks; private List<(ITask task, DateTime scheduledDate)> _tasks;
/// <summary> /// <summary>
/// The queue of tasks that should be runned as soon as possible. /// The queue of tasks that should be run as soon as possible.
/// </summary> /// </summary>
private readonly Queue<(ITask, Dictionary<string, object>)> _queuedTasks = new(); private readonly Queue<(ITask, Dictionary<string, object>)> _queuedTasks = new();
/// <summary> /// <summary>
@ -108,27 +108,11 @@ namespace Kyoo.Controllers
_runningTask = task; _runningTask = task;
try try
{ {
ICollection<TaskParameter> all = task.GetParameters(); await RunTask(task, arguments);
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);
} }
catch (Exception e) catch (Exception e)
{ {
_logger.LogError("An unhandled exception occured while running the task {Task}.\n" + _logger.LogError(e, "An unhandled exception occured while running the task {Task}", task.Name);
"Inner exception: {Exception}\n\n", task.Name, e.Message);
} }
} }
else else
@ -139,14 +123,51 @@ namespace Kyoo.Controllers
} }
} }
/// <summary>
/// Parse parameters, inject a task and run it.
/// </summary>
/// <param name="task">The task to run</param>
/// <param name="arguments">The arguments to pass to the function</param>
/// <exception cref="ArgumentException">There was an invalid argument or a required argument was not found.</exception>
private async Task RunTask(ITask task, Dictionary<string, object> arguments)
{
_logger.LogInformation("Task starting: {Task}", task.Name);
ICollection<TaskParameter> all = task.GetParameters();
ICollection<string> 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);
}
/// <summary> /// <summary>
/// Inject services into the <see cref="InjectedAttribute"/> marked properties of the given object. /// Inject services into the <see cref="InjectedAttribute"/> marked properties of the given object.
/// </summary> /// </summary>
/// <param name="obj">The object to inject</param> /// <param name="obj">The object to inject</param>
/// <typeparam name="T">The type of the object.</typeparam> private void InjectServices(ITask obj)
private void InjectServices<T>(T obj)
{ {
IEnumerable<PropertyInfo> properties = typeof(T).GetProperties() IEnumerable<PropertyInfo> properties = obj.GetType().GetProperties()
.Where(x => x.GetCustomAttribute<InjectedAttribute>() != null) .Where(x => x.GetCustomAttribute<InjectedAttribute>() != null)
.Where(x => x.CanWrite); .Where(x => x.CanWrite);
@ -180,7 +201,7 @@ namespace Kyoo.Controllers
.Where(x => x.RunOnStartup && x.Priority != int.MaxValue) .Where(x => x.RunOnStartup && x.Priority != int.MaxValue)
.OrderByDescending(x => x.Priority); .OrderByDescending(x => x.Priority);
foreach (ITask task in startupTasks) foreach (ITask task in startupTasks)
_queuedTasks.Enqueue((task, null)); _queuedTasks.Enqueue((task, new Dictionary<string, object>()));
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Unity; using Unity;
using Unity.Microsoft.DependencyInjection;
namespace Kyoo namespace Kyoo
{ {
@ -99,7 +100,8 @@ namespace Kyoo
if (context.HostingEnvironment.IsDevelopment()) if (context.HostingEnvironment.IsDevelopment())
StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration); StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
}) })
.UseUnityProvider(container) // .UseUnityProvider(container)
.UseUnityServiceProvider(container)
.ConfigureServices(x => x.AddRouting()) .ConfigureServices(x => x.AddRouting())
.UseKestrel(options => { options.AddServerHeader = false; }) .UseKestrel(options => { options.AddServerHeader = false; })
.UseIIS() .UseIIS()

View File

@ -3,11 +3,13 @@ using System.IO;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.AspNetCore.StaticFiles; using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Unity; using Unity;
using Unity.Lifetime; using Unity.Lifetime;
@ -19,11 +21,13 @@ namespace Kyoo
public class Startup public class Startup
{ {
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
private readonly ILoggerFactory _loggerFactory;
public Startup(IConfiguration configuration) public Startup(IConfiguration configuration, ILoggerFactory loggerFactory, IServiceProvider provider)
{ {
_configuration = configuration; _configuration = configuration;
_loggerFactory = loggerFactory;
} }
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
@ -60,11 +64,20 @@ namespace Kyoo
// }); // });
// services.AddAuthentication() // services.AddAuthentication()
// container.Resolve<IConfiguration>();
services.AddSingleton<ITaskManager, TaskManager>(); services.AddSingleton<ITaskManager, TaskManager>();
services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager); services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager);
} }
public void ConfigureContainer(UnityContainer container) { } public void ConfigureContainer(IUnityContainer container)
{
container.RegisterType<IPluginManager, PluginManager>(new SingletonLifetimeManager());
container.RegisterInstance(_configuration);
PluginManager pluginManager = new(container, _configuration, _loggerFactory.CreateLogger<PluginManager>());
pluginManager.ReloadPlugins();
}
public void Configure(IUnityContainer container, IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IUnityContainer container, IApplicationBuilder app, IWebHostEnvironment env)
{ {
@ -103,18 +116,15 @@ namespace Kyoo
}); });
app.UseResponseCompression(); app.UseResponseCompression();
// app.UseSpa(spa => app.UseSpa(spa =>
// { {
// spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp"); spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp");
//
// if (env.IsDevelopment()) if (env.IsDevelopment())
// spa.UseAngularCliServer("start"); spa.UseAngularCliServer("start");
// }); });
//
container.RegisterType<IPluginManager, PluginManager>(new SingletonLifetimeManager());
// container.Resolve<IConfiguration>();
IPluginManager pluginManager = container.Resolve<IPluginManager>(); IPluginManager pluginManager = container.Resolve<IPluginManager>();
pluginManager.ReloadPlugins();
foreach (IPlugin plugin in pluginManager.GetAllPlugins()) foreach (IPlugin plugin in pluginManager.GetAllPlugins())
plugin.ConfigureAspNet(app); plugin.ConfigureAspNet(app);

View File

@ -18,6 +18,8 @@
"logging": { "logging": {
"logLevel": { "logLevel": {
"default": "Trace", "default": "Trace",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Kyoo": "Trace" "Kyoo": "Trace"
} }
}, },