2022-05-26 10:47:31 +00:00
using System.Reflection ;
2022-12-31 15:16:43 +00:00
using Elsa.Extensions ;
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-12-09 11:25:39 +00:00
/// <inheritdoc />
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-12-30 12:11:29 +00:00
private ISet < IFeature > _features = new HashSet < IFeature > ( ) ;
2022-05-26 10:47:31 +00:00
private readonly ICollection < HostedServiceDescriptor > _hostedServiceDescriptors = new List < HostedServiceDescriptor > ( ) ;
2022-12-09 11:25:39 +00:00
/// <summary>
/// Constructor.
/// </summary>
2022-05-27 10:36:39 +00:00
public Module ( IServiceCollection services )
2022-05-26 10:47:31 +00:00
{
Services = services ;
}
2022-12-09 11:25:39 +00:00
/// <inheritdoc />
2022-05-26 10:47:31 +00:00
public IServiceCollection Services { get ; }
2022-12-09 11:25:39 +00:00
/// <inheritdoc />
public IDictionary < object , object > Properties { get ; } = new Dictionary < object , object > ( ) ;
2022-05-26 10:47:31 +00:00
2022-12-09 11:25:39 +00:00
/// <inheritdoc />
2023-01-01 17:02:38 +00:00
public T Configure < T > ( Action < T > ? configure = default ) where T : class , IFeature
= > Configure ( module = > ( T ) Activator . CreateInstance ( typeof ( T ) , module ) ! , configure ) ;
2022-05-26 10:47:31 +00:00
2022-12-09 11:25:39 +00:00
/// <inheritdoc />
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-14 17:38:58 +00:00
if ( _features . FirstOrDefault ( x = > x is T ) is not T feature )
2022-05-26 10:47:31 +00:00
{
2022-08-14 17:38:58 +00:00
feature = factory ( this ) ;
_features . Add ( feature ) ;
2022-05-26 10:47:31 +00:00
}
2022-08-14 17:38:58 +00:00
configure ? . Invoke ( feature ) ;
return feature ;
2022-05-26 10:47:31 +00:00
}
2022-12-09 11:25:39 +00:00
/// <inheritdoc />
2023-04-17 13:23:05 +00:00
public IModule ConfigureHostedService < T > ( int priority = 0 ) where T : class , IHostedService
2022-05-26 10:47:31 +00:00
{
_hostedServiceDescriptors . Add ( new HostedServiceDescriptor ( priority , typeof ( T ) ) ) ;
return this ;
}
2022-12-09 11:25:39 +00:00
/// <inheritdoc />
2022-05-26 10:47:31 +00:00
public void Apply ( )
{
2022-08-14 17:38:58 +00:00
var featureTypes = _features . Select ( x = > x . GetType ( ) ) . TSort ( x = > x . GetCustomAttributes < DependsOn > ( ) . Select ( dependsOn = > dependsOn . Type ) ) . ToList ( ) ;
var features = featureTypes . Select ( featureType = > _features . FirstOrDefault ( x = > x . GetType ( ) = = featureType ) ? ? ( IFeature ) Activator . CreateInstance ( featureType , this ) ! ) . ToList ( ) ;
2022-05-26 10:47:31 +00:00
2022-12-30 12:11:29 +00:00
// Update list with complete list of features. This is important because during the Configure phase, dependent features might configure other features, which should not be created as new instances.
_features = features . ToHashSet ( ) ;
2022-08-14 17:38:58 +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-14 17:38:58 +00:00
foreach ( var feature in features )
feature . Apply ( ) ;
2022-05-26 10:47:31 +00:00
}
}