Compare commits
14 Commits
bf12c889f3
...
5aab46a221
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5aab46a221 | ||
|
|
9fee7ea381 | ||
|
|
cfe5df4b1d | ||
|
|
31ccd93b0d | ||
|
|
48970a1e13 | ||
|
|
0614b205bd | ||
|
|
b533634e14 | ||
|
|
766e4e6d27 | ||
|
|
878e927be9 | ||
|
|
24a0efb979 | ||
|
|
8e450f7934 | ||
|
|
77bbcfe4f1 | ||
|
|
c8eacc1d54 | ||
|
|
bea08ce06c |
6
DigitalData.Auth.Abstractions/ClientExtensions.cs
Normal file
6
DigitalData.Auth.Abstractions/ClientExtensions.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace DigitalData.Auth.Abstractions;
|
||||
|
||||
public static class ClientExtensions
|
||||
{
|
||||
public static bool IsConnectionFailed(this IAuthClient client) => client.ConnectionError is not null;
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
namespace DigitalData.Auth.Abstractions;
|
||||
|
||||
public interface IAuthClient
|
||||
public interface IAuthClient : IAuthClientHandler
|
||||
{
|
||||
Task ReceiveMessage(string user, string message);
|
||||
bool IsConnected { get; }
|
||||
|
||||
Exception? ConnectionError { get; }
|
||||
|
||||
bool IsConnectionFailed => ConnectionError is not null;
|
||||
|
||||
Task StartAsync();
|
||||
|
||||
Task<bool> TryStartAsync();
|
||||
}
|
||||
6
DigitalData.Auth.Abstractions/IAuthClientHandler.cs
Normal file
6
DigitalData.Auth.Abstractions/IAuthClientHandler.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace DigitalData.Auth.Abstractions;
|
||||
|
||||
public interface IAuthClientHandler
|
||||
{
|
||||
Task ReceiveMessageAsync(string user, string message);
|
||||
}
|
||||
@@ -9,6 +9,8 @@ public class AuthClient : IAuthClient
|
||||
{
|
||||
private readonly HubConnection _connection;
|
||||
|
||||
private readonly Lazy<Task<bool>> _lazyInitiator;
|
||||
|
||||
private readonly ILogger? _logger;
|
||||
|
||||
private readonly ClientParams _params;
|
||||
@@ -19,14 +21,45 @@ public class AuthClient : IAuthClient
|
||||
.WithUrl(paramsOptions.Value.Url)
|
||||
.Build();
|
||||
|
||||
_connection.On<string, string>(nameof(ReceiveMessage), ReceiveMessage);
|
||||
_connection.On<string, string>(nameof(ReceiveMessageAsync), ReceiveMessageAsync);
|
||||
|
||||
_logger = logger;
|
||||
|
||||
_params = paramsOptions.Value;
|
||||
|
||||
_lazyInitiator = new(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await _connection.StartAsync();
|
||||
IsConnected = true;
|
||||
return true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ConnectionError = ex;
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async Task StartAsync() => await _connection.StartAsync();
|
||||
public bool IsConnected { get; private set; } = false;
|
||||
|
||||
public Task ReceiveMessage(string user, string message) => _params.Events.OnMessageReceived(user, message, _logger);
|
||||
public Exception? ConnectionError { get; private set; }
|
||||
|
||||
public async Task StartAsync() => await _lazyInitiator.Value;
|
||||
|
||||
public async Task<bool> TryStartAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _lazyInitiator.Value;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Task ReceiveMessageAsync(string user, string message) => Task.Run(() => _params.Events.OnMessageReceived(user, message, _logger));
|
||||
}
|
||||
@@ -4,9 +4,7 @@ namespace DigitalData.Auth.Client
|
||||
{
|
||||
public class ClientEvents
|
||||
{
|
||||
public Func<string, string, ILogger?, Task> OnMessageReceived { get; set; } = (user, message, logger)
|
||||
=> Task.Run(
|
||||
() => logger?.LogInformation("{user}: {message}", user, message)
|
||||
);
|
||||
public Action<string, string, ILogger?> OnMessageReceived { get; set; } = (user, message, logger)
|
||||
=> logger?.LogInformation("{user}: {message}", user, message);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
public class ClientParams
|
||||
{
|
||||
public required string Url { get; init; }
|
||||
#pragma warning disable CS8618 // throw exception in DI extension if it not set
|
||||
public string Url { get; set; }
|
||||
#pragma warning restore CS8618
|
||||
|
||||
public readonly ClientEvents Events = new();
|
||||
}
|
||||
19
DigitalData.Auth.Client/DIExtensions.cs
Normal file
19
DigitalData.Auth.Client/DIExtensions.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using DigitalData.Auth.Abstractions;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace DigitalData.Auth.Client;
|
||||
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddAuthHubClient(this IServiceCollection services, Action<ClientParams> options)
|
||||
{
|
||||
services
|
||||
.Configure(options)
|
||||
.AddSingleton<IAuthClient, AuthClient>()
|
||||
.TryAddSingleton<HubConnectionBuilder>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
78
DigitalData.Auth.Tests/Client/AuthClientTests.cs
Normal file
78
DigitalData.Auth.Tests/Client/AuthClientTests.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using DigitalData.Auth.Abstractions;
|
||||
using DigitalData.Auth.Client;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace DigitalData.Auth.Tests.Client;
|
||||
|
||||
[TestFixture]
|
||||
public class AuthClientTests
|
||||
{
|
||||
private static readonly string HubUrl = "https://localhost:7192/auth-hub";
|
||||
|
||||
private Func<Action<ClientParams>, ServiceProvider> Build;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Build = options => new ServiceCollection()
|
||||
.AddAuthHubClient(options)
|
||||
.BuildServiceProvider();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task StartAsync_ShouldConnectSuccessfully()
|
||||
{
|
||||
// Arrange
|
||||
using var provider = Build(opt => opt.Url = HubUrl);
|
||||
var client = provider.GetRequiredService<IAuthClient>();
|
||||
|
||||
// Act
|
||||
await client.TryStartAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(client.IsConnected);
|
||||
Assert.That(!client.IsConnectionFailed);
|
||||
Assert.That(client.ConnectionError, Is.Null);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ReceiveMessage_ShouldCallOnMessageReceived()
|
||||
{
|
||||
// Arrange
|
||||
string rcv_user = string.Empty;
|
||||
string rcv_msg = string.Empty;
|
||||
|
||||
// Sender client
|
||||
using var provider_sender = Build(opt => opt.Url = HubUrl);
|
||||
var sender_client = provider_sender.GetRequiredService<IAuthClient>();
|
||||
await sender_client.TryStartAsync();
|
||||
|
||||
// Receiver client
|
||||
using var provider_receiver = Build(opt =>
|
||||
{
|
||||
opt.Url = HubUrl;
|
||||
opt.Events.OnMessageReceived = (user, message, logger) =>
|
||||
{
|
||||
rcv_user = user;
|
||||
rcv_msg = message;
|
||||
};
|
||||
});
|
||||
var client_receiver = provider_receiver.GetRequiredService<IAuthClient>();
|
||||
|
||||
string user = "user";
|
||||
string message = "message";
|
||||
|
||||
// Act
|
||||
await client_receiver.ReceiveMessageAsync(user, message);
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(rcv_user, Is.EqualTo(user));
|
||||
Assert.That(rcv_msg, Is.EqualTo(message));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
@@ -9,12 +9,6 @@
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="NewFolder\**" />
|
||||
<EmbeddedResource Remove="NewFolder\**" />
|
||||
<None Remove="NewFolder\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
@@ -25,6 +19,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DigitalData.Auth.Client\DigitalData.Auth.Client.csproj" />
|
||||
<ProjectReference Include="..\src\DigitalData.Auth.API\DigitalData.Auth.API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -3,14 +3,14 @@ using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace DigitalData.Auth.API.Hubs;
|
||||
|
||||
public class AuthHub : Hub<IAuthClient>
|
||||
public class AuthHub : Hub<IAuthClientHandler>
|
||||
{
|
||||
public async Task SendMessage(string user, string message)
|
||||
=> await Clients.All.ReceiveMessage(user, message);
|
||||
=> await Clients.All.ReceiveMessageAsync(user, message);
|
||||
|
||||
public async Task SendMessageToCaller(string user, string message)
|
||||
=> await Clients.Caller.ReceiveMessage(user, message);
|
||||
=> await Clients.Caller.ReceiveMessageAsync(user, message);
|
||||
|
||||
public async Task SendMessageToGroup(string user, string message)
|
||||
=> await Clients.Group("Auth.API Consumers").ReceiveMessage(user, message);
|
||||
=> await Clients.Group("Auth.API Consumers").ReceiveMessageAsync(user, message);
|
||||
}
|
||||
Reference in New Issue
Block a user