Add project files.
This commit is contained in:
6
Inspectron.Epson/Queue/IPrintService.cs
Normal file
6
Inspectron.Epson/Queue/IPrintService.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public interface IPrintService
|
||||
{
|
||||
Task<bool> PrintAsync(string printerIp, PrintJob job);
|
||||
}
|
||||
14
Inspectron.Epson/Queue/PrintJob.cs
Normal file
14
Inspectron.Epson/Queue/PrintJob.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
public class PrintJob
|
||||
{
|
||||
public string AreaId { get; set; }
|
||||
public string Document { get; set; }
|
||||
public DateTime QueuedAt { get; set; }
|
||||
public int RetryCount { get; set; }
|
||||
|
||||
public PrintJob()
|
||||
{
|
||||
AreaId = Guid.NewGuid().ToString();
|
||||
QueuedAt = DateTime.UtcNow;
|
||||
RetryCount = 0;
|
||||
}
|
||||
}
|
||||
66
Inspectron.Epson/Queue/PrintServer.cs
Normal file
66
Inspectron.Epson/Queue/PrintServer.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public class PrintServer
|
||||
{
|
||||
private readonly IPrintService _printService;
|
||||
private readonly ILogger _logger;
|
||||
private readonly Dictionary<string, PrinterQueue> _printerQueues;
|
||||
|
||||
public PrintServer(IPrintService printService, ILogger logger)
|
||||
{
|
||||
_printService = printService;
|
||||
_logger = logger;
|
||||
_printerQueues = new Dictionary<string, PrinterQueue>();
|
||||
|
||||
}
|
||||
|
||||
public void RegisterPrinter(string printerIp)
|
||||
{
|
||||
if (_printerQueues.ContainsKey(printerIp))
|
||||
return;
|
||||
|
||||
var queue = new PrinterQueue(printerIp, _printService,_logger);
|
||||
_printerQueues[printerIp] = queue;
|
||||
queue.Start();
|
||||
Console.WriteLine($"Printer {printerIp} registered");
|
||||
}
|
||||
|
||||
public void UnregisterPrinter(string printerIp)
|
||||
{
|
||||
if (_printerQueues.TryGetValue(printerIp, out var queue))
|
||||
{
|
||||
queue.StopAsync().Wait();
|
||||
_printerQueues.Remove(printerIp);
|
||||
Console.WriteLine($"Printer {printerIp} unregistered");
|
||||
}
|
||||
}
|
||||
|
||||
public void SubmitJob(string printerIp, PrintJob job)
|
||||
{
|
||||
if (_printerQueues.TryGetValue(printerIp, out var queue))
|
||||
{
|
||||
queue.Enqueue(job);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning( $"Printer {printerIp} not found. Job cannot be submitted.");
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, int> GetQueueStatus()
|
||||
{
|
||||
var status = new Dictionary<string, int>();
|
||||
foreach (var kvp in _printerQueues)
|
||||
{
|
||||
status[kvp.Key] = kvp.Value.QueueLength;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
public async Task ShutdownAsync()
|
||||
{
|
||||
var stopTasks = _printerQueues.Values.Select(q => q.StopAsync());
|
||||
await Task.WhenAll(stopTasks);
|
||||
Console.WriteLine("Print server shut down");
|
||||
}
|
||||
}
|
||||
124
Inspectron.Epson/Queue/PrinterQueue.cs
Normal file
124
Inspectron.Epson/Queue/PrinterQueue.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public class PrinterQueue
|
||||
{
|
||||
public string PrinterIp { get; }
|
||||
private readonly ConcurrentQueue<PrintJob> _queue;
|
||||
private readonly ConcurrentStack<PrintJob> _priorityQueue; // For failed jobs
|
||||
private readonly SemaphoreSlim _signal;
|
||||
private readonly CancellationTokenSource _cancellationTokenSource;
|
||||
private Task _processingTask;
|
||||
private readonly IPrintService _printService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public bool IsProcessing { get; private set; }
|
||||
public int QueueLength => _queue.Count + _priorityQueue.Count;
|
||||
|
||||
public PrinterQueue(string printerIp, IPrintService printService, ILogger logger)
|
||||
{
|
||||
PrinterIp = printerIp;
|
||||
_queue = new ConcurrentQueue<PrintJob>();
|
||||
_priorityQueue = new ConcurrentStack<PrintJob>();
|
||||
_signal = new SemaphoreSlim(0);
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_printService = printService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Enqueue(PrintJob job)
|
||||
{
|
||||
_queue.Enqueue(job);
|
||||
_signal.Release(); // Signal that there's work to do
|
||||
_logger.LogInformation("Job {JobId} queued for printer {PrinterId}. Queue length: {QueueLength}", job.AreaId, PrinterIp, QueueLength);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (_processingTask != null)
|
||||
return;
|
||||
|
||||
IsProcessing = true;
|
||||
_processingTask = Task.Run(() => ProcessQueueAsync(_cancellationTokenSource.Token));
|
||||
_logger.LogInformation("Printer queue {PrinterId} started", PrinterIp);
|
||||
}
|
||||
private void EnqueuePriority(PrintJob job)
|
||||
{
|
||||
_priorityQueue.Push(job);
|
||||
_signal.Release();
|
||||
_logger.LogInformation("Job {JobId} priority queued for printer {PrinterId}. Queue length: {QueueLength}", job.AreaId, PrinterIp, QueueLength);
|
||||
}
|
||||
private async Task ProcessQueueAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Wait for signal that there's work or cancellation
|
||||
await _signal.WaitAsync(cancellationToken);
|
||||
PrintJob job = null;
|
||||
if (!_priorityQueue.TryPop(out job))
|
||||
{
|
||||
_queue.TryDequeue(out job);
|
||||
}
|
||||
|
||||
if (job!=null)
|
||||
{
|
||||
_logger.LogInformation("Processing job {JobId} on printer {PrinterId}", job.AreaId, PrinterIp);
|
||||
|
||||
try
|
||||
{
|
||||
// Call the actual print function
|
||||
bool success = await _printService.PrintAsync(PrinterIp, job);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
// Re-queue with retry logic
|
||||
job.RetryCount++;
|
||||
_logger.LogWarning("Job {JobId} failed, retrying ({RetryCount}/3)", job.AreaId, job.RetryCount);
|
||||
await Task.Delay(5000, cancellationToken); // Wait before retry
|
||||
EnqueuePriority(job);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("Job {JobId} completed successfully on printer {PrinterId}", job.AreaId, PrinterIp);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error processing job {JobId}", job.AreaId);
|
||||
// Handle exception (retry, log, etc.)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IsProcessing = false;
|
||||
_logger.LogInformation("Printer queue {PrinterId} stopped", PrinterIp);
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
_signal.Release(); // Release to unblock the wait
|
||||
|
||||
if (_processingTask != null)
|
||||
{
|
||||
await _processingTask;
|
||||
}
|
||||
}
|
||||
|
||||
public List<PrintJob> GetPendingJobs()
|
||||
{
|
||||
return new List<PrintJob>(_queue);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user