Skip to content

Commit

Permalink
Add SignalR methods for events related to a given cart
Browse files Browse the repository at this point in the history
  • Loading branch information
NixFey committed Jan 12, 2024
1 parent 1237d39 commit d403b68
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 34 deletions.
11 changes: 5 additions & 6 deletions Controllers/AlertController.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using fim_queueing_admin.Data;
using fim_queueing_admin.Hubs;
using fim_queueing_admin.Models;
using fim_queueing_admin.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;

namespace fim_queueing_admin.Controllers;

[Authorize]
[Route("[controller]")]
public partial class AlertController(FimDbContext dbContext, IHubContext<AssistantHub> assistantHub) : Controller
public partial class AlertController(FimDbContext dbContext, AssistantService assistantService) : Controller
{

[HttpGet]
Expand Down Expand Up @@ -57,7 +56,7 @@ public async Task<ActionResult> Manage(Guid id, [FromForm] AlertManageModel mode

await dbContext.SaveChangesAsync();

await assistantHub.SendPendingAlertsToEveryone(dbContext);
await assistantService.SendPendingAlertsToEveryone();

return RedirectToAction(nameof(Index));
}
Expand Down Expand Up @@ -85,7 +84,7 @@ public async Task<ActionResult> Manage([FromForm] AlertManageModel model)
await dbContext.Alerts.AddAsync(dbAlert);
await dbContext.SaveChangesAsync();

await assistantHub.SendPendingAlertsToEveryone(dbContext);
await assistantService.SendPendingAlertsToEveryone();

return RedirectToAction(nameof(Index));
}
Expand All @@ -98,7 +97,7 @@ await Task.WhenAll(
dbContext.AlertCarts.Where(ac => ac.AlertId == id).ExecuteDeleteAsync()
);

await assistantHub.SendPendingAlertsToEveryone(dbContext);
await assistantService.SendPendingAlertsToEveryone();

return RedirectToAction(nameof(Index));
}
Expand Down
11 changes: 10 additions & 1 deletion Controllers/EventController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,22 @@ await client.Child($"/seasons/{state.CurrentSeason}/events/{id}")
}

[HttpPost("[action]/{id}")]
public async Task<IActionResult> UpdateCart(string id, [FromForm] Guid cartId)
public async Task<IActionResult> UpdateCart(string id, [FromForm] Guid? cartId, [FromServices] AssistantService assistantService)
{
var oldCartId = await client.Child($"/seasons/{state.CurrentSeason}/events/{id}/cartId")
.OnceSingleAsync<Guid?>();
await client.Child($"/seasons/{state.CurrentSeason}/events/{id}").PatchAsync(JsonSerializer.Serialize(new
{
cartId,
}));

var notifyTasks = new List<Task>();
if (oldCartId is not null && oldCartId != cartId)
notifyTasks.Add(assistantService.SendEventsToCart(oldCartId.Value));
if (cartId is not null) notifyTasks.Add(assistantService.SendEventsToCart(cartId.Value));

await Task.WhenAll(notifyTasks);

return RedirectToAction(nameof(Index));
}
}
36 changes: 9 additions & 27 deletions Hubs/AssistantHub.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using fim_queueing_admin.Auth;
using fim_queueing_admin.Data;
using fim_queueing_admin.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;

namespace fim_queueing_admin.Hubs;

[Authorize(AuthTokenScheme.AuthenticationScheme)]
public class AssistantHub(FimDbContext dbContext) : Hub
public class AssistantHub(FimDbContext dbContext, AssistantService assistantService) : Hub
{
private Guid CartId => Guid.Parse(Context.User?.FindFirst(ClaimTypes.CartId)?.Value ??
throw new ApplicationException("No cart id"));
Expand All @@ -29,7 +30,7 @@ public async Task MarkAlertRead(Guid alertId)
{
var alertCart =
await dbContext.AlertCarts.SingleOrDefaultAsync(ac => ac.CartId == CartId && ac.AlertId == alertId);
if (alertCart is null) throw new ApplicationException($"Unable to find alert {alertId} for card {CartId}");
if (alertCart is null) throw new ApplicationException($"Unable to find alert {alertId} for cart {CartId}");

alertCart.ReadTime = DateTime.UtcNow;

Expand All @@ -38,36 +39,17 @@ public async Task MarkAlertRead(Guid alertId)
await SendPendingAlertsToCaller();
}

// ReSharper disable once UnusedMember.Global
public async Task GetEvents()
{
await assistantService.SendEventsToCart(CartId);
}

private async Task SendPendingAlertsToCaller()
{
var pendingAlerts = await dbContext.AlertCarts.Where(ac => ac.CartId == CartId && ac.ReadTime == null)
.Select(ac => ac.Alert).ToListAsync();

await Clients.Caller.SendAsync("PendingAlerts", pendingAlerts);
}

public async Task SendPendingAlertsToEveryone()
{
var pendingAlerts = await dbContext.AlertCarts.Where(ac => ac.ReadTime == null)
.GroupBy(k => k.CartId, v => v.Alert).ToListAsync();

foreach (var group in pendingAlerts)
{
await Clients.User(group.Key.ToString()).SendAsync("PendingAlerts", group.ToList());
}
}
}

public static class AssistantHubExtensions
{
public static async Task SendPendingAlertsToEveryone(this IHubContext<AssistantHub> hubContext, FimDbContext dbContext)
{
var pendingAlerts = await dbContext.AlertCarts.Where(ac => ac.ReadTime == null)
.GroupBy(k => k.CartId, v => v.Alert).ToListAsync();

foreach (var group in pendingAlerts)
{
await hubContext.Clients.User(group.Key.ToString()).SendAsync("PendingAlerts", group.ToList());
}
}
}
49 changes: 49 additions & 0 deletions Services/AssistantService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using fim_queueing_admin.Data;
using fim_queueing_admin.Hubs;
using fim_queueing_admin.Models;
using Firebase.Database;
using Firebase.Database.Query;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;

namespace fim_queueing_admin.Services;

/// <summary>
/// Helpers for interfacing with AssistantHub clients
/// </summary>
public class AssistantService(IServiceProvider serviceProvider) : IService
{
public async Task SendPendingAlertsToEveryone()
{
var hubContext = serviceProvider.GetRequiredService<IHubContext<AssistantHub>>();
var dbContext = serviceProvider.GetRequiredService<FimDbContext>();

var pendingAlerts = await dbContext.AlertCarts.Where(ac => ac.ReadTime == null)
.GroupBy(k => k.CartId, v => v.Alert).ToListAsync();

foreach (var group in pendingAlerts)
{
await hubContext.Clients.User(group.Key.ToString()).SendAsync("PendingAlerts", group.ToList());
}
}

public async Task SendEventsToCart(Guid cartId)
{
var season = serviceProvider.GetRequiredService<GlobalState>().CurrentSeason;
var rtdb = serviceProvider.GetRequiredService<FirebaseClient>();
var hubContext = serviceProvider.GetRequiredService<IHubContext<AssistantHub>>();

var events = await rtdb.Child($"/seasons/{season}/events").OrderBy("cartId").EqualTo(cartId.ToString())
.OnceAsync<DbEvent>();

await hubContext.Clients.User(cartId.ToString()).SendAsync("Events", events.Select(e => new
{
eventKey = e.Key,
e.Object.eventCode,
e.Object.name,
e.Object.start,
e.Object.end,
state = e.Object.state?.ToString()
}));
}
}

0 comments on commit d403b68

Please sign in to comment.