2022-05-26 10:47:31 +00:00
|
|
|
using System.Reflection;
|
2022-05-27 10:36:39 +00:00
|
|
|
using Elsa.Features.Attributes;
|
|
|
|
|
using Elsa.Features.Services;
|
2022-05-26 10:47:31 +00:00
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
namespace Elsa.Features.Implementations;
|
2022-05-26 10:47:31 +00:00
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
public class Module : IModule
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
|
|
|
|
private record HostedServiceDescriptor(int Order, Type HostedServiceType);
|
|
|
|
|
|
2022-08-11 10:45:07 +00:00
|
|
|
private readonly ISet<IFeature> _features = new HashSet<IFeature>();
|
2022-05-26 10:47:31 +00:00
|
|
|
private readonly ICollection<HostedServiceDescriptor> _hostedServiceDescriptors = new List<HostedServiceDescriptor>();
|
|
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
public Module(IServiceCollection services)
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
|
|
|
|
Services = services;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IServiceCollection Services { get; }
|
|
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
public T Configure<T>(Action<T>? configure = default) where T : class, IFeature => Configure(serviceConfiguration => (T)Activator.CreateInstance(typeof(T), serviceConfiguration)!, configure);
|
2022-05-26 10:47:31 +00:00
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
public T Configure<T>(Func<IModule, T> factory, Action<T>? configure = default) where T : class, IFeature
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
2022-08-11 10:45:07 +00:00
|
|
|
if (_features.FirstOrDefault(x => x is T) is not T configurator)
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
|
|
|
|
configurator = factory(this);
|
2022-08-11 10:45:07 +00:00
|
|
|
_features.Add(configurator);
|
2022-05-26 10:47:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
configure?.Invoke(configurator);
|
|
|
|
|
return configurator;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
public IModule ConfigureHostedService<T>(int priority = 0)
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
|
|
|
|
_hostedServiceDescriptors.Add(new HostedServiceDescriptor(priority, typeof(T)));
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Apply()
|
|
|
|
|
{
|
|
|
|
|
ResolveDependencies();
|
|
|
|
|
|
2022-08-11 10:45:07 +00:00
|
|
|
foreach (var feature in _features)
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
2022-08-11 10:45:07 +00:00
|
|
|
feature.Configure();
|
|
|
|
|
feature.ConfigureHostedServices();
|
2022-05-26 10:47:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var hostedServiceDescriptor in _hostedServiceDescriptors.OrderBy(x => x.Order))
|
|
|
|
|
Services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IHostedService), hostedServiceDescriptor.HostedServiceType));
|
|
|
|
|
|
2022-08-11 10:45:07 +00:00
|
|
|
foreach (var feature in _features)
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
2022-08-11 10:45:07 +00:00
|
|
|
feature.Apply();
|
2022-05-26 10:47:31 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ResolveDependencies()
|
|
|
|
|
{
|
|
|
|
|
var resolvedDependencyTypes = new HashSet<Type>();
|
|
|
|
|
|
2022-08-11 10:45:07 +00:00
|
|
|
foreach (var configurator in _features.ToList())
|
2022-05-26 10:47:31 +00:00
|
|
|
ResolveDependencies(configurator, resolvedDependencyTypes);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
private void ResolveDependencies(IFeature feature, ISet<Type> resolvedDependencyTypes)
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
2022-05-27 10:36:39 +00:00
|
|
|
var dependencyTypes = feature.GetType().GetCustomAttributes<DependsOn>().Select(x => x.Type).ToHashSet();
|
2022-05-26 10:47:31 +00:00
|
|
|
dependencyTypes = dependencyTypes.Except(resolvedDependencyTypes).ToHashSet();
|
|
|
|
|
|
|
|
|
|
foreach (var type in dependencyTypes)
|
|
|
|
|
{
|
|
|
|
|
var dependencyConfigurator = AddConfigurator(type);
|
|
|
|
|
resolvedDependencyTypes.Add(type);
|
|
|
|
|
ResolveDependencies(dependencyConfigurator, resolvedDependencyTypes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
private IFeature AddConfigurator(Type type)
|
2022-05-26 10:47:31 +00:00
|
|
|
{
|
2022-08-11 10:45:07 +00:00
|
|
|
var configurator = _features.FirstOrDefault(x => x.GetType() == type);
|
2022-05-26 10:47:31 +00:00
|
|
|
|
|
|
|
|
if (configurator != null)
|
|
|
|
|
return configurator;
|
|
|
|
|
|
2022-05-27 10:36:39 +00:00
|
|
|
configurator = (IFeature)Activator.CreateInstance(type, this)!;
|
2022-08-11 10:45:07 +00:00
|
|
|
_features.Add(configurator);
|
2022-05-26 10:47:31 +00:00
|
|
|
return configurator;
|
|
|
|
|
}
|
|
|
|
|
}
|