Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/PipeForge/DelegatePipelineStep.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace PipeForge;

/// <summary>
/// A pipeline step that delegates execution to a provided function.
/// </summary>
/// <typeparam name="TContext">The type of the pipeline context.</typeparam>
internal sealed class DelegatePipelineStep<TContext> : PipelineStep<TContext>
{
private readonly Func<TContext, PipelineDelegate<TContext>, CancellationToken, Task> _invoke;

/// <summary>
/// Initializes a new instance of the <see cref="DelegatePipelineStep{TContext}"/> class with a delegate to execute.
/// </summary>
/// <param name="invoke">The delegate to invoke during pipeline execution.</param>
public DelegatePipelineStep(Func<TContext, PipelineDelegate<TContext>, CancellationToken, Task> invoke)
{
_invoke = invoke ?? throw new ArgumentNullException(nameof(invoke));
}

public override Task InvokeAsync(TContext context, PipelineDelegate<TContext> next, CancellationToken cancellationToken = default)
{
return _invoke(context, next, cancellationToken);
}
}
14 changes: 0 additions & 14 deletions src/PipeForge/Pipeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,6 @@ public static PipelineBuilder<T> CreateFor<T>() where T : class
return new PipelineBuilder<T>();
}

/// <summary>
/// Creates a new instance of <see cref="PipelineBuilder{T}"/> for the specified context type.
/// </summary>
/// <remarks>
/// This method is used to start building a pipeline for a specific type.
/// It allows for fluent configuration of pipeline steps.
/// </remarks>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static PipelineBuilder<T> CreateFor<T>(ILoggerFactory? loggerFactory) where T : class
{
return new PipelineBuilder<T>(loggerFactory);
}

/// <summary>
/// Discovers pipeline steps for a specific context type from all assemblies in the current AppDomain.
/// </summary>
Expand Down
53 changes: 34 additions & 19 deletions src/PipeForge/PipelineBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,53 +1,68 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;

namespace PipeForge;

/// <summary>
/// PipelineBuilder is used to configure and build a pipeline of steps.
/// </summary>
/// <typeparam name="T"></typeparam>
public class PipelineBuilder<T>
where T : class
/// <typeparam name="TContext"></typeparam>
public class PipelineBuilder<TContext>
where TContext : class
{
private readonly List<Lazy<IPipelineStep<T>>> _steps = new();
private readonly ILoggerFactory? _loggerFactory;
private readonly IServiceCollection _services = new ServiceCollection();

internal PipelineBuilder() { }
internal PipelineBuilder()
{ }

internal PipelineBuilder(ILoggerFactory? loggerFactory)
/// <summary>
/// Builds a pipeline from the configured steps
/// </summary>
/// <returns></returns>
public IPipelineRunner<TContext> Build()
{
_loggerFactory = loggerFactory;
//return new PipelineRunner<TContext>(_services.BuildServiceProvider());
throw new NotImplementedException();
}

/// <summary>
/// Builds a pipeline from the configured steps
/// Configures the services used by the pipeline
/// </summary>
/// <param name="configure"></param>
/// <returns></returns>
public IPipelineRunner<T> Build()
public PipelineBuilder<TContext> ConfigureServices(Action<IServiceCollection> configure)
{
return new PipelineRunner<T>(_steps, _loggerFactory);
configure(_services);
return this;
}

/// <summary>
/// Adds a step to the pipeline
/// </summary>
/// <typeparam name="TStep"></typeparam>
/// <returns></returns>
public PipelineBuilder<T> WithStep<TStep>() where TStep : IPipelineStep<T>, new()
public PipelineBuilder<TContext> WithStep<TStep>() where TStep : class, IPipelineStep<TContext>
{
_steps.Add(new(() => new TStep()));
_services.AddPipelineStep<TStep>();
return this;
}

/// <summary>
/// Adds a step to the pipeline
/// Adds a step to the pipeline using a delegate. By default, the step is registered with a transient lifetime.
/// You can specify a different lifetime if needed.
/// </summary>
/// <typeparam name="TStep"></typeparam>
/// <param name="stepFactory"></param>
/// <param name="invoke">The delegate to invoke for the step.</param>
/// <param name="lifetime">The service lifetime for the step. Defaults to <see cref="ServiceLifetime.Transient"/>.</param>
/// <returns></returns>
public PipelineBuilder<T> WithStep<TStep>(Func<TStep> stepFactory) where TStep : IPipelineStep<T>
public PipelineBuilder<TContext> WithStep(
Func<TContext, PipelineDelegate<TContext>, CancellationToken, Task> invoke,
ServiceLifetime lifetime = ServiceLifetime.Transient)
{
_steps.Add(new(() => stepFactory()));
var stepFactory = new Func<IServiceProvider, DelegatePipelineStep<TContext>>(_ => new DelegatePipelineStep<TContext>(invoke));

_services.Add(ServiceDescriptor.Describe(typeof(IPipelineStep<TContext>), stepFactory, lifetime));
_services.Add(ServiceDescriptor.Describe(typeof(Lazy<IPipelineStep<TContext>>),
sp => new Lazy<IPipelineStep<TContext>>(() => stepFactory(sp)), lifetime));

return this;
}
}