Skip to content

Commit

Permalink
Refactored Live Events
Browse files Browse the repository at this point in the history
  • Loading branch information
AlenGeoAlex committed Jan 22, 2024
1 parent d520dfc commit 881461f
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 86 deletions.
20 changes: 2 additions & 18 deletions Sharecode.Backend.Api/Extensions/BootstrapExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public static IServiceCollection RegisterCors(this IServiceCollection service)
.AllowAnyHeader()
.SetIsOriginAllowed((url) =>
{
if (url == "https://sharecodeapp.onrender.com" || url == "http://localhost:4000")
if (url is "https://sharecodeapp.onrender.com" or "http://localhost:4000")
return true;

return urlRegex.Match(url).Success;
Expand All @@ -167,22 +167,7 @@ public static IKeyValueClient GetKeyValueClient(this IServiceCollection serviceC
IKeyValueClient keyValueClient = serviceProvider.GetRequiredService<IKeyValueClient>();
return keyValueClient;
}

/*public static IServiceCollection CreateShareCodeJobScheduler(this IServiceCollection serviceCollection)
{
serviceCollection.AddQuartz(conf =>
{
var outboxJob = new JobKey(nameof(ProcessOutboxJob));
conf.AddJob<ProcessOutboxJob>(outboxJob)
.AddTrigger(trigger =>
{
trigger.ForJob(jobKey: outboxJob)
.WithSimpleSchedule(schedule => schedule.WithIntervalInSeconds(20).RepeatForever());
});
});
return serviceCollection;
}*/


public static IServiceCollection BuildAuthenticationSchema(this IServiceCollection serviceCollection, IConfiguration configuration, Namespace keyValueNamespace)
{
serviceCollection.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
Expand Down Expand Up @@ -227,7 +212,6 @@ public static IServiceCollection BuildAuthenticationSchema(this IServiceCollecti
context.Token = signalRToken.ToString().Replace("Bearer%20", string.Empty);
context.Request.Headers.Authorization = signalRToken;
context.HttpContext.User.AddIdentity(new ClaimsIdentity(enumerable));
var userClaims = context.HttpContext.User.Claims;
}

return Task.CompletedTask;
Expand Down
1 change: 1 addition & 0 deletions Sharecode.Backend.Api/SharecodeRestApi.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Reflection;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Sharecode.Backend.Application;
Expand Down
71 changes: 62 additions & 9 deletions Sharecode.Backend.Api/SignalR/AbstractHub.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Sharecode.Backend.Application.Client;
using Sharecode.Backend.Application.Event;
using Sharecode.Backend.Application.Exceptions;
using Sharecode.Backend.Application.Models;
using Sharecode.Backend.Domain.Base.Interfaces;
using Sharecode.Backend.Domain.Base.Primitive;
using Sharecode.Backend.Utilities.RedisCache;
using ILogger = Serilog.ILogger;

namespace Sharecode.Backend.Api.SignalR;

public abstract class AbstractHub<TClient>(ILogger logger, IGroupStateManager groupStateManager, IMediator mediator ,IAppCacheClient cacheClient) : Hub<TClient> where TClient : class
public abstract class AbstractHub(ILogger logger, IGroupStateManager groupStateManager, IMediator mediator ,IAppCacheClient cacheClient) : Hub<ISignalRClient>
{
private static readonly Dictionary<string, Func<object, LiveEventContext, Task<LiveEvent<object>>>> InvokeFunc = new();
private static readonly Dictionary<string, Func<object, LiveEventContext, Task>> SendFunc = new();
protected IAppCacheClient CacheClient => cacheClient;
protected IMediator Mediator => mediator;
private IGroupStateManager StateManager => groupStateManager;
Expand Down Expand Up @@ -56,19 +57,71 @@ protected async Task<bool> DisconnectAsync(string connectionId, CancellationToke
}
}

protected static void RegisterReturn(string eventType, Func<object, LiveEventContext, Task<LiveEvent<object>>> func)

public async Task Execute(ClientEvent @event)
{
InvokeFunc[eventType] = func;
if(string.IsNullOrEmpty(@event.EventType))
{
throw new LiveException("No event type specified");
}

var action = TriggerFunctions[@event.EventType];
if (action == null)
{
throw new LiveException("No event action has been registered", eventType: @event.EventType);
}

try
{
await action(@event.Event, new LiveEventContext(Context, Clients, groupStateManager));
}
catch (Exception e)
{
logger.Error(e, "An unknown error occured while handling the Invoke of {FunctionName} by {CallerId}", @event.EventType, Context.ConnectionId);
throw new LiveException("An error has been occured while processing", extendedMessage: e.Message, eventType: @event.EventType);
}
}

protected static void RegisterNonReturn(string eventType, Func<object, LiveEventContext, Task> act)
public async Task<LiveEvent<object>> Invoke(ClientEvent @event)
{
SendFunc[eventType] = act;
if(string.IsNullOrEmpty(@event.EventType))
{
throw new LiveException("No event type specified");
}

var action = InvokeFunctions[@event.EventType];
if (action == null)
{
throw new LiveException("No event action has been registered", eventType: @event.EventType);
}

try
{
return await action(@event.Event, new LiveEventContext(Context, Clients, groupStateManager));
}
catch (Exception e)
{
logger.Error(e, "An unknown error occured while handling the Invoke of {FunctionName} by {CallerId}", @event.EventType, Context.ConnectionId);
throw new LiveException("An error has been occured while processing", extendedMessage: e.Message, eventType: @event.EventType);
}
}
protected static Func<object, LiveEventContext, Task>? Action(string type) => SendFunc[type];
protected static Func<object, LiveEventContext, Task<LiveEvent<object>>>? Invoke(string type) => InvokeFunc[type];

#region Static Invoke Functions

private static readonly Dictionary<string, Func<object, LiveEventContext, Task<LiveEvent<object>>>> InvokeFunctions = new();
private static readonly Dictionary<string, Func<object, LiveEventContext, Task>> TriggerFunctions = new();

protected static void RegisterReturn(string eventType, Func<object, LiveEventContext, Task<LiveEvent<object>>> func)
{
InvokeFunctions[eventType] = func;
}

protected static void RegisterNonReturn(string eventType, Func<object, LiveEventContext, Task> act)
{
TriggerFunctions[eventType] = act;
}

#endregion
}

public sealed class LiveEventContext
Expand Down
58 changes: 2 additions & 56 deletions Sharecode.Backend.Api/SignalR/SnippetHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
using Newtonsoft.Json;
using Sharecode.Backend.Application.Client;
using Sharecode.Backend.Application.Event;
using Sharecode.Backend.Application.Event.Inbound;
using Sharecode.Backend.Application.Event.Outbond;
using Sharecode.Backend.Application.Features.Live.Snippet;
using Sharecode.Backend.Application.Features.Live.Snippet.Joined;
using Sharecode.Backend.Application.Features.Live.Snippet.Left;
using Sharecode.Backend.Application.LiveEvents.Inbound;
using Sharecode.Backend.Application.Models;
using Sharecode.Backend.Domain.Base.Interfaces;
using Sharecode.Backend.Domain.Base.Primitive;
Expand All @@ -16,7 +16,7 @@

namespace Sharecode.Backend.Api.SignalR;

public class SnippetHub(ILogger logger, IGroupStateManager groupStateManager, IMediator mediator, IAppCacheClient appCacheClient) : AbstractHub<ISignalRClient>(logger, groupStateManager, mediator, appCacheClient)
public class SnippetHub(ILogger logger, IGroupStateManager groupStateManager, IMediator mediator, IAppCacheClient appCacheClient) : AbstractHub(logger, groupStateManager, mediator, appCacheClient)
{

static SnippetHub()
Expand Down Expand Up @@ -99,61 +99,7 @@ await Clients.Group(joinedSnippetResponse.SnippetId.ToString())
Context.Items["IDENTIFIER"] = joinedSnippetResponse.JoinedUserId.GetValueOrDefault();
}
}

public async Task Execute(ClientEvent @event)
{
if(string.IsNullOrEmpty(@event.EventType))
{
var liveEvent = LiveEvent<object>.Of(LogEvent.Error($"No execute action is passed in"));
await Clients.Caller.Message(liveEvent);
return;
}

var action = Action(@event.EventType);
if (action == null)
{
var liveEvent = LiveEvent<object>.Of(LogEvent.Warning($"No execute action is registered for the event {@event.EventType}"));
await Clients.Caller.Message(liveEvent);
return;
}

try
{
await action(@event.Event, new LiveEventContext(Context, Clients, groupStateManager));
}
catch (Exception e)
{
var liveEvent = LiveEvent<object>.Of(LogEvent.Error($"Failed to execute the action"));
await Clients.Caller.Message(liveEvent);
}
}

public async Task<LiveEvent<object>> Invoke(ClientEvent @event)
{
if(string.IsNullOrEmpty(@event.EventType))
{
var liveEvent = LiveEvent<object>.Of(LogEvent.Error($"No execute action is passed in"));
return liveEvent;
}

var action = Invoke(@event.EventType);
if (action == null)
{
var liveEvent = LiveEvent<object>.Of(LogEvent.Warning($"No execute action is registered for the event {@event.EventType}"));
return liveEvent;
}

try
{
return await action(@event.Event, new LiveEventContext(Context, Clients, groupStateManager));
}
catch (Exception e)
{
var liveEvent = LiveEvent<object>.Of(LogEvent.Error($"Failed to execute the action"));
return liveEvent;
}
}

public override async Task OnDisconnectedAsync(Exception? exception)
{
var contextConnectionId = Context.ConnectionId;
Expand Down
21 changes: 21 additions & 0 deletions Sharecode.Backend.Application/Exceptions/LiveException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Net;
using Sharecode.Backend.Domain.Exceptions;
using Sharecode.Backend.Utilities.JsonExceptions;

namespace Sharecode.Backend.Application.Exceptions;

[ExceptionDetail(76223, "An unknown error occured while handling the live request")]
public class LiveException : AppException
{
public LiveException(string message, string? extendedMessage = default, string? eventType = default) : base(message, 76223, HttpStatusCode.InternalServerError, extendedMessage)
{
if (string.IsNullOrEmpty(eventType))
{
SetMessage($"Your request failed to specify the event type");
}
else
{
SetMessage($"An unknown error occured while processing the event of {eventType}. Occured exception is : {message}. Additional Message: {extendedMessage}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Sharecode.Backend.Application.Features.Http.Snippet.Comments.List;

public class ListSnippetCommentsQuery : ListQuery, IAppRequest<ListSnippetCommentsResponse>
public class ListSnippetCommentsQuery : ListQuery, IAppRequest<ListSnippetCommentsResponse?>
{
public Guid SnippetId { get; set; }
public Guid? ParentCommentId { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Sharecode.Backend.Application.Event.Inbound;
namespace Sharecode.Backend.Application.LiveEvents.Inbound;

public class LineCommentTypingEvent
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Sharecode.Backend.Application.Event;
namespace Sharecode.Backend.Application.LiveEvents.Outbond;

public class LogEvent
{
Expand Down

0 comments on commit 881461f

Please sign in to comment.