using MessageFlow;
namespace MessageFlow.Samples;
///
/// The kind of a support ticket.
///
public enum TicketKind
{
/// A refund request.
Refund,
/// A password reset request.
PasswordReset,
/// Anything the automated handlers do not understand.
Other,
}
///
/// A support ticket flowing through the triage chain.
///
/// The ticket identifier.
/// The kind of the ticket.
public sealed class Ticket(int id, TicketKind kind)
{
/// Gets the ticket identifier.
public int Id { get; } = id;
/// Gets the kind of the ticket.
public TicketKind Kind { get; } = kind;
}
///
/// Handles refund tickets.
///
public sealed class RefundHandler : HandlerBase
{
///
protected override bool CanHandle(Ticket request)
{
ArgumentNullException.ThrowIfNull(request);
return request.Kind == TicketKind.Refund;
}
///
protected override ValueTask ProcessAsync(Ticket request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
return new ValueTask($"refund issued for ticket {request.Id}");
}
}
///
/// Handles password reset tickets.
///
public sealed class PasswordResetHandler : HandlerBase
{
///
protected override bool CanHandle(Ticket request)
{
ArgumentNullException.ThrowIfNull(request);
return request.Kind == TicketKind.PasswordReset;
}
///
protected override ValueTask ProcessAsync(Ticket request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
return new ValueTask($"reset link sent for ticket {request.Id}");
}
}
///
/// Routes support tickets to reusable implementations.
///
public static class SupportTicketSample
{
///
/// Builds the ticket triage chain, escalating anything the handlers do not accept.
///
/// The composed chain.
public static IChain BuildChain()
=> Chain.Create()
.Use(new RefundHandler())
.Use(new PasswordResetHandler())
.WithFallback((request, _) => new ValueTask($"escalated ticket {request.Id} to a human"))
.Build();
///
/// Runs the sample against one ticket of every kind.
///
/// The writer receiving the sample output.
/// A token used to cancel the operation.
/// The triage decisions, in ticket order.
public static async Task> RunAsync(
TextWriter output,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(output);
var chain = BuildChain();
var tickets = new[]
{
new Ticket(1, TicketKind.Refund),
new Ticket(2, TicketKind.PasswordReset),
new Ticket(3, TicketKind.Other),
};
var results = new List();
foreach (var ticket in tickets)
{
var response = await chain.ExecuteAsync(ticket, cancellationToken).ConfigureAwait(false);
results.Add(response);
await output.WriteLineAsync($"ticket {ticket.Id} ({ticket.Kind}) => {response}").ConfigureAwait(false);
}
return results;
}
}