Skip to content

Commit

Permalink
Feat/tokens reworked (#27)
Browse files Browse the repository at this point in the history
* Initial implementation

- anything as a token
- anything as initialization (unfinished)
- sm standard requests turned to commands (unfinished)

* Token -> Object

* Restore

* Works!

* Fixes on token handling

- token identity is now taken under consideration and tokens are not duplicated in inputs
- non-outputting structured activities are now producing control token

* Tokens reworked

Everything can be token now!

* Little cleanup

* 0.12.3-alpha

* Multiple changes
  • Loading branch information
mikolaj-milewski authored Jun 14, 2024
1 parent 14dcad6 commit dc14436
Show file tree
Hide file tree
Showing 259 changed files with 4,175 additions and 2,493 deletions.
10 changes: 10 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[*.cs]

# S3358: Ternary operators should not be nested
dotnet_diagnostic.S3358.severity = none

# S2094: Classes should not be empty
dotnet_diagnostic.S2094.severity = none
dotnet_diagnostic.S2326.severity = none
dotnet_diagnostic.S1121.severity = none
dotnet_diagnostic.CS0067.severity = none
4 changes: 2 additions & 2 deletions Core/Stateflows.Common/Activities/Classes/ActivityWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public ActivityWrapper(IBehavior consumer)
Behavior = consumer;
}

public Task<RequestResult<ExecutionResponse>> ExecuteAsync(InitializationRequest initializationRequest = null, IEnumerable<Token> inputTokens = null)
public Task<RequestResult<ExecutionResponse>> ExecuteAsync(InitializationRequest initializationRequest = null, IEnumerable<object> inputTokens = null)
{
var executionRequest = new ExecutionRequest(initializationRequest ?? new InitializationRequest(), inputTokens ?? new Token[0]);
var executionRequest = new ExecutionRequest(initializationRequest ?? new InitializationRequest(), inputTokens ?? new object[0]);
if (initializationRequest != null)
{
executionRequest.Headers.AddRange(initializationRequest.Headers);
Expand Down
4 changes: 2 additions & 2 deletions Core/Stateflows.Common/Activities/Events/ExecutionRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Stateflows.Activities.Events
{
public sealed class ExecutionRequest : Request<ExecutionResponse>
{
public ExecutionRequest(InitializationRequest initializationRequest, IEnumerable<Token> inputTokens)
public ExecutionRequest(InitializationRequest initializationRequest, IEnumerable<object> inputTokens)
{
InitializationRequest = initializationRequest;
InputTokens = inputTokens;
Expand All @@ -15,6 +15,6 @@ public ExecutionRequest(InitializationRequest initializationRequest, IEnumerable
public InitializationRequest InitializationRequest { get; set; }

[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public IEnumerable<Token> InputTokens { get; set; }
public IEnumerable<object> InputTokens { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ public sealed class ExecutionResponse : Response
public bool ExecutionSuccessful { get; set; }

[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public IEnumerable<Token> OutputTokens { get; set; } = new List<Token>();
public IEnumerable<object> OutputTokens { get; set; } = new List<object>();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Linq;
using System.Collections.Generic;
using Stateflows.Common;
using Stateflows.Activities.Events;

namespace Stateflows.Activities
Expand All @@ -9,7 +8,7 @@ public static class ExecutionResponseExtensions
{
public static IEnumerable<T> GetOutputValues<T>(this ExecutionResponse response)
=> response != null
? response.OutputTokens.OfType<Token<T>>().Select(t => t.Payload).ToArray()
? response.OutputTokens.OfType<T>().ToArray()
: new T[0];

public static T GetOutputValueOrDefault<T>(this ExecutionResponse response, T defaultValue = default)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ namespace Stateflows.Activities
public static class IBehaviorLocatorActivityExtensions
{
public static bool TryLocateActivity(this IBehaviorLocator locator, ActivityId id, out IActivity activity)
#pragma warning disable S1121 // Assignments should not be made from within sub-expressions
=> (
activity = locator.TryLocateBehavior(id.BehaviorId, out var behavior)
? new ActivityWrapper(behavior)
: null
) != null;
#pragma warning restore S1121 // Assignments should not be made from within sub-expressions
}
}

This file was deleted.

2 changes: 1 addition & 1 deletion Core/Stateflows.Common/Activities/Interfaces/IActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ namespace Stateflows.Activities
{
public interface IActivity : IBehavior
{
Task<RequestResult<ExecutionResponse>> ExecuteAsync(InitializationRequest initializationRequest = null, IEnumerable<Token> inputTokens = null);
Task<RequestResult<ExecutionResponse>> ExecuteAsync(InitializationRequest initializationRequest = null, IEnumerable<object> inputTokens = null);
}
}
6 changes: 5 additions & 1 deletion Core/Stateflows.Common/Events/Event.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@

namespace Stateflows.Common
{
public class Event : Token
public class Event
{
public Guid Id { get; set; } = Guid.NewGuid();

[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public List<EventHeader> Headers { get; set; } = new List<EventHeader>();

public DateTime SentAt { get; set; }

public virtual string Name => GetType().GetEventName();
}

public class Event<TPayload> : Event
Expand Down
2 changes: 0 additions & 2 deletions Core/Stateflows.Common/Events/TimeEvents/RecurringEvent.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
namespace Stateflows.Common
{
#pragma warning disable S2094 // Classes should not be empty
public abstract class RecurringEvent : TimeEvent
#pragma warning restore S2094 // Classes should not be empty
{ }
}
5 changes: 3 additions & 2 deletions Core/Stateflows.Common/Extensions/EventInfoExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Stateflows.Common.Extensions;
using System;

namespace Stateflows.Common
{
Expand All @@ -11,7 +12,7 @@ public static string GetEventName(this Type @type)
throw new ArgumentException("Given type is not subclass of Event class");
}

return @type.GetTokenName();
return @type.GetReadableName();
}
}
}
23 changes: 7 additions & 16 deletions Core/Stateflows.Common/Extensions/PayloadObjectExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
using System.Linq;
using System.Collections.Generic;

namespace Stateflows.Common.Data
namespace Stateflows.Common.Data
{
public static class PayloadObjectExtensions
{
public static Event<T> ToEvent<T>(this T obj)
=> new Event<T>() { Payload = obj };

public static Request<TRequestPayload, TResponsePayload> ToRequest<TRequestPayload, TResponsePayload>(this TRequestPayload obj)
=> new Request<TRequestPayload, TResponsePayload>() { Payload = obj };

public static InitializationRequest<T> ToInitializationRequest<T>(this T obj)
=> new InitializationRequest<T>() { Payload = obj };
public static Event<T> ToEvent<T>(this T payload)
=> new Event<T>() { Payload = payload };

public static Token<T> ToToken<T>(this T obj)
=> new Token<T>() { Payload = obj };
public static Request<TRequestPayload, TPayload> ToRequest<TRequestPayload, TPayload>(this TRequestPayload payload)
=> new Request<TRequestPayload, TPayload>() { Payload = payload };

public static IEnumerable<Token<T>> ToTokens<T>(this IEnumerable<T> objs)
=> objs.Select(obj => obj.ToToken()).ToArray();
public static InitializationRequest<TPayload> ToInitializationRequest<TPayload>(this TPayload payload)
=> new InitializationRequest<TPayload>() { Payload = payload };
}
}
10 changes: 1 addition & 9 deletions Core/Stateflows.Common/Extensions/TokenInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@ namespace Stateflows.Common
public static class TokenInfoExtensions
{
public static string GetTokenName(this Type @type)
{
if (!@type.IsSubclassOf(typeof(Token)))
{
throw new ArgumentException("Given type is not subclass of Token class");
}

var token = @type.GetUninitializedInstance() as Token;
return token.Name;
}
=> @type.GetReadableName();
}
}
2 changes: 1 addition & 1 deletion Core/Stateflows.Common/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static string GetReadableName(this Type type)
var standardPrefix = "Stateflows.Activities.";
if (result.StartsWith(standardPrefix))
{
result = result.Substring(standardPrefix.Length);
result = result[standardPrefix.Length..];
}

return result;
Expand Down
7 changes: 3 additions & 4 deletions Core/Stateflows.Common/Interfaces/IBehavior.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Stateflows.Common.Data;
using Stateflows.Common.Interfaces;

namespace Stateflows.Common
{
/// <summary>
/// Behavior handle
/// </summary>
public interface IBehavior : IWatches, IDisposable
{
BehaviorId Id { get; }
Expand Down Expand Up @@ -41,9 +43,6 @@ async Task<RequestResult<InitializationResponse>> ReinitializeAsync(Initializati
return new RequestResult<InitializationResponse>(initializationRequest, result.Status, result.Validation);
}

Task<RequestResult<InitializationResponse>> ReinitializeAsync<TInitializationPayload>(TInitializationPayload payload, bool keepVersion = true)
=> ReinitializeAsync(payload.ToInitializationRequest(), keepVersion);

Task<RequestResult<BehaviorStatusResponse>> GetStatusAsync()
=> RequestAsync(new BehaviorStatusRequest());

Expand Down
6 changes: 6 additions & 0 deletions Core/Stateflows.Common/Interfaces/IBehaviorLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ namespace Stateflows.Common
{
public interface IBehaviorLocator
{
/// <summary>
/// Locates handle of behavior with given identifier.
/// </summary>
/// <param name="id">Identifier of behavior</param>
/// <param name="behavior">out parameter providing behavior handle</param>
/// <returns>True if behavior handle is available; false otherwise</returns>
bool TryLocateBehavior(BehaviorId id, out IBehavior behavior);
}
}
13 changes: 13 additions & 0 deletions Core/Stateflows.Common/Interfaces/ISubscriptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,22 @@ namespace Stateflows.Common
{
public interface ISubscriptions
{
/// <summary>
/// Subscribes for notifications from given behavior (by sending <see cref="SubscriptionRequest"/> to it).<br/>
/// Subscription is durable over time; the only way to end it is by calling <see cref="UnsubscribeAsync"/>.
/// </summary>
/// <typeparam name="TNotification">Subscribed notification type</typeparam>
/// <param name="behaviorId">Identifier of a behavior being subscribed to</param>
/// <returns>Task providing <see cref="SubscriptionResponse"/></returns>
Task<RequestResult<SubscriptionResponse>> SubscribeAsync<TNotification>(BehaviorId behaviorId)
where TNotification : Notification, new();

/// <summary>
/// Unsubscribes for notifications from given behavior (by sending <see cref="UnsubscriptionRequest"/> to it).
/// </summary>
/// <typeparam name="TNotification">Unsubscribed notification type</typeparam>
/// <param name="behaviorId">Identifier of a behavior being unsubscribed to</param>
/// <returns>Task providing <see cref="UnsubscriptionResponse"/></returns>
Task<RequestResult<UnsubscriptionResponse>> UnsubscribeAsync<TNotification>(BehaviorId behaviorId)
where TNotification : Notification, new();
}
Expand Down
12 changes: 12 additions & 0 deletions Core/Stateflows.Common/Interfaces/IWatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,21 @@ namespace Stateflows.Common.Interfaces
{
public interface IWatches
{
/// <summary>
/// Watches for notifications from behavior.<br/>
/// Watch is not durable; it lasts as long as behavior handle does.
/// </summary>
/// <typeparam name="TNotification">Notification type</typeparam>
/// <param name="handler">Notification handler</param>
/// <returns>Task of watch operation</returns>
Task WatchAsync<TNotification>(Action<TNotification> handler)
where TNotification : Notification, new();

/// <summary>
/// Unwatches for notifications from behavior.
/// </summary>
/// <typeparam name="TNotification">Notification type</typeparam>
/// <returns>Task of unwatch operation</returns>
Task UnwatchAsync<TNotification>()
where TNotification : Notification, new();
}
Expand Down
16 changes: 0 additions & 16 deletions Core/Stateflows.Common/Tokens/GroupToken.cs

This file was deleted.

52 changes: 0 additions & 52 deletions Core/Stateflows.Common/Tokens/Token.cs

This file was deleted.

Loading

0 comments on commit dc14436

Please sign in to comment.