[shared/signalr] Strongly typed SignalR bootstrap

This commit is contained in:
Laura Hausmann 2024-04-06 18:20:10 +02:00
parent e4c4ec186c
commit 76b283b3ba
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
7 changed files with 123 additions and 59 deletions

View file

@ -1,10 +1,11 @@
using Iceshrimp.Shared.HubSchemas;
using Microsoft.AspNetCore.SignalR;
namespace Iceshrimp.Backend.Hubs;
public class ExampleHub : Hub
public class ExampleHub : Hub<IExampleHubClient>, IExampleHubServer
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", "SignalR", "ping!");
await Clients.All.ReceiveMessage("SignalR", "ping!");
}
}

View file

@ -1,13 +1,21 @@
using Iceshrimp.Shared.HubSchemas;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
namespace Iceshrimp.Backend.Hubs;
[Authorize(Policy = "HubAuthorization")]
public class StreamingHub : Hub
public class StreamingHub : Hub<IStreamingHubClient>, IStreamingHubServer
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", "SignalR", "ping!");
await Clients.All.ReceiveMessage("SignalR", "ping!");
}
public override async Task OnConnectedAsync()
{
await base.OnConnectedAsync();
var userId = Context.UserIdentifier;
//Clients.User(userId);
}
}

View file

@ -17,6 +17,7 @@
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0"/>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.3"/>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="8.0.3"/>
<PackageReference Include="TypedSignalR.Client" Version="3.5.2" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup>
<ItemGroup>

View file

@ -1,5 +1,4 @@
@page "/hub"
@using Microsoft.AspNetCore.SignalR.Client
@inject NavigationManager Navigation
@implements IAsyncDisposable
@ -29,48 +28,5 @@
</ul>
@code {
private HubConnection? _hubConnection;
private List<string> _messages = [];
private string? _userInput;
private string? _messageInput;
protected override async Task OnInitializedAsync()
{
_hubConnection = new HubConnectionBuilder()
.WithUrl(Navigation.ToAbsoluteUri("/hubs/example"))
.AddMessagePackProtocol()
.Build();
//TODO: authentication is done like this:
//options => { options.AccessTokenProvider = () => Task.FromResult("the_access_token")!; })
_hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
var encodedMsg = $"{user}: {message}";
_messages.Add(encodedMsg);
InvokeAsync(StateHasChanged);
});
await _hubConnection.StartAsync();
}
private async Task Send()
{
if (_hubConnection is not null)
{
await _hubConnection.SendAsync("SendMessage", _userInput, _messageInput);
}
}
public bool IsConnected =>
_hubConnection?.State == HubConnectionState.Connected;
public async ValueTask DisposeAsync()
{
if (_hubConnection is not null)
{
await _hubConnection.DisposeAsync();
}
}
// See Hub.razor.cs
}

View file

@ -0,0 +1,76 @@
using Iceshrimp.Shared.HubSchemas;
using Microsoft.AspNetCore.SignalR.Client;
using TypedSignalR.Client;
namespace Iceshrimp.Frontend.Pages;
public partial class Hub
{
private HubConnection? _hubConnection;
private IExampleHubServer? _hub;
private List<string> _messages = [];
private string _userInput = "";
private string _messageInput = "";
private class ExampleHubClient(Hub page) : IExampleHubClient, IHubConnectionObserver
{
public Task ReceiveMessage(string user, string message)
{
var encodedMsg = $"{user}: {message}";
page._messages.Add(encodedMsg);
page.InvokeAsync(page.StateHasChanged);
return Task.CompletedTask;
}
public Task OnClosed(Exception? exception)
{
return ReceiveMessage("System", "Connection closed.");
}
public Task OnReconnected(string? connectionId)
{
return ReceiveMessage("System", "Reconnected.");
}
public Task OnReconnecting(Exception? exception)
{
return ReceiveMessage("System", "Reconnecting...");
}
}
protected override async Task OnInitializedAsync()
{
_hubConnection = new HubConnectionBuilder()
.WithUrl(Navigation.ToAbsoluteUri("/hubs/example"))
.AddMessagePackProtocol()
.Build();
// This must be in a .razor.cs file for the code generator to work correctly
_hub = _hubConnection.CreateHubProxy<IExampleHubServer>();
//TODO: authentication is done like this:
//options => { options.AccessTokenProvider = () => Task.FromResult("the_access_token")!; })
_hubConnection.Register<IExampleHubClient>(new ExampleHubClient(this));
await _hubConnection.StartAsync();
}
private async Task Send()
{
if (_hub is not null)
{
await _hub.SendMessage(_userInput, _messageInput);
}
}
private bool IsConnected => _hubConnection?.State == HubConnectionState.Connected;
public async ValueTask DisposeAsync()
{
if (_hubConnection is not null)
{
await _hubConnection.DisposeAsync();
}
}
}

View file

@ -0,0 +1,11 @@
namespace Iceshrimp.Shared.HubSchemas;
public interface IExampleHubServer
{
public Task SendMessage(string user, string message);
}
public interface IExampleHubClient
{
public Task ReceiveMessage(string user, string message);
}

View file

@ -0,0 +1,11 @@
namespace Iceshrimp.Shared.HubSchemas;
public interface IStreamingHubServer
{
public Task SendMessage(string user, string message);
}
public interface IStreamingHubClient
{
public Task ReceiveMessage(string user, string message);
}