Skip to content

Eventengine/effects abstraction #184

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

Merged
merged 2 commits into from
Aug 3, 2023
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
190 changes: 138 additions & 52 deletions src/Api/PubnubApi/EventEngine/Core/EventEngineInterfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,142 @@
using System.Threading.Tasks;
using System.Collections.Generic;

namespace PubnubApi.EventEngine.Core {

/// <summary>
/// Generic effect handler.
/// </summary>
public interface IEffectHandler {
Task Cancel();
}

/// <summary>
/// Handler (implementation) for a given invocation. The invocation represents the input arguments of a handler.
/// </summary>
/// <typeparam name="T">Associated invocation</typeparam>
public interface IEffectHandler<in T> : IEffectHandler where T : IEffectInvocation {
Task Run(T invocation);
bool IsBackground(T invocation);
}

/// <summary>
/// An effect invocation. It represents calling <c>Run()</c> on a registered effect handler - calling it is orchestrated by the dispatcher.
/// </summary>
public interface IEffectInvocation { }

/// <summary>
/// A cancel effect invocation. It represents calling <c>Cancel()</c> on a registered effect handler - calling it is orchestrated by the dispatcher.
/// </summary>
public interface IEffectCancelInvocation : IEffectInvocation { }

public interface IEvent { };

public abstract class State
{
public virtual IEnumerable<IEffectInvocation> OnEntry { get; } = null;
public virtual IEnumerable<IEffectInvocation> OnExit { get; } = null;

/// <summary>
/// The EE transition pure function.
/// </summary>
/// <param name="e">Input event</param>
/// <returns>Target state and invocation list, or null for no-transition</returns>
public abstract TransitionResult Transition(IEvent e);

public TransitionResult With(params IEffectInvocation[] invocations)
{
return new TransitionResult(this, invocations);
}

public static implicit operator TransitionResult(State s)
{
return new TransitionResult(s);
}
}
namespace PubnubApi.EventEngine.Core
{
/// <summary>
/// Generic effect handler.
/// </summary>
public interface IEffectHandler
{
Task Cancel();
Task Run(IEffectInvocation invocation);
bool IsBackground(IEffectInvocation invocation);
}

/// <summary>
/// Handler (implementation) for a given invocation. The invocation represents the input arguments of a handler.
/// </summary>
/// <typeparam name="T">Associated invocation</typeparam>
public interface IEffectHandler<T> : IEffectHandler where T : IEffectInvocation
{
Task Run(T invocation);
bool IsBackground(T invocation);
}

public abstract class EffectHandler<T> : IEffectHandler<T>
where T : class, IEffectInvocation
{
public abstract Task Cancel();

public Task Run(IEffectInvocation invocation) => Run(invocation as T);

public bool IsBackground(IEffectInvocation invocation) => IsBackground(invocation as T);

public abstract Task Run(T invocation);

public abstract bool IsBackground(T invocation);
}

/// <summary>
/// Implement a handler a cancellable invocation.
/// </summary>
/// <typeparam name="T1">Connect type invocation</typeparam>
/// <typeparam name="T2">Cancel running invocation</typeparam>
public abstract class EffectCancellableHandler<T1, T2> : EffectHandler<T1>, IEffectHandler<T2>
where T1 : class, IEffectInvocation
where T2 : class, IEffectCancelInvocation
{
// run is not implemented in cancel.
public Task Run(T2 invocation)
{
throw new NotImplementedException();
}

public bool IsBackground(T2 invocation) => false;
}


/// <summary>
/// Implement a handler for two invocations (meant for connect-reconnect pairs). Use EffectDoubleCancellableHandler to implement cancellable handler.
/// </summary>
/// <typeparam name="T1">Run type invocation</typeparam>
/// <typeparam name="T2">Retry type invocation</typeparam>
public abstract class EffectDoubleHandler<T1, T2> : EffectHandler<T1>, IEffectHandler<T2>
where T1 : class, IEffectInvocation
where T2 : class, IEffectInvocation
{

public new Task Run(IEffectInvocation invocation) =>
invocation is T1 ? (this as EffectHandler<T1>).Run(invocation) : Run(invocation as T2);

public new bool IsBackground(IEffectInvocation invocation) =>
invocation is T1 ? (this as EffectHandler<T1>).IsBackground(invocation) : IsBackground(invocation as T2);

public abstract Task Run(T2 invocation);

public abstract bool IsBackground(T2 invocation);
}


/// <summary>
/// Implement a handler for two invocations (meant for connect-reconnect pairs) with a cancel invocation
/// </summary>
/// <typeparam name="T1">Run type invocation</typeparam>
/// <typeparam name="T2">Retry type invocation</typeparam>
/// <typeparam name="T3">Cancel connecting invocation</typeparam>
public abstract class EffectDoubleCancellableHandler<T1, T2, T3> : EffectDoubleHandler<T1, T2>, IEffectHandler<T3>
where T1 : class, IEffectInvocation
where T2 : class, IEffectInvocation
where T3 : class, IEffectCancelInvocation
{
// Run is not implemented in cancel.
public Task Run(T3 invocation)
{
throw new NotImplementedException();
}

public bool IsBackground(T3 invocation) => false;
}


/// <summary>
/// An effect invocation. It represents calling <c>Run()</c> on a registered effect handler - calling it is orchestrated by the dispatcher.
/// </summary>
public interface IEffectInvocation
{
}

/// <summary>
/// A cancel effect invocation. It represents calling <c>Cancel()</c> on a registered effect handler - calling it is orchestrated by the dispatcher.
/// </summary>
public interface IEffectCancelInvocation : IEffectInvocation
{
}

public interface IEvent
{
};

public abstract class State
{
public virtual IEnumerable<IEffectInvocation> OnEntry { get; } = null;
public virtual IEnumerable<IEffectInvocation> OnExit { get; } = null;

/// <summary>
/// The EE transition pure function.
/// </summary>
/// <param name="e">Input event</param>
/// <returns>Target state and invocation list, or null for no-transition</returns>
public abstract TransitionResult Transition(IEvent e);

public TransitionResult With(params IEffectInvocation[] invocations)
{
return new TransitionResult(this, invocations);
}

public static implicit operator TransitionResult(State s)
{
return new TransitionResult(s);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace PubnubApi.EventEngine.Subscribe.Effects
{
public class EmitMessagesHandler : IEffectHandler<Invocations.EmitMessagesInvocation>
public class EmitMessagesHandler : EffectHandler<Invocations.EmitMessagesInvocation>
{
private readonly System.Action<Pubnub, PNMessageResult<object>> messageEmitterFunction;
private readonly Pubnub pubnubInstance;
Expand All @@ -19,7 +19,7 @@ public EmitMessagesHandler(Pubnub pubnubInstance,
this.pubnubInstance = pubnubInstance;
}

public async Task Run(EmitMessagesInvocation invocation)
public async override Task Run(EmitMessagesInvocation invocation)
{
var processedMessages = invocation.Messages.Messages.Select(m => new PNMessageResult<object>()
{
Expand All @@ -37,9 +37,9 @@ public async Task Run(EmitMessagesInvocation invocation)
}
}

public bool IsBackground(EmitMessagesInvocation invocation) => false;
public override bool IsBackground(EmitMessagesInvocation invocation) => false;

public Task Cancel()
public override Task Cancel()
{
throw new NotImplementedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace PubnubApi.EventEngine.Subscribe.Effects
{
public class EmitStatusEffectHandler: IEffectHandler<EmitStatusInvocation>
public class EmitStatusEffectHandler: EffectHandler<EmitStatusInvocation>
{
private readonly Action<Pubnub, PNStatus> statusEmitterFunction;
private readonly Pubnub pubnubInstance;
Expand All @@ -16,11 +16,11 @@ public EmitStatusEffectHandler(Pubnub pn, Action<Pubnub, PNStatus> statusEmitter
this.pubnubInstance = pn;
}

public Task Cancel() => Utils.EmptyTask;
public override Task Cancel() => Utils.EmptyTask;

public bool IsBackground(EmitStatusInvocation invocation) => false;
public override bool IsBackground(EmitStatusInvocation invocation) => false;

public async Task Run(EmitStatusInvocation invocation)
public override async Task Run(EmitStatusInvocation invocation)
{
this.statusEmitterFunction(this.pubnubInstance, invocation.Status);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
namespace PubnubApi.EventEngine.Subscribe.Effects
{
public class HandshakeEffectHandler :
Core.IEffectHandler<HandshakeInvocation>,
Core.IEffectHandler<HandshakeReconnectInvocation>
EffectDoubleCancellableHandler<HandshakeInvocation, HandshakeReconnectInvocation, CancelHandshakeInvocation>
{
private SubscribeManager2 manager;
private EventQueue eventQueue;
Expand All @@ -29,7 +28,7 @@ internal HandshakeEffectHandler(SubscribeManager2 manager, EventQueue eventQueue
this.eventQueue = eventQueue;
}

public async Task Run(HandshakeReconnectInvocation invocation)
public override async Task Run(HandshakeReconnectInvocation invocation)
{
if (!ReconnectionDelayUtil.shouldRetry(invocation.ReconnectionConfiguration, invocation.AttemptedRetries))
{
Expand All @@ -44,12 +43,12 @@ public async Task Run(HandshakeReconnectInvocation invocation)
}
}

public bool IsBackground(HandshakeReconnectInvocation invocation)
public override bool IsBackground(HandshakeReconnectInvocation invocation)
{
return true;
}

public async Task Run(HandshakeInvocation invocation)
public override async Task Run(HandshakeInvocation invocation)
{
var response = await MakeHandshakeRequest(invocation);

Expand All @@ -71,7 +70,7 @@ public async Task Run(HandshakeInvocation invocation)
}
}

public bool IsBackground(HandshakeInvocation invocation)
public override bool IsBackground(HandshakeInvocation invocation)
{
return false;
}
Expand Down Expand Up @@ -105,7 +104,7 @@ public bool IsBackground(HandshakeInvocation invocation)
}
}

public async Task Cancel()
public override async Task Cancel()
{
if (!retryDelay.Cancelled)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
namespace PubnubApi.EventEngine.Subscribe.Effects
{
public class ReceivingEffectHandler:
Core.IEffectHandler<ReceiveMessagesInvocation>,
Core.IEffectHandler<ReceiveReconnectInvocation>
EffectDoubleCancellableHandler<ReceiveMessagesInvocation, ReceiveReconnectInvocation, CancelReceiveMessagesInvocation>
{
private SubscribeManager2 manager;
private EventQueue eventQueue;
Expand All @@ -29,7 +28,7 @@ internal ReceivingEffectHandler(SubscribeManager2 manager, EventQueue eventQueue
this.eventQueue = eventQueue;
}

public Task Run(ReceiveReconnectInvocation invocation)
public override Task Run(ReceiveReconnectInvocation invocation)
{
if (!ReconnectionDelayUtil.shouldRetry(invocation.ReconnectionConfiguration, invocation.AttemptedRetries))
{
Expand All @@ -45,12 +44,12 @@ public Task Run(ReceiveReconnectInvocation invocation)
return Utils.EmptyTask;
}

public bool IsBackground(ReceiveReconnectInvocation invocation)
public override bool IsBackground(ReceiveReconnectInvocation invocation)
{
return true;
}

public async Task Run(ReceiveMessagesInvocation invocation)
public override async Task Run(ReceiveMessagesInvocation invocation)
{
var response = await MakeReceiveMessagesRequest(invocation);
var cursor = new SubscriptionCursor()
Expand All @@ -76,7 +75,7 @@ public async Task Run(ReceiveMessagesInvocation invocation)
}
}

public bool IsBackground(ReceiveMessagesInvocation invocation)
public override bool IsBackground(ReceiveMessagesInvocation invocation)
{
return true;
}
Expand Down Expand Up @@ -105,7 +104,7 @@ public bool IsBackground(ReceiveMessagesInvocation invocation)
}
}

public async Task Cancel()
public override async Task Cancel()
{
if (!retryDelay.Cancelled)
{
Expand Down