Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/subscriptions #25

Merged
merged 9 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,5 @@ Transport/@stateflows/http-client/dist/
Examples/SignalR/SignalR.Client/ClientApp/.angular/
*.txt
Publish.ps1
/Transport/@stateflows/common/dist
/Transport/@stateflows/http-client/dist
5 changes: 5 additions & 0 deletions Core/Stateflows.Common/Activities/Classes/ActivityId.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Newtonsoft.Json;
using Stateflows.Common.Exceptions;
using Stateflows.Common.Utilities;

Expand Down Expand Up @@ -27,6 +28,10 @@ public ActivityId(BehaviorId id)

public string Instance { get; set; }

[JsonIgnore]
public readonly ActivityClass ActivityClass => new ActivityClass(Name);

[JsonIgnore]
public readonly BehaviorId BehaviorId => new BehaviorId(BehaviorType.Activity, Name, Instance);

public static bool operator ==(ActivityId id1, ActivityId id2)
Expand Down
25 changes: 21 additions & 4 deletions Core/Stateflows.Common/Activities/Classes/ActivityWrapper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Linq;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Stateflows.Activities;
Expand Down Expand Up @@ -28,15 +28,32 @@ public Task<RequestResult<ExecutionResponse>> ExecuteAsync(InitializationRequest
return Behavior.RequestAsync(executionRequest);
}

public Task<RequestResult<CancelResponse>> CancelAsync()
=> RequestAsync(new CancelRequest());

public Task<SendResult> SendAsync<TEvent>(TEvent @event)
where TEvent : Event, new()
=> Behavior.SendAsync(@event);

public Task<RequestResult<TResponse>> RequestAsync<TResponse>(Request<TResponse> request)
where TResponse : Response, new()
=> Behavior.RequestAsync(request);

public Task WatchAsync<TNotification>(Action<TNotification> handler)
where TNotification : Notification, new()
=> Behavior.WatchAsync<TNotification>(handler);

public Task UnwatchAsync<TNotification>()
where TNotification : Notification, new()
=> Behavior.UnwatchAsync<TNotification>();

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
=> Behavior.Dispose();

~ActivityWrapper()
=> Dispose(false);
}
}
7 changes: 0 additions & 7 deletions Core/Stateflows.Common/Activities/Events/CancelRequest.cs

This file was deleted.

9 changes: 0 additions & 9 deletions Core/Stateflows.Common/Activities/Events/CancelResponse.cs

This file was deleted.

2 changes: 0 additions & 2 deletions Core/Stateflows.Common/Activities/Interfaces/IActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,5 @@ namespace Stateflows.Activities
public interface IActivity : IBehavior
{
Task<RequestResult<ExecutionResponse>> ExecuteAsync(InitializationRequest initializationRequest = null, IEnumerable<Token> inputTokens = null);

Task<RequestResult<CancelResponse>> CancelAsync();
}
}
8 changes: 4 additions & 4 deletions Core/Stateflows.Common/Classes/RequestResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public class RequestResult<TResponse> : SendResult
[JsonConstructor]
protected RequestResult() : base() { }

public RequestResult(Request<TResponse> request, EventStatus status, EventValidation requestValidation)
: base(request, status, requestValidation)
public RequestResult(Request<TResponse> request, EventStatus status, EventValidation validation = null)
: base(request, status, validation)
{
Response = request.Response;
}
Expand All @@ -19,8 +19,8 @@ public RequestResult(Request<TResponse> request, EventStatus status, EventValida

public class RequestResult : SendResult
{
public RequestResult(Event request, Response response, EventStatus status, EventValidation requestValidation)
: base(request, status, requestValidation)
public RequestResult(Event request, Response response, EventStatus status, EventValidation validation = null)
: base(request, status, validation)
{
Response = response;
}
Expand Down
74 changes: 73 additions & 1 deletion Core/Stateflows.Common/Context/StateflowsContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;

namespace Stateflows.Common.Context
{
Expand All @@ -21,6 +21,78 @@ public bool ShouldSerializePendingTimeEvents()

public Dictionary<Guid, TimeEvent> PendingTimeEvents { get; set; } = new Dictionary<Guid, TimeEvent>();

public Dictionary<BehaviorId, List<string>> Subscriptions { get; set; } = new Dictionary<BehaviorId, List<string>>();

public bool AddSubscription(BehaviorId subscribeeBehaviorId, string eventName)
{
if (!Subscriptions.TryGetValue(subscribeeBehaviorId, out var eventNames))
{
eventNames = new List<string>();
Subscriptions[subscribeeBehaviorId] = eventNames;
}

if (!eventNames.Contains(eventName))
{
eventNames.Add(eventName);

return true;
}

return false;
}

public bool RemoveSubscription(BehaviorId subscribeeBehaviorId, string eventName)
{
if (
Subscriptions.TryGetValue(subscribeeBehaviorId, out var eventNames) &&
eventNames.Contains(eventName)
)
{
eventNames.Remove(eventName);

return true;
}

return false;
}

public Dictionary<string, List<BehaviorId>> Subscribers { get; set; } = new Dictionary<string, List<BehaviorId>>();

public bool AddSubscribers(BehaviorId subscriberBehaviorId, IEnumerable<string> notificationNames)
{
foreach (var notificationName in notificationNames)
{
if (!Subscribers.TryGetValue(notificationName, out var behaviorIds))
{
behaviorIds = new List<BehaviorId>();
Subscribers[notificationName] = behaviorIds;
}

if (!behaviorIds.Contains(subscriberBehaviorId))
{
behaviorIds.Add(subscriberBehaviorId);
}
}

return true;
}

public bool RemoveSubscribers(BehaviorId subscriberBehaviorId, IEnumerable<string> notificationNames)
{
foreach (var notificationName in notificationNames)
{
if (
Subscribers.TryGetValue(notificationName, out var behaviorIds) &&
behaviorIds.Contains(subscriberBehaviorId)
)
{
behaviorIds.Remove(subscriberBehaviorId);
}
}

return true;
}

public bool ShouldSerializeValues()
=> Values.Any();

Expand Down
6 changes: 5 additions & 1 deletion Core/Stateflows.Common/Enums/EventStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ public enum EventStatus
/// <summary>
/// Event was omitted because other events in CompoundRequest were invalid
/// </summary>
Omitted
Omitted,
/// <summary>
/// Event was forwarded to embedded behavior
/// </summary>
Forwarded
}
}
13 changes: 13 additions & 0 deletions Core/Stateflows.Common/Events/BehaviorStatusNotification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Newtonsoft.Json;
using System.Collections.Generic;

namespace Stateflows.Common
{
public class BehaviorStatusNotification : Notification
{
public BehaviorStatus BehaviorStatus { get; set; }

[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public IEnumerable<string> ExpectedEvents { get; set; }
}
}
8 changes: 7 additions & 1 deletion Core/Stateflows.Common/Events/BehaviorStatusResponse.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
namespace Stateflows.Common
using Newtonsoft.Json;
using System.Collections.Generic;

namespace Stateflows.Common
{
public class BehaviorStatusResponse : Response
{
public override string Name => nameof(BehaviorStatusResponse);

public BehaviorStatus BehaviorStatus { get; set; }

[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public IEnumerable<string> ExpectedEvents { get; set; }
}
}
5 changes: 5 additions & 0 deletions Core/Stateflows.Common/Events/Command.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Stateflows.Common
{
public abstract class Command : Event
{ }
}
2 changes: 2 additions & 0 deletions Core/Stateflows.Common/Events/Event.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class Event : Token
{
[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public List<EventHeader> Headers { get; set; } = new List<EventHeader>();

public DateTime SentAt { get; set; }
}

public class Event<TPayload> : Event
Expand Down
4 changes: 1 addition & 3 deletions Core/Stateflows.Common/Events/EventValidation.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using Stateflows.Common.Extensions;

namespace Stateflows.Common
{
Expand Down
5 changes: 5 additions & 0 deletions Core/Stateflows.Common/Events/FinalizationRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Stateflows.Common
{
public sealed class FinalizationRequest : Request<FinalizationResponse>
{ }
}
7 changes: 7 additions & 0 deletions Core/Stateflows.Common/Events/FinalizationResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Stateflows.Common
{
public sealed class FinalizationResponse : Response
{
public bool FinalizationSuccessful { get; set; }
}
}
17 changes: 17 additions & 0 deletions Core/Stateflows.Common/Events/Notification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Stateflows.Common
{
public class Notification : Event
{
public BehaviorId SenderId { get; set; }
}

public class Notification<TPayload> : Notification
{
public Notification()
{
Payload = default;
}

public TPayload Payload { get; set; }
}
}
5 changes: 5 additions & 0 deletions Core/Stateflows.Common/Events/NotificationsRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Stateflows.Common
{
public sealed class NotificationsRequest : Request<NotificationsResponse>
{ }
}
5 changes: 5 additions & 0 deletions Core/Stateflows.Common/Events/NotificationsResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Stateflows.Common
{
public sealed class NotificationsResponse : Response
{ }
}
4 changes: 3 additions & 1 deletion Core/Stateflows.Common/Events/ResetRequest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace Stateflows.Common
{
public class ResetRequest : Request<ResetResponse>
{ }
{
public bool KeepVersion { get; set; } = false;
}
}
13 changes: 13 additions & 0 deletions Core/Stateflows.Common/Events/SubscriptionRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Newtonsoft.Json;
using System.Collections.Generic;

namespace Stateflows.Common
{
public sealed class SubscriptionRequest : Request<SubscriptionResponse>
{
public BehaviorId BehaviorId { get; set; }

[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public List<string> NotificationNames { get; set; } = new List<string>();
}
}
7 changes: 7 additions & 0 deletions Core/Stateflows.Common/Events/SubscriptionResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Stateflows.Common
{
public sealed class SubscriptionResponse : Response
{
public bool SubscriptionSuccessful { get; set; }
}
}
13 changes: 13 additions & 0 deletions Core/Stateflows.Common/Events/UnsubscriptionRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Newtonsoft.Json;
using System.Collections.Generic;

namespace Stateflows.Common
{
public sealed class UnsubscriptionRequest : Request<UnsubscriptionResponse>
{
public BehaviorId BehaviorId { get; set; }

[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public List<string> NotificationNames { get; set; } = new List<string>();
}
}
7 changes: 7 additions & 0 deletions Core/Stateflows.Common/Events/UnsubscriptionResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Stateflows.Common
{
public sealed class UnsubscriptionResponse : Response
{
public bool UnsubscriptionSuccessful { get; set; }
}
}
13 changes: 11 additions & 2 deletions Core/Stateflows.Common/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,25 @@ public static class TypeExtensions
{
public static string GetReadableName(this Type type)
{
var result = string.Empty;
if (!type.IsGenericType)
{
return type.FullName;
result = type.FullName;
}
else
{
var typeName = type.GetGenericTypeDefinition().FullName.Split('`').First();
var typeNames = string.Join(", ", type.GetGenericArguments().Select(t => t.FullName));
return $"{typeName}<{typeNames}>";
result = $"{typeName}<{typeNames}>";
}

var standardPrefix = "Stateflows.Activities.";
if (result.StartsWith(standardPrefix))
{
result = result.Substring(standardPrefix.Length);
}

return result;
}

public static object GetUninitializedInstance(this Type type)
Expand Down
Loading
Loading