using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
// ReSharper disable UnusedMember.Global
namespace Tapeti.Flow
{
///
/// Provides methods to build an IYieldPoint to indicate if and how Flow should continue.
///
public interface IFlowProvider
{
///
/// Publish a request message and continue the flow when the response arrives.
/// The request message must be marked with the [Request] attribute, and the
/// Response type must match. Used for asynchronous response handlers.
///
///
///
///
///
IYieldPoint YieldWithRequest(TRequest message, Func> responseHandler);
///
/// Publish a request message and continue the flow when the response arrives.
/// The request message must be marked with the [Request] attribute, and the
/// Response type must match. Used for synchronous response handlers.
///
///
/// The reason why this requires the extra 'Sync' in the name: one does not simply overload methods
/// with Task vs non-Task Funcs. "Ambiguous call". Apparantly this is because a return type
/// of a method is not part of its signature,according to:
/// http://stackoverflow.com/questions/18715979/ambiguity-with-action-and-func-parameter
///
///
///
///
///
///
IYieldPoint YieldWithRequestSync(TRequest message, Func responseHandler);
///
/// Create a request builder to publish one or more requests messages. Call Yield on the resulting builder
/// to acquire an IYieldPoint.
///
IFlowParallelRequestBuilder YieldWithParallelRequest();
///
/// End the flow by publishing the specified response message. Only allowed, and required, when the
/// current flow was started by a message handler for a Request message.
///
///
///
IYieldPoint EndWithResponse(TResponse message);
///
/// End the flow and dispose any state.
///
IYieldPoint End();
}
///
/// Allows starting a flow outside of a message handler.
///
public interface IFlowStarter
{
///
/// Starts a new flow.
///
///
Task Start(Expression>> methodSelector) where TController : class;
///
/// Starts a new flow.
///
///
Task Start(Expression>>> methodSelector) where TController : class;
///
/// Starts a new flow and passes the parameter to the method.
///
///
///
Task Start(Expression>> methodSelector, TParameter parameter) where TController : class;
///
/// Starts a new flow and passes the parameter to the method.
///
///
///
Task Start(Expression>>> methodSelector, TParameter parameter) where TController : class;
}
///
/// Internal interface. Do not call directly.
///
public interface IFlowHandler
{
///
/// Executes the YieldPoint for the given message context.
///
///
///
ValueTask Execute(IFlowHandlerContext context, IYieldPoint yieldPoint);
///
/// Returns the parallel request for the given message context.
///
IFlowParallelRequest GetParallelRequest(IFlowHandlerContext context);
///
/// Calls the converge method for a parallel flow.
///
ValueTask Converge(IFlowHandlerContext context);
}
///
/// Determines how the Yield method of a parallel request behaves when no requests have been added.
/// Useful in cases where requests are sent conditionally.
///
public enum FlowNoRequestsBehaviour
{
///
/// Throw an exception. This is the default behaviour to prevent subtle bugs when not specifying the behaviour explicitly,
/// as well as for backwards compatibility.
///
Exception,
///
/// Immediately call the continuation method.
///
Converge,
///
/// End the flow without calling the converge method.
///
EndFlow
}
///
/// Builder to publish one or more request messages and continuing the flow when the responses arrive.
///
public interface IFlowParallelRequestBuilder
{
///
/// Publish a request message and continue the flow when the response arrives.
/// Note that the response handler can not influence the flow as it does not return a YieldPoint.
/// It can instead store state in the controller for the continuation passed to the Yield method.
/// Used for asynchronous response handlers.
///
///
///
IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler);
///
/// This overload allows the response handler access to the IFlowParallelRequest interface, which
/// can be used to add additional requests to the parallel request before the continuation method passed to the Yield method is called.
///
///
IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler);
///
/// Publish a request message and continue the flow when the response arrives.
/// Note that the response handler can not influence the flow as it does not return a YieldPoint.
/// It can instead store state in the controller for the continuation passed to the Yield method.
/// Used for synchronous response handlers.
///
///
///
IFlowParallelRequestBuilder AddRequestSync(TRequest message, Action responseHandler);
/// There is no Sync overload with an IFlowParallelRequest parameter, as the AddRequest methods for that are
/// async, so you should always await them.
///
/// Constructs an IYieldPoint to continue the flow when responses arrive.
/// The continuation method is called when all responses have arrived.
/// Response handlers and the continuation method are guaranteed thread-safe access to the
/// controller and can store state.
/// Used for asynchronous continuation methods.
///
/// The converge continuation method to be called when all responses have been handled.
/// How the Yield method should behave when no requests have been added to the parallel request builder.
IYieldPoint Yield(Func> continuation, FlowNoRequestsBehaviour noRequestsBehaviour = FlowNoRequestsBehaviour.Exception);
///
/// Constructs an IYieldPoint to continue the flow when responses arrive.
/// The continuation method is called when all responses have arrived.
/// Response handlers and the continuation method are guaranteed thread-safe access to the
/// controller and can store state.
/// Used for synchronous continuation methods.
///
/// The converge continuation method to be called when all responses have been handled.
/// How the Yield method should behave when no requests have been added to the parallel request builder.
IYieldPoint YieldSync(Func continuation, FlowNoRequestsBehaviour noRequestsBehaviour = FlowNoRequestsBehaviour.Exception);
}
///
/// Provides means of adding one or more requests to a parallel request.
///
///
/// Add a parameter of this type to a parallel request's response handler to gain access to it's functionality.
/// Not available in other contexts.
///
public interface IFlowParallelRequest
{
///
/// Publish a request message and continue the flow when the response arrives.
/// Note that the response handler can not influence the flow as it does not return a YieldPoint.
/// It can instead store state in the controller for the continuation passed to the Yield method.
/// Used for asynchronous response handlers.
///
///
///
Task AddRequest(TRequest message, Func responseHandler);
///
/// This overload allows the response handler access to the IFlowParallelRequest interface, which
/// can be used to add additional requests to the parallel request before the continuation method passed to the Yield method is called.
///
///
Task AddRequest(TRequest message, Func responseHandler);
///
/// Publish a request message and continue the flow when the response arrives.
/// Note that the response handler can not influence the flow as it does not return a YieldPoint.
/// It can instead store state in the controller for the continuation passed to the Yield method.
/// Used for synchronous response handlers.
///
///
///
Task AddRequestSync(TRequest message, Action responseHandler);
}
///
/// Defines if and how the Flow should continue. Construct using any of the IFlowProvider methods.
///
public interface IYieldPoint
{
}
}