refactor(arch): introduce IEbookRepository, ISyncBroadcaster, fix EpubReader path resolution
Critical fixes (review findings #1, #2, #3): - Create IEbookRepository abstraction in Application layer - Remove illegal EF Core dependency from IngestEbookCommandHandler - Create EbookRepository implementation in Infrastructure/Persistence - Create ISyncBroadcaster in Application/Abstractions/Messaging - Create SignalRSyncBroadcaster in Infrastructure/RealTime - Move UpdateReadingProgressCommandHandler from Infrastructure → Application - Add EbookId to GetReaderPageQuery and IEpubReader signature - Rewrite EpubReaderService: DB-resolved file path, remove auto-provisioning - Split EpubService.cs into EpubReaderService.cs + EpubMetadataExtractor.cs - Add CurrentEbookId to IReaderNavigationService and ReaderNavigationService - Update WasmEpubReader and /api/epub endpoint for new signature High severity fixes (#4, #6, #7, #8, #16): - Change BookStorageService registration from Singleton → Scoped - Fix empty catch{} in ReaderCanvas JS interop init — now logs warnings - Replace all Console.WriteLine with ILogger in KnowledgeService + ReaderCanvas - Cache JsonSerializerOptions as static field in KnowledgeService - Wrap SyncService Task.Run body in comprehensive try/catch with ILogger Medium/Low fixes (#11, #13, #14, #15, #18, #20): - BookIngestionModal.DisposeAsync now nullifies _epubBytes (50MB array) - KnowledgeCoordinator.OnGraphUpdated: Action<T> → Func<T, Task> - BookStorageService: Path.Combine → forward-slash string interpolation - SignalR CancellationToken passed as named parameter (not payload arg)
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using NexusReader.Application.Abstractions.Messaging;
|
||||
using NexusReader.Infrastructure.RealTime;
|
||||
|
||||
namespace NexusReader.Infrastructure.RealTime;
|
||||
|
||||
/// <summary>
|
||||
/// SignalR implementation of <see cref="ISyncBroadcaster"/>.
|
||||
/// Uses <see cref="IHubContext{SyncHub}"/> to push progress updates to all of a user's connected devices.
|
||||
/// </summary>
|
||||
internal sealed class SignalRSyncBroadcaster : ISyncBroadcaster
|
||||
{
|
||||
private readonly IHubContext<SyncHub> _hubContext;
|
||||
|
||||
public SignalRSyncBroadcaster(IHubContext<SyncHub> hubContext)
|
||||
{
|
||||
_hubContext = hubContext;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task BroadcastProgressAsync(
|
||||
string userId,
|
||||
string pageId,
|
||||
DateTime timestamp,
|
||||
string? excludedConnectionId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var groupName = $"User_{userId}";
|
||||
|
||||
if (!string.IsNullOrEmpty(excludedConnectionId))
|
||||
{
|
||||
await _hubContext.Clients
|
||||
.GroupExcept(groupName, excludedConnectionId)
|
||||
.SendAsync("ProgressUpdated", pageId, timestamp, cancellationToken: cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _hubContext.Clients
|
||||
.Group(groupName)
|
||||
.SendAsync("ProgressUpdated", pageId, timestamp, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user