diff --git a/src/Flowsharp.Core/Activities/Activity.cs b/src/Flowsharp.Core/Activities/Activity.cs deleted file mode 100644 index 205b10cae..000000000 --- a/src/Flowsharp.Core/Activities/Activity.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Flowsharp.ActivityResults; -using Flowsharp.Models; - -namespace Flowsharp.Activities -{ - public abstract class Activity : IActivity - { - public virtual Task CanExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - return Task.FromResult(CanExecute(workflowContext, activityContext)); - } - - public virtual Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - return Task.FromResult(Execute(workflowContext, activityContext)); - } - - public virtual Task ResumeAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - return Task.FromResult(Resume(workflowContext, activityContext)); - } - - public virtual Task OnActivityExecutedAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - OnActivityExecuted(workflowContext, activityContext); - return Task.CompletedTask; - } - - public virtual Task OnActivityExecutingAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - OnActivityExecuting(workflowContext, activityContext); - return Task.CompletedTask; - } - - public virtual Task ReceiveInputAsync(WorkflowExecutionContext workflowContext, IDictionary input, CancellationToken cancellationToken) - { - ReceiveInput(workflowContext, input); - return Task.CompletedTask; - } - - public virtual Task WorkflowResumedAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - WorkflowResumed(workflowContext); - return Task.CompletedTask; - } - - public virtual Task WorkflowResumingAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - WorkflowResuming(workflowContext); - return Task.CompletedTask; - } - - public virtual Task WorkflowStartedAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - WorkflowStarted(workflowContext); - return Task.CompletedTask; - } - - public virtual Task WorkflowStartingAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - WorkflowStarting(workflowContext); - return Task.CompletedTask; - } - - protected virtual ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) - { - return ActivateEndpoint(); - } - - protected virtual ActivityExecutionResult Resume(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) - { - return ActivateEndpoint(); - } - - protected virtual bool CanExecute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) => true; - protected virtual void OnActivityExecuted(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) {} - protected virtual void OnActivityExecuting(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) {} - protected virtual void ReceiveInput(WorkflowExecutionContext workflowContext, IDictionary input) {} - protected virtual void WorkflowResumed(WorkflowExecutionContext workflowContext) {} - protected virtual void WorkflowResuming(WorkflowExecutionContext workflowContext) {} - protected virtual void WorkflowStarted(WorkflowExecutionContext workflowContext) {} - protected virtual void WorkflowStarting(WorkflowExecutionContext workflowContext) {} - - protected HaltResult Halt() - { - return new HaltResult(); - } - - protected ActivateEndpointResult ActivateEndpoint(string name = null) - { - return new ActivateEndpointResult(new SourceEndpoint(this, name)); - } - - protected ScheduleActivityResult ScheduleActivity(IActivity activity) - { - return new ScheduleActivityResult(activity); - } - - protected ReturnValueResult SetReturnValue(object value) - { - return new ReturnValueResult(value); - } - - protected FinishWorkflowResult Finish() - { - return new FinishWorkflowResult(); - } - - protected NoopResult Noop() - { - return new NoopResult(); - } - } -} diff --git a/src/Flowsharp.Core/Activities/IActivity.cs b/src/Flowsharp.Core/Activities/IActivity.cs deleted file mode 100644 index cb927c4a3..000000000 --- a/src/Flowsharp.Core/Activities/IActivity.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Flowsharp.ActivityResults; -using Flowsharp.Models; - -namespace Flowsharp.Activities -{ - public interface IActivity - { - /// - /// Returns a value of whether the specified activity can execute. - /// - Task CanExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken); - - /// - /// Executes the specified activity. - /// - Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken); - - /// - /// Resumes the specified activity. - /// - Task ResumeAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken); - - /// - /// Executes before a workflow starts or resumes, giving activities an opportunity to read and store any values of interest. - /// - Task ReceiveInputAsync(WorkflowExecutionContext workflowContext, IDictionary input, CancellationToken cancellationToken); - - /// - /// Executes when a workflow is about to start. - /// - Task WorkflowStartingAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); - - /// - /// Executes when a workflow has started. - /// - Task WorkflowStartedAsync(WorkflowExecutionContext context, CancellationToken cancellationToken); - - /// - /// Executes when a workflow is about to be resumed. - /// - Task WorkflowResumingAsync(WorkflowExecutionContext context, CancellationToken cancellationToken); - - /// - /// Executes when a workflow is resumed. - /// - Task WorkflowResumedAsync(WorkflowExecutionContext context, CancellationToken cancellationToken); - - /// - /// Executes when an activity is about to be executed. - /// - /// The workflow execution context. - /// The activity context containing the activity that is the subject of the event. - /// The cancellation token. - Task OnActivityExecutingAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Called on each activity when an activity has been executed. - /// - /// The workflow execution context. - /// The activity context containing the activity that is the subject of the event. - /// The cancellation token. - Task OnActivityExecutedAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken); - } -} diff --git a/src/Flowsharp.Core/Activities/IfElse.cs b/src/Flowsharp.Core/Activities/IfElse.cs index cca303b83..5708793ea 100644 --- a/src/Flowsharp.Core/Activities/IfElse.cs +++ b/src/Flowsharp.Core/Activities/IfElse.cs @@ -1,27 +1,10 @@ -using System.Threading; -using System.Threading.Tasks; -using Flowsharp.ActivityResults; +using Flowsharp.Expressions; using Flowsharp.Models; -using Flowsharp.Scripting; namespace Flowsharp.Activities { public class IfElse : Activity { - private readonly IScriptEvaluator scriptEvaluator; - - public IfElse(IScriptEvaluator scriptEvaluator) - { - this.scriptEvaluator = scriptEvaluator; - } - - public ScriptExpression ConditionExpression { get; set; } - - public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - var result = await scriptEvaluator.EvaluateAsync(ConditionExpression, workflowContext, cancellationToken); - - return ActivateEndpoint(result ? "True" : "False"); - } + public WorkflowExpression ConditionExpression { get; set; } } } \ No newline at end of file diff --git a/src/Flowsharp.Core/Activities/SetVariable.cs b/src/Flowsharp.Core/Activities/SetVariable.cs index 7325ffd52..a53d4d9a4 100644 --- a/src/Flowsharp.Core/Activities/SetVariable.cs +++ b/src/Flowsharp.Core/Activities/SetVariable.cs @@ -1,28 +1,11 @@ -using System.Threading; -using System.Threading.Tasks; -using Flowsharp.ActivityResults; +using Flowsharp.Expressions; using Flowsharp.Models; -using Flowsharp.Scripting; namespace Flowsharp.Activities { public class SetVariable : Activity { - private readonly IScriptEvaluator scriptEvaluator; - - public SetVariable(IScriptEvaluator scriptEvaluator) - { - this.scriptEvaluator = scriptEvaluator; - } - public string VariableName { get; set; } - public ScriptExpression ValueExpression { get; set; } - - public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - var value = await scriptEvaluator.EvaluateAsync(ValueExpression, workflowContext, cancellationToken); - workflowContext.CurrentScope.SetVariable(VariableName, value); - return ActivateEndpoint(); - } + public WorkflowExpression ValueExpression { get; set; } } } \ No newline at end of file diff --git a/src/Flowsharp.Core/Expressions/IExpressionEvaluator.cs b/src/Flowsharp.Core/Expressions/IExpressionEvaluator.cs new file mode 100644 index 000000000..021bacff4 --- /dev/null +++ b/src/Flowsharp.Core/Expressions/IExpressionEvaluator.cs @@ -0,0 +1,12 @@ +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; + +namespace Flowsharp.Expressions +{ + public interface IExpressionEvaluator + { + string Syntax { get; } + Task EvaluateAsync(string expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Expressions/IWorkflowExpressionEvaluator.cs b/src/Flowsharp.Core/Expressions/IWorkflowExpressionEvaluator.cs new file mode 100644 index 000000000..1f01c71fc --- /dev/null +++ b/src/Flowsharp.Core/Expressions/IWorkflowExpressionEvaluator.cs @@ -0,0 +1,11 @@ +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; + +namespace Flowsharp.Expressions +{ + public interface IWorkflowExpressionEvaluator + { + Task EvaluateAsync(WorkflowExpression expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Expressions/JavaScriptEvaluator.cs b/src/Flowsharp.Core/Expressions/JavaScriptEvaluator.cs new file mode 100644 index 000000000..0507e033e --- /dev/null +++ b/src/Flowsharp.Core/Expressions/JavaScriptEvaluator.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; +using Jint; + +namespace Flowsharp.Expressions +{ + public class JavaScriptEvaluator : IExpressionEvaluator + { + public const string SyntaxName = "JavaScript"; + private readonly Engine engine; + + public JavaScriptEvaluator() + { + engine = new Engine(options => { options.AllowClr(); }); + } + + public string Syntax => SyntaxName; + + public Task EvaluateAsync(string expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken) + { + var workflowApi = new + { + getVariable = (Func) (name => workflowExecutionContext.CurrentScope.GetVariable(name)), + getLastResult = (Func)(() => workflowExecutionContext.CurrentScope.LastResult) + }; + + engine.SetValue("workflow", workflowApi); + engine.Execute(expression); + var returnValue = engine.GetCompletionValue(); + + return Task.FromResult((T)returnValue.ToObject()); + } + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Expressions/PlainTextEvaluator.cs b/src/Flowsharp.Core/Expressions/PlainTextEvaluator.cs new file mode 100644 index 000000000..b784825a3 --- /dev/null +++ b/src/Flowsharp.Core/Expressions/PlainTextEvaluator.cs @@ -0,0 +1,18 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; + +namespace Flowsharp.Expressions +{ + public class PlainTextEvaluator : IExpressionEvaluator + { + public const string SyntaxName = "PlainText"; + public string Syntax => SyntaxName; + + public Task EvaluateAsync(string expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken) + { + return Task.FromResult((T) Convert.ChangeType(expression, typeof(T))); + } + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Expressions/WorkflowExpression.cs b/src/Flowsharp.Core/Expressions/WorkflowExpression.cs new file mode 100644 index 000000000..5fe39a237 --- /dev/null +++ b/src/Flowsharp.Core/Expressions/WorkflowExpression.cs @@ -0,0 +1,16 @@ +namespace Flowsharp.Expressions +{ + public class WorkflowExpression + { + public WorkflowExpression(string syntax, string expression) + { + Syntax = syntax; + Expression = expression; + } + + public string Syntax { get; set; } + public string Expression { get; } + + public override string ToString() => Expression; + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Expressions/WorkflowExpressionEvaluator.cs b/src/Flowsharp.Core/Expressions/WorkflowExpressionEvaluator.cs new file mode 100644 index 000000000..7e3de955c --- /dev/null +++ b/src/Flowsharp.Core/Expressions/WorkflowExpressionEvaluator.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; + +namespace Flowsharp.Expressions +{ + public class WorkflowExpressionEvaluator : IWorkflowExpressionEvaluator + { + private readonly IDictionary evaluators; + + public WorkflowExpressionEvaluator(IEnumerable evaluators) + { + this.evaluators = evaluators.ToDictionary(x => x.Syntax); + } + + public async Task EvaluateAsync(WorkflowExpression expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken) + { + var evaluator = evaluators[expression.Syntax]; + return await evaluator.EvaluateAsync(expression.Expression, workflowExecutionContext, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Extensions/ConnectionActivityExtensions.cs b/src/Flowsharp.Core/Extensions/ConnectionActivityExtensions.cs deleted file mode 100644 index 85b0b9771..000000000 --- a/src/Flowsharp.Core/Extensions/ConnectionActivityExtensions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Flowsharp.Extensions -{ - public static class ConnectionExtensions - { - } -} \ No newline at end of file diff --git a/src/Flowsharp.Core/Flowsharp.Core.csproj b/src/Flowsharp.Core/Flowsharp.Core.csproj index b6e82098c..70d822784 100644 --- a/src/Flowsharp.Core/Flowsharp.Core.csproj +++ b/src/Flowsharp.Core/Flowsharp.Core.csproj @@ -8,8 +8,12 @@ + + + + diff --git a/src/Flowsharp.Core/Handlers/ActivityHandler.cs b/src/Flowsharp.Core/Handlers/ActivityHandler.cs deleted file mode 100644 index a6e1fe6ab..000000000 --- a/src/Flowsharp.Core/Handlers/ActivityHandler.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Flowsharp.Activities; -using Flowsharp.ActivityResults; -using Flowsharp.Models; - -namespace Flowsharp.Handlers -{ - public abstract class ActivityHandler : IActivityHandler where T : IActivity - { - public virtual Task CanExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - return Task.FromResult(CanExecute(workflowContext, activityContext)); - } - - public virtual Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - return Task.FromResult(Execute(workflowContext, activityContext)); - } - - public virtual Task ResumeAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - return Task.FromResult(Resume(workflowContext, activityContext)); - } - - public virtual Task OnActivityExecutedAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - OnActivityExecuted(workflowContext, activityContext); - return Task.CompletedTask; - } - - public virtual Task OnActivityExecutingAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - OnActivityExecuting(workflowContext, activityContext); - return Task.CompletedTask; - } - - public virtual Task ReceiveInputAsync(WorkflowExecutionContext workflowContext, Variables input, CancellationToken cancellationToken) - { - ReceiveInput(workflowContext, input); - return Task.CompletedTask; - } - - public virtual Task WorkflowResumedAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - WorkflowResumed(workflowContext); - return Task.CompletedTask; - } - - public virtual Task WorkflowResumingAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - WorkflowResuming(workflowContext); - return Task.CompletedTask; - } - - public virtual Task WorkflowStartedAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - WorkflowStarted(workflowContext); - return Task.CompletedTask; - } - - public virtual Task WorkflowStartingAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - WorkflowStarting(workflowContext); - return Task.CompletedTask; - } - - protected virtual ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) - { - return ActivateEndpoint(); - } - - protected virtual ActivityExecutionResult Resume(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) - { - return ActivateEndpoint(); - } - - protected virtual bool CanExecute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) => true; - protected virtual void OnActivityExecuted(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) {} - protected virtual void OnActivityExecuting(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) {} - protected virtual void ReceiveInput(WorkflowExecutionContext workflowContext, Variables input) {} - protected virtual void WorkflowResumed(WorkflowExecutionContext workflowContext) {} - protected virtual void WorkflowResuming(WorkflowExecutionContext workflowContext) {} - protected virtual void WorkflowStarted(WorkflowExecutionContext workflowContext) {} - protected virtual void WorkflowStarting(WorkflowExecutionContext workflowContext) {} - - protected HaltResult Halt() - { - return new HaltResult(); - } - - protected ActivateEndpointResult ActivateEndpoint(string name = null) - { - return new ActivateEndpointResult(new SourceEndpoint(this, name)); - } - - protected ScheduleActivityResult ScheduleActivity(IActivity activity) - { - return new ScheduleActivityResult(activity); - } - - protected ReturnValueResult SetReturnValue(object value) - { - return new ReturnValueResult(value); - } - - protected FinishWorkflowResult Finish() - { - return new FinishWorkflowResult(); - } - - protected NoopResult Noop() - { - return new NoopResult(); - } - } -} \ No newline at end of file diff --git a/src/Flowsharp.Core/Handlers/IActivityHandler.cs b/src/Flowsharp.Core/Handlers/IActivityHandler.cs deleted file mode 100644 index 9be3cad3e..000000000 --- a/src/Flowsharp.Core/Handlers/IActivityHandler.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Flowsharp.Activities; -using Flowsharp.ActivityResults; -using Flowsharp.Models; - -namespace Flowsharp.Handlers -{ - public interface IActivityHandler - { - } - - public interface IActivityHandler : IActivityHandler where T:IActivity - { - /// - /// Returns a value of whether the specified activity can execute. - /// - Task CanExecuteAsync(WorkflowExecutionContext workflowContext, T activity, CancellationToken cancellationToken); - - /// - /// Executes the specified activity. - /// - Task ExecuteAsync(WorkflowExecutionContext workflowContext, T activity, CancellationToken cancellationToken); - - /// - /// Resumes the specified activity. - /// - Task ResumeAsync(WorkflowExecutionContext workflowContext, T activity, CancellationToken cancellationToken); - - /// - /// Executes before a workflow starts or resumes, giving activities an opportunity to read and store any values of interest. - /// - Task ReceiveInputAsync(WorkflowExecutionContext workflowContext, Variables input, CancellationToken cancellationToken); - - /// - /// Executes when a workflow is about to start. - /// - Task WorkflowStartingAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); - - /// - /// Executes when a workflow has started. - /// - Task WorkflowStartedAsync(WorkflowExecutionContext context, CancellationToken cancellationToken); - - /// - /// Executes when a workflow is about to be resumed. - /// - Task WorkflowResumingAsync(WorkflowExecutionContext context, CancellationToken cancellationToken); - - /// - /// Executes when a workflow is resumed. - /// - Task WorkflowResumedAsync(WorkflowExecutionContext context, CancellationToken cancellationToken); - - /// - /// Executes when an activity is about to be executed. - /// - Task OnActivityExecutingAsync(WorkflowExecutionContext workflowContext, T activity, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Called on each activity when an activity has been executed. - /// - Task OnActivityExecutedAsync(WorkflowExecutionContext workflowContext, T activity, CancellationToken cancellationToken); - } -} \ No newline at end of file diff --git a/src/Flowsharp.Core/Handlers/IfElseHandler.cs b/src/Flowsharp.Core/Handlers/IfElseHandler.cs index bda46e498..f02e5d445 100644 --- a/src/Flowsharp.Core/Handlers/IfElseHandler.cs +++ b/src/Flowsharp.Core/Handlers/IfElseHandler.cs @@ -1,7 +1,26 @@ +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Activities; +using Flowsharp.Expressions; +using Flowsharp.Models; +using Flowsharp.Results; +using Flowsharp.Services; + namespace Flowsharp.Handlers { - public class IfElseHandler + public class IfElseHandler : ActivityHandler { - + private readonly IWorkflowExpressionEvaluator expressionEvaluator; + + public IfElseHandler(IWorkflowExpressionEvaluator expressionEvaluator) + { + this.expressionEvaluator = expressionEvaluator; + } + + protected override async Task OnExecuteAsync(IfElse activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + { + var result = await expressionEvaluator.EvaluateAsync(activity.ConditionExpression, workflowContext, cancellationToken); + return ActivateEndpoint(result ? "True" : "False"); + } } } \ No newline at end of file diff --git a/src/Flowsharp.Core/Handlers/SetVariableHandler.cs b/src/Flowsharp.Core/Handlers/SetVariableHandler.cs new file mode 100644 index 000000000..90691d365 --- /dev/null +++ b/src/Flowsharp.Core/Handlers/SetVariableHandler.cs @@ -0,0 +1,27 @@ +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Activities; +using Flowsharp.Expressions; +using Flowsharp.Models; +using Flowsharp.Results; +using Flowsharp.Services; + +namespace Flowsharp.Handlers +{ + public class SetVariableHandler : ActivityHandler + { + private readonly IWorkflowExpressionEvaluator expressionEvaluator; + + public SetVariableHandler(IWorkflowExpressionEvaluator expressionEvaluator) + { + this.expressionEvaluator = expressionEvaluator; + } + + protected override async Task OnExecuteAsync(SetVariable activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + { + var value = await expressionEvaluator.EvaluateAsync(activity.ValueExpression, workflowContext, cancellationToken); + workflowContext.CurrentScope.SetVariable(activity.VariableName, value); + return ActivateEndpoint(); + } + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Models/Activity.cs b/src/Flowsharp.Core/Models/Activity.cs new file mode 100644 index 000000000..4f6294608 --- /dev/null +++ b/src/Flowsharp.Core/Models/Activity.cs @@ -0,0 +1,6 @@ +namespace Flowsharp.Models +{ + public abstract class Activity : IActivity + { + } +} diff --git a/src/Flowsharp.Core/Models/IActivity.cs b/src/Flowsharp.Core/Models/IActivity.cs new file mode 100644 index 000000000..cd943c3ff --- /dev/null +++ b/src/Flowsharp.Core/Models/IActivity.cs @@ -0,0 +1,6 @@ +namespace Flowsharp.Models +{ + public interface IActivity + { + } +} diff --git a/src/Flowsharp.Core/Models/Workflow.cs b/src/Flowsharp.Core/Models/Workflow.cs index 86d36ed2c..8dbf4f795 100644 --- a/src/Flowsharp.Core/Models/Workflow.cs +++ b/src/Flowsharp.Core/Models/Workflow.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; -using Flowsharp.Models; +using Flowsharp.Activities; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace Flowsharp.Activities +namespace Flowsharp.Models { public class Workflow { diff --git a/src/Flowsharp.Core/Models/WorkflowExecutionContext.cs b/src/Flowsharp.Core/Models/WorkflowExecutionContext.cs index 8b6f333ce..55482b5fc 100644 --- a/src/Flowsharp.Core/Models/WorkflowExecutionContext.cs +++ b/src/Flowsharp.Core/Models/WorkflowExecutionContext.cs @@ -77,7 +77,7 @@ namespace Flowsharp.Models Workflow.Status = WorkflowStatus.Finished; } - public virtual void ScheduleNextActivities(WorkflowExecutionContext workflowContext, SourceEndpoint endpoint) + public void ScheduleNextActivities(WorkflowExecutionContext workflowContext, SourceEndpoint endpoint) { var completedActivity = workflowContext.CurrentActivity; var connections = Workflow.Connections.Where(x => x.Source.Activity == completedActivity && x.Source.Name == endpoint.Name); diff --git a/src/Flowsharp.Core/Results/ActivateEndpointResult.cs b/src/Flowsharp.Core/Results/ActivateEndpointResult.cs index 9ddfbcade..ded61128c 100644 --- a/src/Flowsharp.Core/Results/ActivateEndpointResult.cs +++ b/src/Flowsharp.Core/Results/ActivateEndpointResult.cs @@ -1,22 +1,24 @@ using Flowsharp.Models; +using Flowsharp.Services; -namespace Flowsharp.ActivityResults +namespace Flowsharp.Results { /// /// A result that carries information about the next activity to execute. /// public class ActivateEndpointResult : ActivityExecutionResult { - public ActivateEndpointResult(SourceEndpoint endpoint) + public ActivateEndpointResult(string endpointName = null) { - Endpoint = endpoint; + EndpointName = endpointName; } - public SourceEndpoint Endpoint { get; } + public string EndpointName { get; } - protected override void Execute(WorkflowExecutionContext workflowContext) + protected override void Execute(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext) { - workflowContext.ScheduleNextActivities(workflowContext, Endpoint); + var currentActivity = workflowContext.CurrentActivity; + workflowContext.ScheduleNextActivities(workflowContext, new SourceEndpoint(currentActivity, EndpointName)); } } } \ No newline at end of file diff --git a/src/Flowsharp.Core/Results/ActivityExecutionResult.cs b/src/Flowsharp.Core/Results/ActivityExecutionResult.cs index cce7c58fe..61d92d9d9 100644 --- a/src/Flowsharp.Core/Results/ActivityExecutionResult.cs +++ b/src/Flowsharp.Core/Results/ActivityExecutionResult.cs @@ -2,20 +2,20 @@ using System.Threading; using System.Threading.Tasks; using Flowsharp.Models; +using Flowsharp.Services; -namespace Flowsharp.ActivityResults +namespace Flowsharp.Results { public abstract class ActivityExecutionResult : IActivityExecutionResult { - public virtual Task ExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + public virtual Task ExecuteAsync(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) { - Execute(workflowContext); + Execute(invoker, workflowContext); return Task.CompletedTask; } - protected virtual void Execute(WorkflowExecutionContext workflowContext) + protected virtual void Execute(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext) { - throw new NotImplementedException("You must either implement ExecuteAsync or Execute"); } } } diff --git a/src/Flowsharp.Core/Results/FinishWorkflowResult.cs b/src/Flowsharp.Core/Results/FinishWorkflowResult.cs index 95fec5e70..3a6fe3fb9 100644 --- a/src/Flowsharp.Core/Results/FinishWorkflowResult.cs +++ b/src/Flowsharp.Core/Results/FinishWorkflowResult.cs @@ -1,10 +1,11 @@ using Flowsharp.Models; +using Flowsharp.Services; -namespace Flowsharp.ActivityResults +namespace Flowsharp.Results { public class FinishWorkflowResult : ActivityExecutionResult { - protected override void Execute(WorkflowExecutionContext workflowContext) + protected override void Execute(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext) { workflowContext.Finish(); } diff --git a/src/Flowsharp.Core/Results/HaltResult.cs b/src/Flowsharp.Core/Results/HaltResult.cs index 9b62aef97..fc169e635 100644 --- a/src/Flowsharp.Core/Results/HaltResult.cs +++ b/src/Flowsharp.Core/Results/HaltResult.cs @@ -1,25 +1,24 @@ using System.Threading; using System.Threading.Tasks; using Flowsharp.Models; +using Flowsharp.Services; -namespace Flowsharp.ActivityResults +namespace Flowsharp.Results { /// /// Halts workflow execution. /// public class HaltResult : ActivityExecutionResult { - public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) - { - var currentActivity = workflowContext.CurrentActivity; - + public override async Task ExecuteAsync(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + { if (workflowContext.IsFirstPass) { - // Resume immediately when this is the first pass. - var result = await currentActivity.ResumeAsync(workflowContext, new ActivityExecutionContext(currentActivity), cancellationToken); + var activity = workflowContext.CurrentActivity; + var result = await invoker.ActivityInvoker.ResumeAsync(activity, workflowContext, cancellationToken); workflowContext.IsFirstPass = false; - await result.ExecuteAsync(workflowContext, cancellationToken); + await result.ExecuteAsync(invoker, workflowContext, cancellationToken); } else { diff --git a/src/Flowsharp.Core/Results/IActivityExecutionResult.cs b/src/Flowsharp.Core/Results/IActivityExecutionResult.cs index b4761d556..e5aa4e0fb 100644 --- a/src/Flowsharp.Core/Results/IActivityExecutionResult.cs +++ b/src/Flowsharp.Core/Results/IActivityExecutionResult.cs @@ -1,11 +1,12 @@ using System.Threading; using System.Threading.Tasks; using Flowsharp.Models; +using Flowsharp.Services; -namespace Flowsharp.ActivityResults +namespace Flowsharp.Results { public interface IActivityExecutionResult { - Task ExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); + Task ExecuteAsync(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); } } diff --git a/src/Flowsharp.Core/Results/NoopResult.cs b/src/Flowsharp.Core/Results/NoopResult.cs index 7948c4788..1c3795b2d 100644 --- a/src/Flowsharp.Core/Results/NoopResult.cs +++ b/src/Flowsharp.Core/Results/NoopResult.cs @@ -1,13 +1,14 @@ using Flowsharp.Models; +using Flowsharp.Services; -namespace Flowsharp.ActivityResults +namespace Flowsharp.Results { /// /// A result that does nothing. /// public class NoopResult : ActivityExecutionResult { - protected override void Execute(WorkflowExecutionContext workflowContext) + protected override void Execute(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext) { // Noop. } diff --git a/src/Flowsharp.Core/Results/ReturnValueResult.cs b/src/Flowsharp.Core/Results/ReturnValueResult.cs index 9dcaa6a11..d3f7e0162 100644 --- a/src/Flowsharp.Core/Results/ReturnValueResult.cs +++ b/src/Flowsharp.Core/Results/ReturnValueResult.cs @@ -1,6 +1,7 @@ using Flowsharp.Models; +using Flowsharp.Services; -namespace Flowsharp.ActivityResults +namespace Flowsharp.Results { public class ReturnValueResult : ActivityExecutionResult { @@ -11,7 +12,7 @@ namespace Flowsharp.ActivityResults this.value = value; } - protected override void Execute(WorkflowExecutionContext workflowContext) + protected override void Execute(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext) { workflowContext.SetLastResult(value); } diff --git a/src/Flowsharp.Core/Results/ScheduleActivityResult.cs b/src/Flowsharp.Core/Results/ScheduleActivityResult.cs index 23a7a2ea6..7fddf8bc3 100644 --- a/src/Flowsharp.Core/Results/ScheduleActivityResult.cs +++ b/src/Flowsharp.Core/Results/ScheduleActivityResult.cs @@ -1,7 +1,8 @@ using Flowsharp.Activities; using Flowsharp.Models; +using Flowsharp.Services; -namespace Flowsharp.ActivityResults +namespace Flowsharp.Results { public class ScheduleActivityResult : ActivityExecutionResult { @@ -12,7 +13,7 @@ namespace Flowsharp.ActivityResults this.activity = activity; } - protected override void Execute(WorkflowExecutionContext workflowContext) + protected override void Execute(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext) { workflowContext.ScheduleActivity(activity); } diff --git a/src/Flowsharp.Core/Scripting/IScriptEvaluator.cs b/src/Flowsharp.Core/Scripting/IScriptEvaluator.cs deleted file mode 100644 index 1e0698ffe..000000000 --- a/src/Flowsharp.Core/Scripting/IScriptEvaluator.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Flowsharp.Models; - -namespace Flowsharp.Scripting -{ - public interface IScriptEvaluator - { - Task EvaluateAsync(ScriptExpression script, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken); - } -} \ No newline at end of file diff --git a/src/Flowsharp.Core/Scripting/JintEvaluator.cs b/src/Flowsharp.Core/Scripting/JintEvaluator.cs deleted file mode 100644 index c0150f2eb..000000000 --- a/src/Flowsharp.Core/Scripting/JintEvaluator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Flowsharp.Models; -using Jint; - -namespace Flowsharp.Scripting -{ - public class JintEvaluator : IScriptEvaluator - { - private readonly Engine engine; - - public JintEvaluator() - { - engine = new Engine(options => { options.AllowClr(); }); - } - - public Task EvaluateAsync(ScriptExpression script, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken) - { - engine.SetValue("workflow.getVariable", (Func)(name => workflowExecutionContext.CurrentScope.GetVariable(name))); - engine.Execute(script.Expression); - var returnValue = engine.GetCompletionValue(); - - return Task.FromResult((T)returnValue.ToObject()); - } - } -} \ No newline at end of file diff --git a/src/Flowsharp.Core/Scripting/ScriptExpression.cs b/src/Flowsharp.Core/Scripting/ScriptExpression.cs deleted file mode 100644 index f6355f337..000000000 --- a/src/Flowsharp.Core/Scripting/ScriptExpression.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Flowsharp.Scripting -{ - public class ScriptExpression - { - public static implicit operator string(ScriptExpression expression) => expression.Expression; - public static implicit operator ScriptExpression(string expression) => new ScriptExpression(expression); - - public ScriptExpression(string expression) - { - Expression = expression; - } - - public string Expression { get; } - - public override string ToString() => Expression; - } -} \ No newline at end of file diff --git a/src/Flowsharp.Core/Serialization/IWorkflowSerializer.cs b/src/Flowsharp.Core/Serialization/IWorkflowSerializer.cs index 6bf6aa655..ffc249c89 100644 --- a/src/Flowsharp.Core/Serialization/IWorkflowSerializer.cs +++ b/src/Flowsharp.Core/Serialization/IWorkflowSerializer.cs @@ -1,6 +1,7 @@ using System.Threading; using System.Threading.Tasks; using Flowsharp.Activities; +using Flowsharp.Models; namespace Flowsharp.Serialization { diff --git a/src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs b/src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs index 3503d89ba..d8c357327 100644 --- a/src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs +++ b/src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs @@ -1,6 +1,7 @@ using System.Threading; using System.Threading.Tasks; using Flowsharp.Activities; +using Flowsharp.Models; using Flowsharp.Services; using Newtonsoft.Json; diff --git a/src/Flowsharp.Core/Services/ActivityHandler.cs b/src/Flowsharp.Core/Services/ActivityHandler.cs new file mode 100644 index 000000000..8193d5de6 --- /dev/null +++ b/src/Flowsharp.Core/Services/ActivityHandler.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; +using Flowsharp.Results; + +namespace Flowsharp.Services +{ + public abstract class ActivityHandler : IActivityHandler where T : IActivity + { + public Type ActivityType => typeof(T); + + public Task CanExecuteAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) => OnCanExecuteAsync((T)activity, workflowContext, cancellationToken); + public Task ExecuteAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) => OnExecuteAsync((T) activity, workflowContext, cancellationToken); + public Task ResumeAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) => OnResumeAsync((T)activity, workflowContext, cancellationToken); + + protected virtual Task OnCanExecuteAsync(T activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) => Task.FromResult(OnCanExecute(activity, workflowContext)); + protected virtual Task OnExecuteAsync(T activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) => Task.FromResult(OnExecute(activity, workflowContext)); + protected virtual Task OnResumeAsync(T activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) => Task.FromResult(OnResume(activity, workflowContext)); + + protected virtual bool OnCanExecute(T activity, WorkflowExecutionContext workflowContext) => true; + protected virtual ActivityExecutionResult OnExecute(T activity, WorkflowExecutionContext workflowContext) => Noop(); + protected virtual ActivityExecutionResult OnResume(T activity, WorkflowExecutionContext workflowContext) => Noop(); + + protected HaltResult Halt() => new HaltResult(); + protected ActivateEndpointResult ActivateEndpoint(string name = null) => new ActivateEndpointResult(name); + protected ScheduleActivityResult ScheduleActivity(IActivity activity) => new ScheduleActivityResult(activity); + protected ReturnValueResult SetReturnValue(object value) => new ReturnValueResult(value); + protected FinishWorkflowResult Finish() => new FinishWorkflowResult(); + protected NoopResult Noop() => new NoopResult(); + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Services/ActivityInvoker.cs b/src/Flowsharp.Core/Services/ActivityInvoker.cs new file mode 100644 index 000000000..1ad60868c --- /dev/null +++ b/src/Flowsharp.Core/Services/ActivityInvoker.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; +using Flowsharp.Results; + +namespace Flowsharp.Services +{ + public class ActivityInvoker : IActivityInvoker + { + private readonly IDictionary handlers; + + public ActivityInvoker(IEnumerable handlers) + { + this.handlers = handlers.ToDictionary(x => x.ActivityType); + } + + public async Task CanExecuteAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + { + return await GetHandlerFor(activity).CanExecuteAsync(activity, workflowContext, cancellationToken); + } + + public async Task ExecuteAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + { + return await GetHandlerFor(activity).ExecuteAsync(activity, workflowContext, cancellationToken); + } + + public async Task ResumeAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + { + return await GetHandlerFor(activity).ResumeAsync(activity, workflowContext, cancellationToken); + } + + private IActivityHandler GetHandlerFor(IActivity activity) + { + return handlers[activity.GetType()]; + } + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Services/IActivityHandler.cs b/src/Flowsharp.Core/Services/IActivityHandler.cs new file mode 100644 index 000000000..6e6a56a8a --- /dev/null +++ b/src/Flowsharp.Core/Services/IActivityHandler.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; +using Flowsharp.Results; + +namespace Flowsharp.Services +{ + public interface IActivityHandler + { + /// + /// The type of activity handled by this handler. + /// + Type ActivityType { get; } + + /// + /// Returns a value of whether the specified activity can execute. + /// + Task CanExecuteAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); + + /// + /// Executes the specified activity. + /// + Task ExecuteAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); + + /// + /// Resumes the specified activity. + /// + Task ResumeAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Services/IActivityInvoker.cs b/src/Flowsharp.Core/Services/IActivityInvoker.cs new file mode 100644 index 000000000..1c9b43b27 --- /dev/null +++ b/src/Flowsharp.Core/Services/IActivityInvoker.cs @@ -0,0 +1,14 @@ +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Models; +using Flowsharp.Results; + +namespace Flowsharp.Services +{ + public interface IActivityInvoker + { + Task CanExecuteAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); + Task ExecuteAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); + Task ResumeAsync(IActivity activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/src/Flowsharp.Core/Services/IWorkflowInvoker.cs b/src/Flowsharp.Core/Services/IWorkflowInvoker.cs index f24c522a1..0111b558c 100644 --- a/src/Flowsharp.Core/Services/IWorkflowInvoker.cs +++ b/src/Flowsharp.Core/Services/IWorkflowInvoker.cs @@ -7,6 +7,7 @@ namespace Flowsharp.Services { public interface IWorkflowInvoker { + IActivityInvoker ActivityInvoker { get; } Task InvokeAsync(Workflow workflow, IActivity startActivity = default, CancellationToken cancellationToken = default); } } diff --git a/src/Flowsharp.Core/Services/WorkflowInvoker.cs b/src/Flowsharp.Core/Services/WorkflowInvoker.cs index 20a1b352b..582316061 100644 --- a/src/Flowsharp.Core/Services/WorkflowInvoker.cs +++ b/src/Flowsharp.Core/Services/WorkflowInvoker.cs @@ -2,22 +2,23 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Flowsharp.Activities; -using Flowsharp.ActivityResults; using Flowsharp.Extensions; using Flowsharp.Models; +using Flowsharp.Results; using Microsoft.Extensions.Logging; namespace Flowsharp.Services { public class WorkflowInvoker : IWorkflowInvoker { - public WorkflowInvoker(ILogger logger) + public WorkflowInvoker(IActivityInvoker activityInvoker, ILogger logger) { + ActivityInvoker = activityInvoker; this.logger = logger; } private readonly ILogger logger; + public IActivityInvoker ActivityInvoker { get; } public async Task InvokeAsync(Workflow workflow, IActivity startActivity = default, CancellationToken cancellationToken = default) { @@ -31,7 +32,6 @@ namespace Flowsharp.Services workflowExecutionContext.Workflow.Status = WorkflowStatus.Executing; workflowExecutionContext.ScheduleActivity(startActivity); - await InvokeActivitiesAsync(workflowExecutionContext, x => x.WorkflowStartingAsync(workflowExecutionContext, cancellationToken)); while (workflowExecutionContext.HasScheduledActivities) { @@ -41,7 +41,7 @@ namespace Flowsharp.Services if(result == null) break; - await result.ExecuteAsync(workflowExecutionContext, cancellationToken); + await result.ExecuteAsync(this, workflowExecutionContext, cancellationToken); workflowExecutionContext.IsFirstPass = false; isResuming = false; @@ -57,8 +57,6 @@ namespace Flowsharp.Services { try { - //await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutingAsync(workflowContext, activity, cancellationToken)); - if (cancellationToken.IsCancellationRequested) { workflowContext.Workflow.Status = WorkflowStatus.Aborted; @@ -66,7 +64,6 @@ namespace Flowsharp.Services } return await ExecuteOrResumeActivityAsync(workflowContext, activity, isResuming, cancellationToken); - //await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutedAsync(workflowContext, activity, cancellationToken)); } catch (Exception ex) @@ -88,21 +85,9 @@ namespace Flowsharp.Services private async Task ExecuteOrResumeActivityAsync(WorkflowExecutionContext workflowContext, IActivity activity, bool isResuming, CancellationToken cancellationToken) { - if (!isResuming) - { - // Execute the current activity. - return await activity.ExecuteAsync(workflowContext, new ActivityExecutionContext(activity), cancellationToken); - } - else - { - // Resume the current activity. - return await activity.ResumeAsync(workflowContext, new ActivityExecutionContext(activity), cancellationToken); - } - } - - private async Task InvokeActivitiesAsync(WorkflowExecutionContext workflowContext, Func action) - { - await workflowContext.Workflow.Activities.InvokeAsync(action, logger); + return isResuming + ? await ActivityInvoker.ResumeAsync(activity, workflowContext, cancellationToken) + : await ActivityInvoker.ExecuteAsync(activity, workflowContext, cancellationToken); } } } diff --git a/src/Flowsharp.Samples.Console/Activities/ReadLine.cs b/src/Flowsharp.Samples.Console/Activities/ReadLine.cs index cc0d07aef..4e8ea5b1e 100644 --- a/src/Flowsharp.Samples.Console/Activities/ReadLine.cs +++ b/src/Flowsharp.Samples.Console/Activities/ReadLine.cs @@ -2,48 +2,13 @@ using System.Threading; using System.Threading.Tasks; using Flowsharp.Activities; -using Flowsharp.ActivityResults; using Flowsharp.Models; +using Flowsharp.Results; namespace Flowsharp.Samples.Console.Activities { public class ReadLine : Activity { - private readonly TextReader input; - - public ReadLine() : this(System.Console.In) - { - } - - public ReadLine(TextReader input) - { - this.input = input; - } - - public ReadLine(string argumentName) - { - ArgumentName = argumentName; - input = null; - } - public string ArgumentName { get; set; } - - public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - if (input == null) - return Halt(); - - var value = await input.ReadLineAsync(); - workflowContext.SetLastResult(value); - return ActivateEndpoint(); - - } - - protected override ActivityExecutionResult Resume(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) - { - var receivedInput = workflowContext.Workflow.Arguments[ArgumentName]; - workflowContext.SetLastResult(receivedInput); - return ActivateEndpoint(); - } } } \ No newline at end of file diff --git a/src/Flowsharp.Samples.Console/Activities/WriteLine.cs b/src/Flowsharp.Samples.Console/Activities/WriteLine.cs index e6aed8673..f7dc5ee9b 100644 --- a/src/Flowsharp.Samples.Console/Activities/WriteLine.cs +++ b/src/Flowsharp.Samples.Console/Activities/WriteLine.cs @@ -2,9 +2,10 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using Flowsharp.ActivityResults; +using Flowsharp.Expressions; using Flowsharp.Models; -using Activity = Flowsharp.Activities.Activity; +using Flowsharp.Results; +using Activity = Flowsharp.Models.Activity; namespace Flowsharp.Samples.Console.Activities { @@ -13,42 +14,15 @@ namespace Flowsharp.Samples.Console.Activities /// public class WriteLine : Activity { - private readonly TextWriter output; - private readonly Func textProvider; - - public WriteLine() : this(System.Console.Out, null) + public WriteLine() { } - public WriteLine(string text) : this(System.Console.Out, text) + public WriteLine(string text) { + TextExpression = new WorkflowExpression(PlainTextEvaluator.SyntaxName, text); } - public WriteLine(Func textProvider) : this(System.Console.Out, null) - { - this.textProvider = textProvider; - } - - public WriteLine(TextWriter output, string text) - { - this.output = output; - Text = text; - textProvider = (w, a) => Text; - } - - public string Text { get; set; } - - protected override bool CanExecute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) - { - var text = textProvider(workflowContext, activityContext); - return text != null; - } - - public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken) - { - var text = textProvider(workflowContext, activityContext); - await output.WriteLineAsync(text); - return ActivateEndpoint(); - } + public WorkflowExpression TextExpression { get; set; } } } diff --git a/src/Flowsharp.Samples.Console/Handlers/ReadLineHandler.cs b/src/Flowsharp.Samples.Console/Handlers/ReadLineHandler.cs new file mode 100644 index 000000000..ddc95e608 --- /dev/null +++ b/src/Flowsharp.Samples.Console/Handlers/ReadLineHandler.cs @@ -0,0 +1,43 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Handlers; +using Flowsharp.Models; +using Flowsharp.Results; +using Flowsharp.Samples.Console.Activities; +using Flowsharp.Services; + +namespace Flowsharp.Samples.Console.Handlers +{ + public class ReadLineHandler : ActivityHandler + { + private readonly TextReader input; + + public ReadLineHandler() + { + } + + public ReadLineHandler(TextReader input) + { + this.input = input; + } + + protected override async Task OnExecuteAsync(ReadLine activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + { + if (input == null) + return Halt(); + + var value = await input.ReadLineAsync(); + workflowContext.SetLastResult(value); + return ActivateEndpoint(); + + } + + protected override ActivityExecutionResult OnResume(ReadLine activity, WorkflowExecutionContext workflowContext) + { + var receivedInput = workflowContext.Workflow.Arguments[activity.ArgumentName]; + workflowContext.SetLastResult(receivedInput); + return ActivateEndpoint(); + } + } +} \ No newline at end of file diff --git a/src/Flowsharp.Samples.Console/Handlers/WriteLineHandler.cs b/src/Flowsharp.Samples.Console/Handlers/WriteLineHandler.cs new file mode 100644 index 000000000..343db36e8 --- /dev/null +++ b/src/Flowsharp.Samples.Console/Handlers/WriteLineHandler.cs @@ -0,0 +1,38 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Flowsharp.Expressions; +using Flowsharp.Handlers; +using Flowsharp.Models; +using Flowsharp.Results; +using Flowsharp.Samples.Console.Activities; +using Flowsharp.Services; + +namespace Flowsharp.Samples.Console.Handlers +{ + /// + /// Writes a text string to the specified stream. + /// + public class WriteLineHandler : ActivityHandler + { + private readonly IWorkflowExpressionEvaluator evaluator; + private readonly TextWriter output; + + public WriteLineHandler(IWorkflowExpressionEvaluator evaluator) : this(evaluator, System.Console.Out) + { + } + + public WriteLineHandler(IWorkflowExpressionEvaluator evaluator, TextWriter output) + { + this.evaluator = evaluator; + this.output = output; + } + + protected override async Task OnExecuteAsync(WriteLine activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken) + { + var text = await evaluator.EvaluateAsync(activity.TextExpression, workflowContext, cancellationToken); + await output.WriteLineAsync(text); + return ActivateEndpoint(); + } + } +} diff --git a/src/Flowsharp.Samples.Console/Program.cs b/src/Flowsharp.Samples.Console/Program.cs index 80729d995..badf52816 100644 --- a/src/Flowsharp.Samples.Console/Program.cs +++ b/src/Flowsharp.Samples.Console/Program.cs @@ -1,6 +1,13 @@ using System.Threading; using System.Threading.Tasks; +using Flowsharp.Expressions; +using Flowsharp.Handlers; +using Flowsharp.Samples.Console.Handlers; using Flowsharp.Samples.Console.Programs; +using Flowsharp.Serialization; +using Flowsharp.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace Flowsharp.Samples.Console { @@ -8,8 +15,29 @@ namespace Flowsharp.Samples.Console { static async Task Main() { - //await new AdditionWorkflowProgram().RunAsync(CancellationToken.None); - await new AdditionWorkflowProgramLongRunning().RunAsync(CancellationToken.None); + var services = new ServiceCollection() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddLogging(logging => logging.AddConsole()); + + services + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(); + + services + .AddSingleton() + .AddSingleton(); + + var serviceProvider = services.BuildServiceProvider(); + var program = serviceProvider.GetRequiredService(); + + await program.RunAsync(CancellationToken.None); } } } diff --git a/src/Flowsharp.Samples.Console/Programs/AdditionWorkflowProgram.cs b/src/Flowsharp.Samples.Console/Programs/AdditionWorkflowProgram.cs index 6dff581bf..fa5337ca8 100644 --- a/src/Flowsharp.Samples.Console/Programs/AdditionWorkflowProgram.cs +++ b/src/Flowsharp.Samples.Console/Programs/AdditionWorkflowProgram.cs @@ -1,5 +1,9 @@ using System.Threading; using System.Threading.Tasks; +using Flowsharp.Expressions; +using Flowsharp.Handlers; +using Flowsharp.Samples.Console.Activities; +using Flowsharp.Samples.Console.Handlers; using Flowsharp.Samples.Console.Workflows; using Flowsharp.Serialization; using Flowsharp.Services; @@ -10,12 +14,19 @@ namespace Flowsharp.Samples.Console.Programs { public class AdditionWorkflowProgram { + private readonly IWorkflowInvoker workflowInvoker; + private readonly IWorkflowSerializer serializer; + + public AdditionWorkflowProgram(IWorkflowInvoker workflowInvoker, IWorkflowSerializer serializer) + { + this.workflowInvoker = workflowInvoker; + this.serializer = serializer; + } + public async Task RunAsync(CancellationToken cancellationToken) { - var invoker = new WorkflowInvoker(new Logger(new NullLoggerFactory())); var workflow = new AdditionWorkflow(); - var workflowContext = await invoker.InvokeAsync(workflow, null, cancellationToken); - var serializer = new JsonWorkflowSerializer(); + var workflowContext = await workflowInvoker.InvokeAsync(workflow, null, cancellationToken); var json = await serializer.SerializeAsync(workflow, cancellationToken); System.Console.WriteLine(json); diff --git a/src/Flowsharp.Samples.Console/Programs/AdditionWorkflowProgramLongRunning.cs b/src/Flowsharp.Samples.Console/Programs/AdditionWorkflowProgramLongRunning.cs index 86e84c807..70c309b6c 100644 --- a/src/Flowsharp.Samples.Console/Programs/AdditionWorkflowProgramLongRunning.cs +++ b/src/Flowsharp.Samples.Console/Programs/AdditionWorkflowProgramLongRunning.cs @@ -2,7 +2,10 @@ using System.Threading; using System.Threading.Tasks; using Flowsharp.Activities; +using Flowsharp.Expressions; +using Flowsharp.Handlers; using Flowsharp.Models; +using Flowsharp.Samples.Console.Handlers; using Flowsharp.Samples.Console.Workflows; using Flowsharp.Serialization; using Flowsharp.Services; @@ -13,13 +16,13 @@ namespace Flowsharp.Samples.Console.Programs { public class AdditionWorkflowProgramLongRunning { - private readonly WorkflowInvoker workflowInvoker; + private readonly IWorkflowInvoker workflowInvoker; private readonly IWorkflowSerializer serializer; - public AdditionWorkflowProgramLongRunning() + public AdditionWorkflowProgramLongRunning(IWorkflowInvoker workflowInvoker, IWorkflowSerializer serializer) { - workflowInvoker = new WorkflowInvoker(new Logger(new NullLoggerFactory())); - serializer = new JsonWorkflowSerializer(); + this.workflowInvoker = workflowInvoker; + this.serializer = serializer; } public async Task RunAsync(CancellationToken cancellationToken) @@ -33,6 +36,9 @@ namespace Flowsharp.Samples.Console.Programs workflowContext = await ReadAndResumeAsync(workflowContext.Workflow, "y", cancellationToken); workflowContext = await ReadAndResumeAsync(workflowContext.Workflow, "tryAgain", cancellationToken); } + + var json = await serializer.SerializeAsync(workflowContext.Workflow, cancellationToken); + System.Console.WriteLine(json); } private async Task ReadAndResumeAsync(Workflow workflow, string argumentName, CancellationToken cancellationToken) diff --git a/src/Flowsharp.Samples.Console/Workflows/AdditionWorkflow.cs b/src/Flowsharp.Samples.Console/Workflows/AdditionWorkflow.cs index c1b26b442..b0c6c2ed6 100644 --- a/src/Flowsharp.Samples.Console/Workflows/AdditionWorkflow.cs +++ b/src/Flowsharp.Samples.Console/Workflows/AdditionWorkflow.cs @@ -1,8 +1,8 @@ using System; using Flowsharp.Activities; +using Flowsharp.Expressions; using Flowsharp.Models; using Flowsharp.Samples.Console.Activities; -using Flowsharp.Scripting; namespace Flowsharp.Samples.Console.Workflows { @@ -10,26 +10,24 @@ namespace Flowsharp.Samples.Console.Workflows { public AdditionWorkflow() { - var scriptEvaluator = new JintEvaluator(); var writeLine1 = new WriteLine("Welcome to Addition Workflow!"); var writeLine2 = new WriteLine("Let's run an interactive program."); var writeLine3 = new WriteLine("Enter first value:"); var readLine1 = new ReadLine(); - var setVariable1 = new SetVariable(scriptEvaluator){ VariableName = "x", ValueExpression = "workflow.getLastResult()"}; + var setVariable1 = new SetVariable{ VariableName = "x", ValueExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, "workflow.getLastResult()")}; var writeLine4 = new WriteLine("Enter second value:"); var readLine2 = new ReadLine(); - var setVariable2 = new SetVariable(scriptEvaluator){ VariableName = "y", ValueExpression = "workflow.getLastResult()"}; - var writeLine5 = new WriteLine((w, a) => - { - var x = w.CurrentScope.GetVariable("x"); - var y = w.CurrentScope.GetVariable("y"); - var z = x + y; - return $"{x} + {y} = {z}"; - }); + var setVariable2 = new SetVariable{ VariableName = "y", ValueExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, "workflow.getLastResult()")}; + var writeLine5 = new WriteLine {TextExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, + "var x = workflow.getVariable('x');\r\n" + + "var y = workflow.getVariable('y');\r\n" + + "var sum = parseInt(x) + parseInt(y);\r\n" + + "x + ' + ' + y + ' = ' + sum;" + )}; var writeLine6 = new WriteLine("Try again? (Y/N)"); var readLine3 = new ReadLine(); - var setVariable3 = new SetVariable(scriptEvaluator){ VariableName = "tryAgain", ValueExpression = "'y' === workflow.getLastResult().toLowerCase()"}; - var ifElse1 = new IfElse(scriptEvaluator){ ConditionExpression = "workflow.getVariable('tryAgain')"}; + var setVariable3 = new SetVariable{ VariableName = "tryAgain", ValueExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, "'y' === workflow.getLastResult().toLowerCase()")}; + var ifElse1 = new IfElse{ ConditionExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, "workflow.getVariable('tryAgain')")}; var writeLine7 = new WriteLine("Bye!"); Activities = new IActivity[] { writeLine1, writeLine2, writeLine3, writeLine4, writeLine5, writeLine6, readLine1, readLine2, readLine3, setVariable1, setVariable2, setVariable3, ifElse1 }; diff --git a/src/Flowsharp.Samples.Console/Workflows/AdditionWorkflowLongRunning.cs b/src/Flowsharp.Samples.Console/Workflows/AdditionWorkflowLongRunning.cs index 4c3c3ee74..56f13a879 100644 --- a/src/Flowsharp.Samples.Console/Workflows/AdditionWorkflowLongRunning.cs +++ b/src/Flowsharp.Samples.Console/Workflows/AdditionWorkflowLongRunning.cs @@ -1,8 +1,8 @@ using System; using Flowsharp.Activities; +using Flowsharp.Expressions; using Flowsharp.Models; using Flowsharp.Samples.Console.Activities; -using Flowsharp.Scripting; namespace Flowsharp.Samples.Console.Workflows { @@ -10,26 +10,24 @@ namespace Flowsharp.Samples.Console.Workflows { public AdditionWorkflowLongRunning() { - var scriptEvaluator = new JintEvaluator(); var writeLine1 = new WriteLine("Welcome to Addition Workflow - Long Running edition!"); var writeLine2 = new WriteLine("Let's run a long-running program."); var writeLine3 = new WriteLine("Enter first value:"); - var readLine1 = new ReadLine("x"); - var setVariable1 = new SetVariable(scriptEvaluator){ VariableName = "x", ValueExpression = "workflow.getLastResult()"}; + var readLine1 = new ReadLine { ArgumentName = "x"}; + var setVariable1 = new SetVariable{ VariableName = "x", ValueExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, "workflow.getLastResult()")}; var writeLine4 = new WriteLine("Enter second value:"); - var readLine2 = new ReadLine("y"); - var setVariable2 = new SetVariable(scriptEvaluator){ VariableName = "y", ValueExpression = "workflow.getLastResult()"}; - var writeLine5 = new WriteLine((w, a) => - { - var x = w.CurrentScope.GetVariable("x"); - var y = w.CurrentScope.GetVariable("y"); - var z = x + y; - return $"{x} + {y} = {z}"; - }); + var readLine2 = new ReadLine { ArgumentName = "y"}; + var setVariable2 = new SetVariable{ VariableName = "y", ValueExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, "workflow.getLastResult()")}; + var writeLine5 = new WriteLine {TextExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, + "var x = workflow.getVariable('x');\r\n" + + "var y = workflow.getVariable('y');\r\n" + + "var sum = parseInt(x) + parseInt(y);\r\n" + + "x + ' + ' + y + ' = ' + sum;" + )}; var writeLine6 = new WriteLine("Try again? (Y/N)"); - var readLine3 = new ReadLine("tryAgain"); - var setVariable3 = new SetVariable(scriptEvaluator){ VariableName = "tryAgain", ValueExpression = "'y' === workflow.getLastResult().toLowerCase()"}; - var ifElse1 = new IfElse(scriptEvaluator){ ConditionExpression = "workflow.getVariable('tryAgain')"}; + var readLine3 = new ReadLine { ArgumentName = "tryAgain"}; + var setVariable3 = new SetVariable{ VariableName = "tryAgain", ValueExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, "'y' === workflow.getLastResult().toLowerCase()")}; + var ifElse1 = new IfElse{ ConditionExpression = new WorkflowExpression(JavaScriptEvaluator.SyntaxName, "workflow.getVariable('tryAgain')")}; var writeLine7 = new WriteLine("Bye!"); Activities = new IActivity[] { writeLine1, writeLine2, writeLine3, writeLine4, writeLine5, writeLine6, readLine1, readLine2, readLine3, setVariable1, setVariable2, setVariable3, ifElse1 };