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) where TRequest : class where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; /// /// 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) where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; /// /// 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 AddRequestSync(TRequest message, Action responseHandler) where TRequest : class where TResponse : class; /// 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) where TRequest : class where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; /// /// 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) where TRequest : class where TResponse : class; } /// /// Defines if and how the Flow should continue. Construct using any of the IFlowProvider methods. /// public interface IYieldPoint { } }