diff --git a/Flowsharp.sln b/Flowsharp.sln
index b6d2ff0f8..f97302418 100644
--- a/Flowsharp.sln
+++ b/Flowsharp.sln
@@ -16,10 +16,9 @@ ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
README.md = README.md
+ Nuget.Config = Nuget.Config
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flowsharp.Fluid", "src\Flowsharp.Fluid\Flowsharp.Fluid.csproj", "{B20D6AF5-91B1-4455-8541-22C5B31288D0}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -38,10 +37,6 @@ Global
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88}.Release|Any CPU.Build.0 = Release|Any CPU
- {B20D6AF5-91B1-4455-8541-22C5B31288D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B20D6AF5-91B1-4455-8541-22C5B31288D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B20D6AF5-91B1-4455-8541-22C5B31288D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B20D6AF5-91B1-4455-8541-22C5B31288D0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -53,6 +48,5 @@ Global
{300EE2D5-54C5-46F2-AD03-BB43589EA074} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{3B33AE9C-0465-4DA3-8C02-65E5766A7ED4} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
- {B20D6AF5-91B1-4455-8541-22C5B31288D0} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
EndGlobalSection
EndGlobal
diff --git a/Nuget.Config b/Nuget.Config
new file mode 100644
index 000000000..de3a3397c
--- /dev/null
+++ b/Nuget.Config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Activities/Activity.cs b/src/Flowsharp.Abstractions/Activities/Activity.cs
index 045cbc21a..205b10cae 100644
--- a/src/Flowsharp.Abstractions/Activities/Activity.cs
+++ b/src/Flowsharp.Abstractions/Activities/Activity.cs
@@ -1,26 +1,16 @@
using System.Collections.Generic;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flowsharp.ActivityResults;
using Flowsharp.Models;
-using Microsoft.Extensions.Localization;
namespace Flowsharp.Activities
{
public abstract class Activity : IActivity
{
- public virtual string Name => GetType().Name;
-
- public Task ProvideMetadataAsync(ActivityMetadataContext context, CancellationToken cancellationToken)
- {
- ProvideMetadata(context);
- return Task.CompletedTask;
- }
-
public virtual Task CanExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
{
- return Task.FromResult(true);
+ return Task.FromResult(CanExecute(workflowContext, activityContext));
}
public virtual Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
@@ -33,11 +23,6 @@ namespace Flowsharp.Activities
return Task.FromResult(Resume(workflowContext, activityContext));
}
- public virtual IEnumerable GetOutcomes(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
- {
- return Enumerable.Empty();
- }
-
public virtual Task OnActivityExecutedAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
{
OnActivityExecuted(workflowContext, activityContext);
@@ -80,20 +65,17 @@ namespace Flowsharp.Activities
return Task.CompletedTask;
}
- protected virtual void ProvideMetadata(ActivityMetadataContext context)
- {
- }
-
protected virtual ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
{
- return Noop();
+ return ActivateEndpoint();
}
protected virtual ActivityExecutionResult Resume(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
{
- return Noop();
+ 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) {}
@@ -102,32 +84,32 @@ namespace Flowsharp.Activities
protected virtual void WorkflowStarted(WorkflowExecutionContext workflowContext) {}
protected virtual void WorkflowStarting(WorkflowExecutionContext workflowContext) {}
- protected IEnumerable Outcomes(params LocalizedString[] names)
- {
- return names.Select(x => new Outcome(x));
- }
-
- protected IEnumerable Outcomes(IEnumerable names)
- {
- return names.Select(x => new Outcome(x));
- }
-
- protected ActivityExecutionResult Outcomes(params string[] names)
- {
- return Outcomes((IEnumerable)names);
- }
-
- protected ActivityExecutionResult Outcomes(IEnumerable names)
- {
- return new OutcomeResult(names);
- }
-
- protected ActivityExecutionResult Halt()
+ protected HaltResult Halt()
{
return new HaltResult();
}
- protected ActivityExecutionResult Noop()
+ 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.Abstractions/Activities/IActivity.cs b/src/Flowsharp.Abstractions/Activities/IActivity.cs
index f88645721..cb927c4a3 100644
--- a/src/Flowsharp.Abstractions/Activities/IActivity.cs
+++ b/src/Flowsharp.Abstractions/Activities/IActivity.cs
@@ -8,22 +8,6 @@ namespace Flowsharp.Activities
{
public interface IActivity
{
- ///
- /// The system name of the activity.
- ///
- /// The Name is used to identify a given activity type and must be unique.
- string Name { get; }
-
- ///
- /// Provides metadata about the specified activity.
- ///
- Task ProvideMetadataAsync(ActivityMetadataContext context, CancellationToken cancellationToken);
-
- ///
- /// Returns a list of possible outcomes when the activity is executed.
- ///
- IEnumerable GetOutcomes(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext);
-
///
/// Returns a value of whether the specified activity can execute.
///
diff --git a/src/Flowsharp.Abstractions/Activities/Workflow.cs b/src/Flowsharp.Abstractions/Activities/Workflow.cs
new file mode 100644
index 000000000..f37a2c27c
--- /dev/null
+++ b/src/Flowsharp.Abstractions/Activities/Workflow.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using System.Linq;
+using Flowsharp.ActivityResults;
+using Flowsharp.Models;
+
+namespace Flowsharp.Activities
+{
+ public class Workflow
+ {
+ public Workflow()
+ {
+ }
+
+ public Workflow(IEnumerable activities, IEnumerable connections)
+ {
+ Activities = activities.ToList();
+ Connections = connections.ToList();
+ }
+
+ public IList Activities { get; set; } = new List();
+ public IList Connections { get; set; } = new List();
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/ActivityProviders/TypedActivityProvider.cs b/src/Flowsharp.Abstractions/ActivityProviders/TypedActivityProvider.cs
deleted file mode 100644
index 152656c6b..000000000
--- a/src/Flowsharp.Abstractions/ActivityProviders/TypedActivityProvider.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Flowsharp.Activities;
-using Flowsharp.Descriptors;
-using Flowsharp.Services;
-
-namespace Flowsharp.ActivityProviders
-{
- ///
- /// Provides activities based on implementations that have been registered with the service container.
- ///
- public class TypedActivityProvider : IActivityProvider
- {
- private readonly Func> _activitiesFactory;
-
- public TypedActivityProvider(Func> activitiesFactory)
- {
- _activitiesFactory = activitiesFactory;
- }
-
- public Task> GetActivityDescriptorsAsync(CancellationToken cancellationToken)
- {
- return Task.FromResult(_activitiesFactory().Select(ToDescriptor));
- }
-
- private ActivityDescriptor ToDescriptor(IActivity activity)
- {
- return new ActivityDescriptor
- {
- Name = activity.Name,
- GetMetadataAsync = activity.ProvideMetadataAsync,
- CanExecuteAsync = activity.CanExecuteAsync,
- GetOutcomes = activity.GetOutcomes,
- ExecuteActivityAsync = activity.ExecuteAsync,
- ResumeActivityAsync = activity.ResumeAsync,
- ReceiveInputAsync = activity.ReceiveInputAsync,
- WorkflowResumedAsync = activity.WorkflowResumedAsync,
- WorkflowResumingAsync = activity.WorkflowResumingAsync,
- WorkflowStartedAsync = activity.WorkflowStartedAsync,
- WorkflowStartingAsync = activity.WorkflowStartingAsync,
- OnActivityExecutedAsync = activity.OnActivityExecutedAsync,
- OnActivityExecutingAsync = activity.OnActivityExecutingAsync
- };
- }
- }
-}
diff --git a/src/Flowsharp.Abstractions/ActivityResults/ActivateEndpointResult.cs b/src/Flowsharp.Abstractions/ActivityResults/ActivateEndpointResult.cs
new file mode 100644
index 000000000..9ddfbcade
--- /dev/null
+++ b/src/Flowsharp.Abstractions/ActivityResults/ActivateEndpointResult.cs
@@ -0,0 +1,22 @@
+using Flowsharp.Models;
+
+namespace Flowsharp.ActivityResults
+{
+ ///
+ /// A result that carries information about the next activity to execute.
+ ///
+ public class ActivateEndpointResult : ActivityExecutionResult
+ {
+ public ActivateEndpointResult(SourceEndpoint endpoint)
+ {
+ Endpoint = endpoint;
+ }
+
+ public SourceEndpoint Endpoint { get; }
+
+ protected override void Execute(WorkflowExecutionContext workflowContext)
+ {
+ workflowContext.ScheduleNextActivities(workflowContext, Endpoint);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/ActivityResults/FinishWorkflowResult.cs b/src/Flowsharp.Abstractions/ActivityResults/FinishWorkflowResult.cs
new file mode 100644
index 000000000..95fec5e70
--- /dev/null
+++ b/src/Flowsharp.Abstractions/ActivityResults/FinishWorkflowResult.cs
@@ -0,0 +1,12 @@
+using Flowsharp.Models;
+
+namespace Flowsharp.ActivityResults
+{
+ public class FinishWorkflowResult : ActivityExecutionResult
+ {
+ protected override void Execute(WorkflowExecutionContext workflowContext)
+ {
+ workflowContext.Finish();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/ActivityResults/HaltResult.cs b/src/Flowsharp.Abstractions/ActivityResults/HaltResult.cs
index 5a73e78f0..9b62aef97 100644
--- a/src/Flowsharp.Abstractions/ActivityResults/HaltResult.cs
+++ b/src/Flowsharp.Abstractions/ActivityResults/HaltResult.cs
@@ -11,20 +11,19 @@ namespace Flowsharp.ActivityResults
{
public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
{
- var currentActivity = workflowContext.CurrentExecutingActivity;
+ var currentActivity = workflowContext.CurrentActivity;
if (workflowContext.IsFirstPass)
{
// Resume immediately when this is the first pass.
- var result = await currentActivity.ActivityDescriptor.ResumeActivityAsync(workflowContext, currentActivity, cancellationToken);
+ var result = await currentActivity.ResumeAsync(workflowContext, new ActivityExecutionContext(currentActivity), cancellationToken);
workflowContext.IsFirstPass = false;
await result.ExecuteAsync(workflowContext, cancellationToken);
}
else
{
- // Block on this activity.
- workflowContext.BlockingActivities.Add(currentActivity);
+ await workflowContext.HaltAsync(cancellationToken);
}
}
}
diff --git a/src/Flowsharp.Abstractions/ActivityResults/OutcomeResult.cs b/src/Flowsharp.Abstractions/ActivityResults/OutcomeResult.cs
deleted file mode 100644
index c1f11050f..000000000
--- a/src/Flowsharp.Abstractions/ActivityResults/OutcomeResult.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Flowsharp.Models;
-
-namespace Flowsharp.ActivityResults
-{
- ///
- /// An activity execution result that sets the next outcomes to execute.
- ///
- public class OutcomeResult : ActivityExecutionResult
- {
- private readonly IEnumerable outcomeNames;
-
- public OutcomeResult(IEnumerable names)
- {
- outcomeNames = names.ToList();
- }
-
- protected override void Execute(WorkflowExecutionContext workflowContext)
- {
- var workflowType = workflowContext.WorkflowType;
- var currentActivity = workflowContext.CurrentExecutingActivity;
-
- foreach (var outcome in outcomeNames)
- {
- // Look for next activity in the graph.
- var transition = workflowType.Transitions.FirstOrDefault(x => x.From.ActivityId == currentActivity.ActivityType.Id && x.From.OutcomeName == outcome);
-
- if (transition != null)
- {
- var destinationActivity = workflowContext.Activities.Values.Single(x => x.ActivityType.Id == transition.To.ActivityId);
- workflowContext.PushScheduledActivity(destinationActivity);
- }
- }
- }
- }
-}
diff --git a/src/Flowsharp.Abstractions/ActivityResults/ReturnValueResult.cs b/src/Flowsharp.Abstractions/ActivityResults/ReturnValueResult.cs
new file mode 100644
index 000000000..a2d28e49f
--- /dev/null
+++ b/src/Flowsharp.Abstractions/ActivityResults/ReturnValueResult.cs
@@ -0,0 +1,19 @@
+using Flowsharp.Models;
+
+namespace Flowsharp.ActivityResults
+{
+ public class ReturnValueResult : ActivityExecutionResult
+ {
+ private readonly object value;
+
+ public ReturnValueResult(object value)
+ {
+ this.value = value;
+ }
+
+ protected override void Execute(WorkflowExecutionContext workflowContext)
+ {
+ workflowContext.SetReturnValue(value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/ActivityResults/ScheduleActivityResult.cs b/src/Flowsharp.Abstractions/ActivityResults/ScheduleActivityResult.cs
new file mode 100644
index 000000000..23a7a2ea6
--- /dev/null
+++ b/src/Flowsharp.Abstractions/ActivityResults/ScheduleActivityResult.cs
@@ -0,0 +1,20 @@
+using Flowsharp.Activities;
+using Flowsharp.Models;
+
+namespace Flowsharp.ActivityResults
+{
+ public class ScheduleActivityResult : ActivityExecutionResult
+ {
+ private readonly IActivity activity;
+
+ public ScheduleActivityResult(IActivity activity)
+ {
+ this.activity = activity;
+ }
+
+ protected override void Execute(WorkflowExecutionContext workflowContext)
+ {
+ workflowContext.ScheduleActivity(activity);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Builders/ActivityWorkflowBuilder.cs b/src/Flowsharp.Abstractions/Builders/ActivityWorkflowBuilder.cs
new file mode 100644
index 000000000..10f175f24
--- /dev/null
+++ b/src/Flowsharp.Abstractions/Builders/ActivityWorkflowBuilder.cs
@@ -0,0 +1,28 @@
+using System;
+using Flowsharp.Activities;
+using Flowsharp.Models;
+
+namespace Flowsharp.Builders
+{
+ public class ActivityWorkflowBuilder
+ {
+ private readonly IActivity activity;
+ private readonly WorkflowBuilder builder;
+
+ public ActivityWorkflowBuilder(WorkflowBuilder builder, IActivity activity)
+ {
+ this.builder = builder;
+ this.activity = activity;
+ }
+
+ public ActivityWorkflowBuilder Connect(IActivity target, Action activityBuilder = null)
+ {
+ var connection = new Connection(activity, target);
+ builder.Activities.Add(target);
+ builder.Connections.Add(connection);
+
+ activityBuilder?.Invoke(new ActivityWorkflowBuilder(builder, target));
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Builders/WorkflowBuilder.cs b/src/Flowsharp.Abstractions/Builders/WorkflowBuilder.cs
new file mode 100644
index 000000000..410f85de4
--- /dev/null
+++ b/src/Flowsharp.Abstractions/Builders/WorkflowBuilder.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Flowsharp.Activities;
+using Flowsharp.Models;
+
+namespace Flowsharp.Builders
+{
+ public class WorkflowBuilder
+ {
+ public WorkflowBuilder()
+ {
+ Activities = new List();
+ Connections = new List();
+ }
+
+ public IList Activities { get; }
+ public IList Connections { get; }
+
+ public WorkflowBuilder AddActivity(IActivity activity, Action builder = null)
+ {
+ Activities.Add(activity);
+ builder?.Invoke(new ActivityWorkflowBuilder(this, activity));
+ return this;
+ }
+
+ public Workflow Build()
+ {
+ return new Workflow(Activities, Connections);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Descriptors/ActivityDescriptor.cs b/src/Flowsharp.Abstractions/Descriptors/ActivityDescriptor.cs
deleted file mode 100644
index 2d2c62428..000000000
--- a/src/Flowsharp.Abstractions/Descriptors/ActivityDescriptor.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Flowsharp.ActivityResults;
-using Flowsharp.Models;
-
-namespace Flowsharp.Descriptors
-{
- public class ActivityDescriptor
- {
- public string Name { get; set; }
-
- ///
- /// Provides metadata about the specified activity.
- ///
- public Func GetMetadataAsync { get; set; }
-
- ///
- /// Returns a list of possible outcomes when the activity is executed.
- ///
- public Func> GetOutcomes { get; set; }
-
- ///
- /// Returns a value of whether the specified activity can execute.
- ///
- public Func> CanExecuteAsync { get; set; }
-
- ///
- /// Executes the specified activity.
- ///
- public Func> ExecuteActivityAsync { get; set; }
-
- ///
- /// Resumes the specified activity.
- ///
- public Func> ResumeActivityAsync { get; set; }
-
- ///
- /// Executes before a workflow starts or resumes, giving activities an opportunity to read and store any values of interest.
- ///
- public Func, CancellationToken, Task> ReceiveInputAsync { get; set; }
-
- ///
- /// Executes when a workflow is about to start.
- ///
- public Func WorkflowStartingAsync { get; set; }
-
- ///
- /// Executes when a workflow has started.
- ///
- public Func WorkflowStartedAsync { get; set; }
-
- ///
- /// Executes when a workflow is about to be resumed.
- ///
- public Func WorkflowResumingAsync { get; set; }
-
- ///
- /// Executes when a workflow is resumed.
- ///
- public Func WorkflowResumedAsync { get; set; }
-
- ///
- /// Executes when an activity is about to be executed.
- ///
- /// The activity for which the event is invoked. This is not necessarily the activity that is about to be executed.
- /// The activity context containing the activity that is the subject of the event.
- public Func OnActivityExecutingAsync { get; set; }
-
- ///
- /// Called on each activity when an activity has been executed.
- ///
- /// The activity for which the event is invoked. This is not necessarily the activity that is about to be executed.
- /// The activity context containing the activity that is the subject of the event.
- public Func OnActivityExecutedAsync { get; set; }
- }
-}
diff --git a/src/Flowsharp.Abstractions/Extensions/ConnectionActivityExtensions.cs b/src/Flowsharp.Abstractions/Extensions/ConnectionActivityExtensions.cs
new file mode 100644
index 000000000..70db38456
--- /dev/null
+++ b/src/Flowsharp.Abstractions/Extensions/ConnectionActivityExtensions.cs
@@ -0,0 +1,9 @@
+using Flowsharp.Activities;
+using Flowsharp.Models;
+
+namespace Flowsharp.Extensions
+{
+ public static class ConnectionActivityExtensions
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Extensions/InvokeExtensions.cs b/src/Flowsharp.Abstractions/Extensions/InvokeExtensions.cs
index 38ed6091c..9fc0a08dd 100644
--- a/src/Flowsharp.Abstractions/Extensions/InvokeExtensions.cs
+++ b/src/Flowsharp.Abstractions/Extensions/InvokeExtensions.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Flowsharp.Activities;
using Microsoft.Extensions.Logging;
namespace Flowsharp.Extensions
@@ -10,7 +11,7 @@ namespace Flowsharp.Extensions
///
/// Safely invoke methods by catching non fatal exceptions and logging them.
///
- public static void Invoke(this IEnumerable events, Action dispatch, ILogger logger)
+ public static void Invoke(this IEnumerable events, Action dispatch, ILogger logger)
{
foreach (var sink in events)
{
@@ -20,7 +21,7 @@ namespace Flowsharp.Extensions
}
catch (Exception ex)
{
- HandleException(ex, logger, typeof(TEvents).Name, sink.GetType().FullName);
+ HandleException(ex, logger, typeof(T).Name, sink.GetType().FullName);
}
}
}
@@ -28,7 +29,7 @@ namespace Flowsharp.Extensions
///
/// Safely invoke methods by catching non fatal exceptions and logging them.
///
- public static async Task InvokeAsync(this IEnumerable events, Func dispatch, ILogger logger)
+ public static async Task InvokeAsync(this IEnumerable events, Func dispatch, ILogger logger)
{
foreach (var sink in events)
{
@@ -38,12 +39,12 @@ namespace Flowsharp.Extensions
}
catch (Exception ex)
{
- HandleException(ex, logger, typeof(TEvents).Name, sink.GetType().FullName);
+ HandleException(ex, logger, typeof(T).Name, sink.GetType().FullName);
}
}
}
- public static void HandleException(Exception ex, ILogger logger, string sourceType, string method)
+ private static void HandleException(Exception ex, ILogger logger, string sourceType, string method)
{
if (ex.IsFatal())
throw ex;
diff --git a/src/Flowsharp.Abstractions/Flowsharp.Abstractions.csproj b/src/Flowsharp.Abstractions/Flowsharp.Abstractions.csproj
index d7714b834..19ed3f430 100644
--- a/src/Flowsharp.Abstractions/Flowsharp.Abstractions.csproj
+++ b/src/Flowsharp.Abstractions/Flowsharp.Abstractions.csproj
@@ -3,6 +3,7 @@
netstandard2.0
Flowsharp
+ 7.1
diff --git a/src/Flowsharp.Abstractions/Models/ActivityExecutionContext.cs b/src/Flowsharp.Abstractions/Models/ActivityExecutionContext.cs
index 9f1461f46..960e66f8b 100644
--- a/src/Flowsharp.Abstractions/Models/ActivityExecutionContext.cs
+++ b/src/Flowsharp.Abstractions/Models/ActivityExecutionContext.cs
@@ -1,19 +1,14 @@
-using Flowsharp.Descriptors;
-using Newtonsoft.Json.Linq;
+using Flowsharp.Activities;
namespace Flowsharp.Models
{
public class ActivityExecutionContext
{
- public ActivityExecutionContext(ActivityType activityType, ActivityDescriptor activityDescriptor)
+ public ActivityExecutionContext(IActivity activity)
{
- ActivityType = activityType;
- ActivityDescriptor = activityDescriptor;
- State = new JObject(activityType.State);
+ Activity = activity;
}
- public ActivityType ActivityType { get; }
- public ActivityDescriptor ActivityDescriptor { get; }
- public JObject State { get; set; }
+ public IActivity Activity { get; private set; }
}
}
diff --git a/src/Flowsharp.Abstractions/Models/ActivityMetadata.cs b/src/Flowsharp.Abstractions/Models/ActivityMetadata.cs
deleted file mode 100644
index a4f9542ab..000000000
--- a/src/Flowsharp.Abstractions/Models/ActivityMetadata.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using Microsoft.Extensions.Localization;
-
-namespace Flowsharp.Abstractions.Models
-{
- public class ActivityMetadata
- {
- public LocalizedString DisplayName { get; set; }
- public LocalizedString Category { get; set; }
- }
-}
diff --git a/src/Flowsharp.Abstractions/Models/ActivityMetadataContext.cs b/src/Flowsharp.Abstractions/Models/ActivityMetadataContext.cs
deleted file mode 100644
index ae4c60bf3..000000000
--- a/src/Flowsharp.Abstractions/Models/ActivityMetadataContext.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Flowsharp.Abstractions.Models;
-
-namespace Flowsharp.Models
-{
- public class ActivityMetadataContext
- {
- public ActivityMetadata Metadata { get; set; }
- }
-}
diff --git a/src/Flowsharp.Abstractions/Models/ActivityType.cs b/src/Flowsharp.Abstractions/Models/ActivityType.cs
deleted file mode 100644
index ad359611e..000000000
--- a/src/Flowsharp.Abstractions/Models/ActivityType.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Newtonsoft.Json.Linq;
-
-namespace Flowsharp.Models
-{
- public class ActivityType
- {
- public ActivityType(string id, string name, JObject state = null)
- {
- Id = id;
- Name = name;
- State = state ?? new JObject();
- }
-
- public string Id { get; }
- public string Name { get; }
- public JObject State { get; }
- }
-}
diff --git a/src/Flowsharp.Abstractions/Models/Connection.cs b/src/Flowsharp.Abstractions/Models/Connection.cs
new file mode 100644
index 000000000..6b6f414c4
--- /dev/null
+++ b/src/Flowsharp.Abstractions/Models/Connection.cs
@@ -0,0 +1,28 @@
+using Flowsharp.Activities;
+
+namespace Flowsharp.Models
+{
+ public class Connection
+ {
+ public Connection()
+ {
+ }
+
+ public Connection(IActivity source, IActivity target) : this(new SourceEndpoint(source), new TargetEndpoint(target))
+ {
+ }
+
+ public Connection(IActivity source, string sourceEndpointName, IActivity target) : this(new SourceEndpoint(source, sourceEndpointName), new TargetEndpoint(target))
+ {
+ }
+
+ public Connection(SourceEndpoint source, TargetEndpoint target)
+ {
+ Source = source;
+ Target = target;
+ }
+
+ public SourceEndpoint Source { get; set; }
+ public TargetEndpoint Target { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Models/DestinationEndpoint.cs b/src/Flowsharp.Abstractions/Models/DestinationEndpoint.cs
deleted file mode 100644
index be332d605..000000000
--- a/src/Flowsharp.Abstractions/Models/DestinationEndpoint.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Flowsharp.Models
-{
- public class DestinationEndpoint : Endpoint
- {
- }
-}
diff --git a/src/Flowsharp.Abstractions/Models/Endpoint.cs b/src/Flowsharp.Abstractions/Models/Endpoint.cs
index 96daadac6..5a10b2369 100644
--- a/src/Flowsharp.Abstractions/Models/Endpoint.cs
+++ b/src/Flowsharp.Abstractions/Models/Endpoint.cs
@@ -1,7 +1,18 @@
-namespace Flowsharp.Models
+using Flowsharp.Activities;
+
+namespace Flowsharp.Models
{
- public class Endpoint
+ public abstract class Endpoint
{
- public string ActivityId { get; set; }
+ protected Endpoint()
+ {
+ }
+
+ protected Endpoint(IActivity activity)
+ {
+ Activity = activity;
+ }
+
+ public IActivity Activity { get; set; }
}
-}
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Models/Outcome.cs b/src/Flowsharp.Abstractions/Models/Outcome.cs
deleted file mode 100644
index c3b7c9c78..000000000
--- a/src/Flowsharp.Abstractions/Models/Outcome.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using Flowsharp.Json;
-using Microsoft.Extensions.Localization;
-using Newtonsoft.Json;
-
-namespace Flowsharp.Models
-{
- public class Outcome
- {
- public Outcome(LocalizedString displayName) : this(displayName.Name, displayName)
- {
- }
-
- public Outcome(string name, LocalizedString displayName)
- {
- Name = name;
- DisplayName = displayName;
- }
-
- public string Name { get; }
-
- [JsonConverter(typeof(LocalizedStringConverter))]
- public LocalizedString DisplayName { get; }
- }
-}
diff --git a/src/Flowsharp.Abstractions/Models/SourceEndpoint.cs b/src/Flowsharp.Abstractions/Models/SourceEndpoint.cs
index 164d05524..378aa0180 100644
--- a/src/Flowsharp.Abstractions/Models/SourceEndpoint.cs
+++ b/src/Flowsharp.Abstractions/Models/SourceEndpoint.cs
@@ -1,7 +1,18 @@
-namespace Flowsharp.Models
+using Flowsharp.Activities;
+
+namespace Flowsharp.Models
{
public class SourceEndpoint : Endpoint
{
- public string OutcomeName { get; set; }
+ public SourceEndpoint()
+ {
+ }
+
+ public SourceEndpoint(IActivity activity, string name = null) : base(activity)
+ {
+ Name = name;
+ }
+
+ public string Name { get; set; }
}
-}
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Models/TargetEndpoint.cs b/src/Flowsharp.Abstractions/Models/TargetEndpoint.cs
new file mode 100644
index 000000000..593f4b355
--- /dev/null
+++ b/src/Flowsharp.Abstractions/Models/TargetEndpoint.cs
@@ -0,0 +1,15 @@
+using Flowsharp.Activities;
+
+namespace Flowsharp.Models
+{
+ public class TargetEndpoint : Endpoint
+ {
+ public TargetEndpoint()
+ {
+ }
+
+ public TargetEndpoint(IActivity activity) : base(activity)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Models/Transition.cs b/src/Flowsharp.Abstractions/Models/Transition.cs
deleted file mode 100644
index e99d8abe6..000000000
--- a/src/Flowsharp.Abstractions/Models/Transition.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Flowsharp.Models
-{
- public class Transition
- {
- public SourceEndpoint From { get; set; }
- public DestinationEndpoint To { get; set; }
- }
-}
diff --git a/src/Flowsharp.Abstractions/Models/WorkflowExecutionContext.cs b/src/Flowsharp.Abstractions/Models/WorkflowExecutionContext.cs
index e610255ef..040af39bb 100644
--- a/src/Flowsharp.Abstractions/Models/WorkflowExecutionContext.cs
+++ b/src/Flowsharp.Abstractions/Models/WorkflowExecutionContext.cs
@@ -1,46 +1,87 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
-using Flowsharp.Descriptors;
+using System.Threading;
+using System.Threading.Tasks;
+using Flowsharp.Activities;
namespace Flowsharp.Models
{
public class WorkflowExecutionContext
{
- public WorkflowExecutionContext(IDictionary activityDescriptorDictionary, WorkflowType workflowType, WorkflowStatus status)
+ public WorkflowExecutionContext(Workflow workflow, WorkflowStatus status = WorkflowStatus.Idle)
{
- WorkflowType = workflowType;
- Activities = workflowType.Activities.ToDictionary(x => x.Id, x => new ActivityExecutionContext(x, activityDescriptorDictionary[x.Name]));
- BlockingActivities = new List();
+ Workflow = workflow;
Status = status;
- IsFirstPass = true;
+ IsFirstPass = true;
+ scheduledActivities = new Stack();
+ scopes = new Stack();
- scheduledActivities = new Stack();
+ BeginScope();
}
- private readonly Stack scheduledActivities;
+ private readonly Stack scheduledActivities;
+ private readonly Stack scopes;
- public WorkflowType WorkflowType { get; }
- public IDictionary Activities { get; }
- public ICollection BlockingActivities { get; }
+ public Workflow Workflow { get; }
public WorkflowStatus Status { get; set; }
public bool HasScheduledActivities => scheduledActivities.Any();
public bool IsFirstPass { get; set; }
- public ActivityExecutionContext CurrentExecutingActivity { get; private set; }
+ public IActivity CurrentActivity { get; private set; }
+ public WorkflowExecutionScope CurrentScope { get; private set; }
- public void PushScheduledActivity(ActivityExecutionContext activityExecutionContext)
+ public void BeginScope()
+ {
+ scopes.Push(CurrentScope = new WorkflowExecutionScope());
+ }
+
+ public void EndScope()
{
- scheduledActivities.Push(activityExecutionContext);
+ scopes.Pop();
+ CurrentScope = scopes.Peek();
+ }
+
+ public void ScheduleActivity(IActivity activity)
+ {
+ scheduledActivities.Push(activity);
}
- public ActivityExecutionContext PopScheduledActivity()
+ public IActivity PopScheduledActivity()
{
- return CurrentExecutingActivity = scheduledActivities.Pop();
+ CurrentActivity = scheduledActivities.Pop();
+ return CurrentActivity;
+ }
+
+ public void SetReturnValue(object value)
+ {
+ CurrentScope.ReturnValue = value;
}
- public void Fault(Exception exception, ActivityExecutionContext activity)
+ public void Fault(Exception exception, IActivity activity)
{
throw new NotImplementedException();
}
+
+ public Task HaltAsync(CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Finish()
+ {
+ Status = WorkflowStatus.Finished;
+ }
+
+ public virtual 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);
+
+ foreach (var connection in connections)
+ {
+ workflowContext.ScheduleActivity(connection.Target.Activity);
+ }
+ }
}
}
diff --git a/src/Flowsharp.Abstractions/Models/WorkflowExecutionScope.cs b/src/Flowsharp.Abstractions/Models/WorkflowExecutionScope.cs
new file mode 100644
index 000000000..7c505981e
--- /dev/null
+++ b/src/Flowsharp.Abstractions/Models/WorkflowExecutionScope.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+
+namespace Flowsharp.Models
+{
+ public class WorkflowExecutionScope
+ {
+ public WorkflowExecutionScope()
+ {
+ Variables = new Dictionary();
+ }
+
+ public object ReturnValue { get; set; }
+ public IDictionary Variables { get; }
+
+ public void SetVariable(string variableName, object value)
+ {
+ Variables[variableName] = value;
+ }
+
+ public T GetVariable(string name)
+ {
+ return Variables.ContainsKey(name) ? (T)Variables[name] : default(T);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Models/WorkflowType.cs b/src/Flowsharp.Abstractions/Models/WorkflowType.cs
deleted file mode 100644
index b268e1695..000000000
--- a/src/Flowsharp.Abstractions/Models/WorkflowType.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Collections.Generic;
-
-namespace Flowsharp.Models
-{
- public class WorkflowType
- {
- public string Name { get; set; }
- public ICollection Activities { get; set; }
- public ICollection Transitions { get; set; }
- }
-}
diff --git a/src/Flowsharp.Abstractions/Serialization/IWorkflowSerializer.cs b/src/Flowsharp.Abstractions/Serialization/IWorkflowSerializer.cs
new file mode 100644
index 000000000..8d26a01dc
--- /dev/null
+++ b/src/Flowsharp.Abstractions/Serialization/IWorkflowSerializer.cs
@@ -0,0 +1,11 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Flowsharp.Activities;
+
+namespace Flowsharp.Services
+{
+ public interface IWorkflowSerializer
+ {
+ Task SerializeAsync(Workflow workflow, CancellationToken cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Abstractions/Services/IActivityLibrary.cs b/src/Flowsharp.Abstractions/Services/IActivityLibrary.cs
deleted file mode 100644
index f6d85dea7..000000000
--- a/src/Flowsharp.Abstractions/Services/IActivityLibrary.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Flowsharp.Descriptors;
-
-namespace Flowsharp.Services
-{
- public interface IActivityLibrary
- {
- Task> GetActivityDescriptorsAsync(CancellationToken cancellationToken);
- }
-}
diff --git a/src/Flowsharp.Abstractions/Services/IActivityProvider.cs b/src/Flowsharp.Abstractions/Services/IActivityProvider.cs
deleted file mode 100644
index 4c2e59831..000000000
--- a/src/Flowsharp.Abstractions/Services/IActivityProvider.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Flowsharp.Descriptors;
-
-namespace Flowsharp.Services
-{
- ///
- /// Implementors provide available activity descriptors.
- ///
- public interface IActivityProvider
- {
- Task> GetActivityDescriptorsAsync(CancellationToken cancellationToken);
- }
-}
diff --git a/src/Flowsharp.Abstractions/Services/IWorkflowInvoker.cs b/src/Flowsharp.Abstractions/Services/IWorkflowInvoker.cs
index 444cdaf46..f24c522a1 100644
--- a/src/Flowsharp.Abstractions/Services/IWorkflowInvoker.cs
+++ b/src/Flowsharp.Abstractions/Services/IWorkflowInvoker.cs
@@ -1,11 +1,12 @@
using System.Threading;
using System.Threading.Tasks;
+using Flowsharp.Activities;
using Flowsharp.Models;
namespace Flowsharp.Services
{
public interface IWorkflowInvoker
{
- Task InvokeAsync(WorkflowExecutionContext workflowContext, string startActivityId, CancellationToken cancellationToken);
+ Task InvokeAsync(Workflow workflow, IActivity startActivity = default, CancellationToken cancellationToken = default);
}
}
diff --git a/src/Flowsharp.Core/Activities/IfElse.cs b/src/Flowsharp.Core/Activities/IfElse.cs
new file mode 100644
index 000000000..cdedcdbb9
--- /dev/null
+++ b/src/Flowsharp.Core/Activities/IfElse.cs
@@ -0,0 +1,37 @@
+using System;
+using Flowsharp.ActivityResults;
+using Flowsharp.Models;
+
+namespace Flowsharp.Activities
+{
+ public class IfElse : Activity
+ {
+ private readonly Func condition;
+
+ public IfElse()
+ {
+ }
+
+ public IfElse(Func condition, IActivity trueBranch, IActivity falseBranch)
+ {
+ this.condition = condition;
+ TrueBranch = trueBranch;
+ FalseBranch = falseBranch;
+ }
+
+ public IActivity TrueBranch { get; set; }
+ public IActivity FalseBranch { get; set;}
+
+ protected override ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
+ {
+ var result = condition(workflowContext, activityContext);
+ if (TrueBranch != null && result)
+ return ScheduleActivity(TrueBranch);
+
+ if(FalseBranch != null && !result)
+ return ScheduleActivity(FalseBranch);
+
+ return Noop();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Core/Activities/ReadLine.cs b/src/Flowsharp.Core/Activities/ReadLine.cs
new file mode 100644
index 000000000..620e75514
--- /dev/null
+++ b/src/Flowsharp.Core/Activities/ReadLine.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Flowsharp.ActivityResults;
+using Flowsharp.Models;
+
+namespace Flowsharp.Activities
+{
+ public class ReadLine : Activity
+ {
+ private readonly TextReader input;
+
+ public ReadLine() : this(Console.In)
+ {
+ }
+
+ public ReadLine(TextReader input)
+ {
+ this.input = input;
+ }
+
+ public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
+ {
+ var value = await input.ReadLineAsync();
+ workflowContext.SetReturnValue(value);
+ return ActivateEndpoint();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Core/Activities/SetVariable.cs b/src/Flowsharp.Core/Activities/SetVariable.cs
new file mode 100644
index 000000000..670f5b460
--- /dev/null
+++ b/src/Flowsharp.Core/Activities/SetVariable.cs
@@ -0,0 +1,37 @@
+using System;
+using Flowsharp.ActivityResults;
+using Flowsharp.Models;
+
+namespace Flowsharp.Activities
+{
+ public class SetVariable : Activity
+ {
+ private readonly Func valueProvider;
+
+ public SetVariable()
+ {
+ }
+
+ public SetVariable(string name, Func valueProvider) : this(name, default(object))
+ {
+ VariableName = name;
+ this.valueProvider = valueProvider;
+ }
+
+ public SetVariable(string name, object value)
+ {
+ VariableName = name;
+ Value = value;
+ }
+
+ public string VariableName { get; set; }
+ public object Value { get; set; }
+
+ protected override ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
+ {
+ var value = valueProvider(workflowContext, activityContext);
+ workflowContext.CurrentScope.SetVariable(VariableName, value);
+ return ActivateEndpoint();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Core/Activities/WriteLine.cs b/src/Flowsharp.Core/Activities/WriteLine.cs
index 081d5b647..ed5e7fb59 100644
--- a/src/Flowsharp.Core/Activities/WriteLine.cs
+++ b/src/Flowsharp.Core/Activities/WriteLine.cs
@@ -1,19 +1,54 @@
using System;
-using Flowsharp.Activities;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
using Flowsharp.ActivityResults;
using Flowsharp.Models;
-namespace Flowsharp.ActivityProviders
+namespace Flowsharp.Activities
{
///
- /// Provides activities based on implementations that have been registered with the service container.
+ /// Writes a text string to the specified stream.
///
public class WriteLine : Activity
{
- protected override ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
+ private readonly TextWriter output;
+ private readonly Func textProvider;
+
+ public WriteLine() : this(Console.Out, null)
{
- Console.WriteLine("Hello World!");
- return Outcomes("Done");
+ }
+
+ public WriteLine(string text) : this(Console.Out, text)
+ {
+ }
+
+ public WriteLine(Func textProvider) : this(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();
}
}
}
diff --git a/src/Flowsharp.Core/Flowsharp.Core.csproj b/src/Flowsharp.Core/Flowsharp.Core.csproj
index c7919e206..5a0e596aa 100644
--- a/src/Flowsharp.Core/Flowsharp.Core.csproj
+++ b/src/Flowsharp.Core/Flowsharp.Core.csproj
@@ -3,6 +3,7 @@
netstandard2.0
Flowsharp
+ 7.1
@@ -14,4 +15,8 @@
+
+
+
+
diff --git a/src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs b/src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs
new file mode 100644
index 000000000..02db3c014
--- /dev/null
+++ b/src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs
@@ -0,0 +1,22 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Flowsharp.Activities;
+using Flowsharp.Services;
+using Newtonsoft.Json;
+
+namespace Flowsharp.Serialization
+{
+ public class JsonWorkflowSerializer : IWorkflowSerializer
+ {
+ public Task SerializeAsync(Workflow workflow, CancellationToken cancellationToken)
+ {
+ var settings = new JsonSerializerSettings
+ {
+ PreserveReferencesHandling = PreserveReferencesHandling.Objects,
+ TypeNameHandling = TypeNameHandling.Objects
+ };
+ var json = JsonConvert.SerializeObject(workflow, settings);
+ return Task.FromResult(json);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Flowsharp.Core/Services/ActivityLibrary.cs b/src/Flowsharp.Core/Services/ActivityLibrary.cs
deleted file mode 100644
index 227b37952..000000000
--- a/src/Flowsharp.Core/Services/ActivityLibrary.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Flowsharp.Descriptors;
-
-namespace Flowsharp.Services
-{
- public class ActivityLibrary : IActivityLibrary
- {
- private readonly IEnumerable providers;
-
- public ActivityLibrary(IEnumerable providers)
- {
- this.providers = providers;
- }
-
- public async Task> GetActivityDescriptorsAsync(CancellationToken cancellationToken)
- {
- var tasks = providers.Select(x => x.GetActivityDescriptorsAsync(cancellationToken)).ToList();
- var results = await Task.WhenAll(tasks);
-
- return results.SelectMany(x => x);
- }
- }
-
- public static class ActivityLibraryExtensions
- {
- public static async Task> GetActivityDescriptorDictionaryAsync(this IActivityLibrary activityLibrary, CancellationToken cancellationToken)
- {
- var activityDescriptors = await activityLibrary.GetActivityDescriptorsAsync(cancellationToken);
- return activityDescriptors.ToDictionary(x => x.Name);
- }
- }
-}
diff --git a/src/Flowsharp.Core/Services/WorkflowInvoker.cs b/src/Flowsharp.Core/Services/WorkflowInvoker.cs
index 6447c1bb1..1ed478cbb 100644
--- a/src/Flowsharp.Core/Services/WorkflowInvoker.cs
+++ b/src/Flowsharp.Core/Services/WorkflowInvoker.cs
@@ -1,7 +1,9 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Flowsharp.Activities;
using Flowsharp.ActivityResults;
using Flowsharp.Extensions;
using Flowsharp.Models;
@@ -18,82 +20,87 @@ namespace Flowsharp.Services
private readonly ILogger logger;
- public async Task InvokeAsync(WorkflowExecutionContext workflowContext, string startActivityId, CancellationToken cancellationToken)
+ public async Task InvokeAsync(Workflow workflow, IActivity startActivity = default, CancellationToken cancellationToken = default)
{
- var isResuming = workflowContext.Status == WorkflowStatus.Resuming;
- var startActivity = workflowContext.Activities[startActivityId];
+ var workflowExecutionContext = new WorkflowExecutionContext(workflow);
+ var isResuming = workflowExecutionContext.Status == WorkflowStatus.Resuming;
- workflowContext.Status = WorkflowStatus.Executing;
- workflowContext.PushScheduledActivity(startActivity);
-
- while (workflowContext.HasScheduledActivities)
+ if (startActivity == null)
+ startActivity = workflow.Activities.First();
+
+ workflowExecutionContext.Status = WorkflowStatus.Executing;
+ workflowExecutionContext.ScheduleActivity(startActivity);
+ await InvokeActivitiesAsync(workflowExecutionContext, x => x.WorkflowStartingAsync(workflowExecutionContext, cancellationToken));
+
+ while (workflowExecutionContext.HasScheduledActivities)
{
- var currentActivity = workflowContext.PopScheduledActivity();
+ var currentActivity = workflowExecutionContext.PopScheduledActivity();
+ var result = await ExecuteActivityAsync(workflowExecutionContext, currentActivity, isResuming, cancellationToken);
- if (!await ExecuteActivityAsync(workflowContext, currentActivity, isResuming, cancellationToken))
+ if(result == null)
break;
+
+ await result.ExecuteAsync(workflowExecutionContext, cancellationToken);
- workflowContext.IsFirstPass = false;
+ workflowExecutionContext.IsFirstPass = false;
isResuming = false;
}
- workflowContext.Status = workflowContext.BlockingActivities.Any() ? WorkflowStatus.Halted : WorkflowStatus.Finished;
+ workflowExecutionContext.Status = WorkflowStatus.Finished;
+
+ return workflowExecutionContext;
}
- private async Task ExecuteActivityAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, bool isResuming, CancellationToken cancellationToken)
+ private async Task ExecuteActivityAsync(WorkflowExecutionContext workflowContext, IActivity activity, bool isResuming, CancellationToken cancellationToken)
{
try
{
- await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutingAsync(workflowContext, activityContext, cancellationToken));
+ //await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutingAsync(workflowContext, activity, cancellationToken));
if (cancellationToken.IsCancellationRequested)
{
workflowContext.Status = WorkflowStatus.Aborted;
- return false;
+ return null;
}
- var result = await ExecuteOrResumeActivityAsync(workflowContext, activityContext, isResuming, cancellationToken);
- await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutedAsync(workflowContext, activityContext, cancellationToken));
- await result.ExecuteAsync(workflowContext, cancellationToken);
+ return await ExecuteOrResumeActivityAsync(workflowContext, activity, isResuming, cancellationToken);
+ //await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutedAsync(workflowContext, activity, cancellationToken));
}
catch (Exception ex)
{
- FaultWorkflow(workflowContext, activityContext, ex);
+ FaultWorkflow(workflowContext, activity, ex);
}
- return true;
+ return null;
}
- private void FaultWorkflow(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, Exception ex)
+ private void FaultWorkflow(WorkflowExecutionContext workflowContext, IActivity activity, Exception ex)
{
logger.LogError(
ex,
- "An unhandled error occurred while executing an activity. Workflow ID: '{WorkflowTypeId}'. Activity: '{ActivityId}', '{ActivityName}'. Putting the workflow in the faulted state.",
- workflowContext.WorkflowType.Name,
- activityContext.ActivityType.Id,
- activityContext.ActivityType.Name
+ "An unhandled error occurred while executing an activity. Putting the workflow in the faulted state."
);
- workflowContext.Fault(ex, activityContext);
+ workflowContext.Fault(ex, activity);
}
- private async Task ExecuteOrResumeActivityAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activity, bool isResuming, CancellationToken cancellationToken)
+ private async Task ExecuteOrResumeActivityAsync(WorkflowExecutionContext workflowContext, IActivity activity, bool isResuming, CancellationToken cancellationToken)
{
if (!isResuming)
{
// Execute the current activity.
- return await activity.ActivityDescriptor.ExecuteActivityAsync(workflowContext, activity, cancellationToken);
+ return await activity.ExecuteAsync(workflowContext, new ActivityExecutionContext(activity), cancellationToken);
}
else
{
// Resume the current activity.
- return await activity.ActivityDescriptor.ResumeActivityAsync(workflowContext, activity, cancellationToken);
+ return await activity.ResumeAsync(workflowContext, new ActivityExecutionContext(activity), cancellationToken);
}
}
- private async Task InvokeActivitiesAsync(WorkflowExecutionContext workflowContext, Func action)
+ private async Task InvokeActivitiesAsync(WorkflowExecutionContext workflowContext, Func action)
{
- await workflowContext.Activities.Values.InvokeAsync(action, logger);
+ await workflowContext.Workflow.Activities.InvokeAsync(action, logger);
}
}
}
diff --git a/src/Flowsharp.Fluid/Flowsharp.Fluid.csproj b/src/Flowsharp.Fluid/Flowsharp.Fluid.csproj
deleted file mode 100644
index 633d246d2..000000000
--- a/src/Flowsharp.Fluid/Flowsharp.Fluid.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- netstandard2.0
-
-
-
-
-
-
-
diff --git a/src/Flowsharp.Fluid/WorkflowBuilder.cs b/src/Flowsharp.Fluid/WorkflowBuilder.cs
deleted file mode 100644
index a4e310cb2..000000000
--- a/src/Flowsharp.Fluid/WorkflowBuilder.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Flowsharp.Models;
-
-namespace Flowsharp.Fluid
-{
- public class WorkflowBuilder
- {
- public WorkflowBuilder()
- {
- activityTypes = new List();
- }
-
- private IList activityTypes;
-
- }
-}
\ No newline at end of file
diff --git a/src/Flowsharp.Samples.Console/Flowchart1.yaml b/src/Flowsharp.Samples.Console/Flowchart1.yaml
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/Flowsharp.Samples.Console/Program.cs b/src/Flowsharp.Samples.Console/Program.cs
index c7afb65c4..dc36693db 100644
--- a/src/Flowsharp.Samples.Console/Program.cs
+++ b/src/Flowsharp.Samples.Console/Program.cs
@@ -1,8 +1,9 @@
-using System.Threading;
+using System;
+using System.Threading;
using System.Threading.Tasks;
using Flowsharp.Activities;
-using Flowsharp.ActivityProviders;
-using Flowsharp.Models;
+using Flowsharp.Builders;
+using Flowsharp.Serialization;
using Flowsharp.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@@ -13,22 +14,30 @@ namespace Flowsharp.Samples.Console
{
static async Task Main()
{
- var workflowType = new WorkflowType
- {
- Activities = new[]
- {
- new ActivityType("1", "WriteLine")
- },
- Transitions = new Transition[0]
- };
-
- var typedActivityProvider = new TypedActivityProvider(() => new IActivity[] { new WriteLine() } );
- var activityLibrary = new ActivityLibrary(new[]{ typedActivityProvider });
- var dictionary = await activityLibrary.GetActivityDescriptorDictionaryAsync(CancellationToken.None);
- var workflowContext = new WorkflowExecutionContext(dictionary, workflowType, WorkflowStatus.Idle);
var invoker = new WorkflowInvoker(new Logger(new NullLoggerFactory()));
+
+ var workflow = new WorkflowBuilder()
+ .AddActivity(new WriteLine("You have now transitioned into a networked workflow."), helloWorld =>
+ helloWorld.Connect(new WriteLine("Let's run a program."), runProgram =>
+ runProgram.Connect(new WriteLine("Enter first value:"), firstValue =>
+ firstValue.Connect(new ReadLine(), value1 =>
+ value1.Connect(new SetVariable("x", (w, a) => int.Parse((string)w.CurrentScope.ReturnValue)), setX =>
+ setX.Connect(new WriteLine("Enter second value:"), secondValue =>
+ secondValue.Connect(new ReadLine(), value2 =>
+ value2.Connect(new SetVariable("y", (w, a) => int.Parse((string)w.CurrentScope.ReturnValue)), setY =>
+ setY.Connect(new WriteLine((w, a) =>
+ {
+ var x = w.CurrentScope.GetVariable("x");
+ var y = w.CurrentScope.GetVariable("y");
+ var z = x + y;
+ return $"{x} + {y} = {z}";
+ }))))))))))
+ .Build();
- await invoker.InvokeAsync(workflowContext, "1", CancellationToken.None);
+ await invoker.InvokeAsync(workflow);
+
+ var serializer = new JsonWorkflowSerializer();
+ var json = await serializer.SerializeAsync(workflow, CancellationToken.None);
}
}
}