using System.Collections.Concurrent; using Microsoft.Extensions.Logging; namespace Inspectron.Epson.Queue; public class PrintServer { private readonly IPrintService _printService; private readonly ILogger _logger; private readonly IJobStatusReporter _statusReporter; private readonly ConcurrentDictionary _printerQueues; private readonly SemaphoreSlim _printDiscoveryLock = new(1, 1); private int _readerCount = 0; private readonly object _readerCountLock = new(); public PrintServer(IPrintService printService, ILogger logger, IJobStatusReporter statusReporter) { _printService = printService; _logger = logger; _statusReporter = statusReporter; _printerQueues = new ConcurrentDictionary(); } /// /// Acquires a read lock for print operations. Multiple print operations can run concurrently. /// public void EnterPrintLock() { _logger.LogDebug("Entering print lock"); lock (_readerCountLock) { _readerCount++; if (_readerCount == 1) { _printDiscoveryLock.Wait(); } } _logger.LogDebug("Entered print lock"); } /// /// Releases the read lock after a print operation completes. /// public void ExitPrintLock() { _logger.LogDebug("Exiting print lock"); lock (_readerCountLock) { _readerCount--; if (_readerCount == 0) { _printDiscoveryLock.Release(); } } _logger.LogDebug("Exited print lock"); } /// /// Acquires a write lock for discovery operations. This blocks until all print operations complete /// and prevents new print operations from starting. /// public async Task EnterDiscoveryLockAsync() { _logger.LogDebug("Entering discovery lock"); await _printDiscoveryLock.WaitAsync(); _logger.LogDebug("Entered discovery lock"); } /// /// Releases the write lock after discovery completes. /// public void ExitDiscoveryLock() { _logger.LogDebug("Exiting discovery lock"); _printDiscoveryLock.Release(); _logger.LogDebug("Exited discovery lock"); } public void RegisterPrinter(string printerIp) { var queue = new PrinterQueue(printerIp, _printService, _logger, this, _statusReporter); if (_printerQueues.TryAdd(printerIp, queue)) { queue.Start(); Console.WriteLine($"Printer {printerIp} registered"); } } public void UnregisterPrinter(string printerIp) { if (_printerQueues.TryRemove(printerIp, out var queue)) { queue.StopAsync().Wait(); 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."); _statusReporter.ReportStatusAsync(job, PrintJobStatus.Failed); } } public Dictionary GetQueueStatus() { var status = new Dictionary(); 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"); } }