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
1 change: 1 addition & 0 deletions src/Tests/PipelineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public async Task CanBuildDecoratingPipeline()
called = true;
return inner.HandleAsync(message, cancellation);
})
.Use(handler => WhatsAppHandler.Skip)
.Build();

await pipeline.HandleAsync(new ReactionMessage("1234", service, user, 0, "🗽"));
Expand Down
17 changes: 16 additions & 1 deletion src/WhatsApp/WhatsAppHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,28 @@
public static class WhatsAppHandler
{
/// <summary>
/// An empty implementation of <see cref="IWhatsAppHandler"/> that does nothing.
/// An empty implementation of <see cref="IWhatsAppHandler"/> that does nothing and
/// can be used to shortcircuit the processing of WhatsApp messages.
/// </summary>
public static IWhatsAppHandler Empty { get; } = new EmptyWhatsAppHandler();

/// <summary>
/// An empty implementation of <see cref="IWhatsAppHandler"/> that is skipped
/// when building the processing pipeline. It's useful to implement conditional
/// <c>Use(..)</c> logic that is dependent on runtime conditions, such as the
/// hosting environment or configuration settings.
/// </summary>
public static IWhatsAppHandler Skip { get; } = new SKipWhatsAppHandler();

class EmptyWhatsAppHandler : IWhatsAppHandler
{
public IAsyncEnumerable<Response> HandleAsync(IEnumerable<IMessage> messages, CancellationToken cancellation = default)
=> AsyncEnumerable.Empty<Response>();
}

class SKipWhatsAppHandler : IWhatsAppHandler
{
public IAsyncEnumerable<Response> HandleAsync(IEnumerable<IMessage> messages, CancellationToken cancellation = default)
=> throw new NotSupportedException("This handler should never be invoked by the pipeline.");
}
}
8 changes: 6 additions & 2 deletions src/WhatsApp/WhatsAppHandlerBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,17 @@ public IWhatsAppHandler Build(IServiceProvider? services = default)
{
for (var i = factories.Count - 1; i >= 0; i--)
{
handler = factories[i](handler!, services);
if (handler is null)
var current = factories[i](handler!, services);
if (current is null)
{
Throw.InvalidOperationException(
$"The {nameof(WhatsAppHandlerBuilder)} entry at index {i} returned null. " +
$"Ensure that the callbacks passed to {nameof(Use)} return non-null {nameof(IWhatsAppHandler)} instances.");
}

// Only keep non-skipping handlers.
if (current != WhatsAppHandler.Skip)
handler = factories[i](handler!, services);
Copy link

Copilot AI Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The factory method is invoked twice for the same index. Instead, consider assigning 'handler = current' when the current handler is not Skip to avoid potential side effects from the second invocation.

Suggested change
handler = factories[i](handler!, services);
handler = current;

Copilot uses AI. Check for mistakes.
}
}

Expand Down