Add project files.
This commit is contained in:
122
Inspectron.Epson/PrintServer/JobSources/SignalRPrintJobSource.cs
Normal file
122
Inspectron.Epson/PrintServer/JobSources/SignalRPrintJobSource.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Channels;
|
||||
using Inspectron.Epson.PrintServer.ConfigurationSources;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Inspectron.Epson.PrintServer.JobSources;
|
||||
|
||||
public class SignalRPrintJobSource: IPrintJobSource
|
||||
{
|
||||
private readonly EpsonPrintServiceConfiguration _groupConfiguration;
|
||||
private readonly ILogger _logger;
|
||||
private readonly HubConnection _connection;
|
||||
private readonly Channel<PrintJob> _printJobChannel = Channel.CreateUnbounded<PrintJob>();
|
||||
|
||||
public SignalRPrintJobSource(EpsonPrintServiceConfiguration groupConfiguration, ILogger logger)
|
||||
{
|
||||
_groupConfiguration = groupConfiguration;
|
||||
_logger = logger;
|
||||
|
||||
_connection = new HubConnectionBuilder()
|
||||
.WithUrl("https://api.stage.gastrojames.ch/hubs/internal?access_token=https://api.stage.gastrojames.ch/hubs/internal")
|
||||
.WithAutomaticReconnect(new InfiniteRetryPolicy())
|
||||
.Build();
|
||||
|
||||
// Register handlers BEFORE starting connection
|
||||
_connection.On<PrintJobFromSignalR>("PrintJob", OnPrintJobReceived);
|
||||
|
||||
_connection.Reconnecting += OnReconnecting;
|
||||
_connection.Reconnected += OnReconnected;
|
||||
_connection.Closed += OnClosed;
|
||||
|
||||
_ = InitializeConnectionAsync();
|
||||
}
|
||||
|
||||
private async Task InitializeConnectionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await _connection.StartAsync();
|
||||
await _connection.InvokeAsync("JoinGroup", _groupConfiguration.GroupId);
|
||||
_logger.LogInformation("SignalR connection started and joined group {GroupId}.", _groupConfiguration.GroupId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to initialize SignalR connection.");
|
||||
}
|
||||
}
|
||||
|
||||
private Task OnReconnecting(Exception? exception)
|
||||
{
|
||||
_logger.LogWarning(exception, "SignalR connection lost. Reconnecting...");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task OnReconnected(string? connectionId)
|
||||
{
|
||||
_logger.LogInformation("SignalR reconnected with connection ID: {ConnectionId}. Rejoining group...", connectionId);
|
||||
try
|
||||
{
|
||||
await _connection.InvokeAsync("JoinGroup", _groupConfiguration.GroupId);
|
||||
_logger.LogInformation("Rejoined SignalR group {GroupId} after reconnection.", _groupConfiguration.GroupId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to rejoin group after reconnection.");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnClosed(Exception? exception)
|
||||
{
|
||||
_logger.LogError(exception, "SignalR connection closed. Attempting manual restart...");
|
||||
|
||||
// Manual reconnection loop if automatic reconnection exhausted (shouldn't happen with infinite retry)
|
||||
await Task.Delay(5000); // Wait before retry
|
||||
try
|
||||
{
|
||||
await _connection.StartAsync();
|
||||
await _connection.InvokeAsync("JoinGroup", _groupConfiguration.GroupId);
|
||||
_logger.LogInformation("Manually reconnected to SignalR.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Manual reconnection failed. Will retry on next connection closed event.");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPrintJobReceived(PrintJobFromSignalR args)
|
||||
{
|
||||
|
||||
_logger.LogInformation("Received print job for working area: {PrintJob}", JsonSerializer.Serialize(args));
|
||||
_printJobChannel.Writer.TryWrite(new PrintJob
|
||||
{
|
||||
AreaId = args.WorkingAreaId,
|
||||
Document = args.Content,
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<PrintJob> GetNextJobAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return await _printJobChannel.Reader.ReadAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public class PrintJobFromSignalR
|
||||
{
|
||||
[JsonPropertyName("workingAreaId")]
|
||||
public string WorkingAreaId { get; set; }
|
||||
[JsonPropertyName("content")]
|
||||
public string Content { get; set; }
|
||||
}
|
||||
|
||||
private class InfiniteRetryPolicy : IRetryPolicy
|
||||
{
|
||||
public TimeSpan? NextRetryDelay(RetryContext retryContext)
|
||||
{
|
||||
// Exponential backoff with a cap at 30 seconds
|
||||
var delay = Math.Min(Math.Pow(2, retryContext.PreviousRetryCount), 30);
|
||||
return TimeSpan.FromSeconds(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Inspectron.Epson/PrintServer/JobSources/SingleJobSource.cs
Normal file
18
Inspectron.Epson/PrintServer/JobSources/SingleJobSource.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace Inspectron.Epson.PrintServer.JobSources;
|
||||
|
||||
public class SingleJobSource: IPrintJobSource
|
||||
{
|
||||
public SingleJobSource(PrintJob job)
|
||||
{
|
||||
_channel.Writer.WriteAsync(job);
|
||||
}
|
||||
|
||||
private Channel<PrintJob> _channel = Channel.CreateUnbounded<PrintJob>();
|
||||
public async Task<PrintJob> GetNextJobAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return await _channel.Reader.ReadAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user