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 _queue; private readonly ConcurrentStack _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(); _priorityQueue = new ConcurrentStack(); _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 queued for printer {PrinterId}. Queue length: {QueueLength}", 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 priority queued for printer {PrinterId}. Queue length: {QueueLength}", 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 on printer {PrinterId}", 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 failed, retrying ({RetryCount}/3)", job.RetryCount); await Task.Delay(5000, cancellationToken); // Wait before retry EnqueuePriority(job); } else { _logger.LogInformation("Job completed successfully on printer {PrinterId}", PrinterIp); } } catch (Exception ex) { _logger.LogError(ex, "Error processing job"); // 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 GetPendingJobs() { return new List(_queue); } }