using PrintService.Models; using PrintService.Services; namespace PrintService; /// /// Main worker service that coordinates all components /// public class Worker : BackgroundService { private readonly ILogger _logger; private readonly PrintQueueService _queueService; private readonly FileMonitorService _fileMonitorService; private readonly PrinterService _printerService; private readonly DocumentProcessor _documentProcessor; private readonly IpcService _ipcService; public Worker( ILogger logger, PrintQueueService queueService, FileMonitorService fileMonitorService, PrinterService printerService, DocumentProcessor documentProcessor, IpcService ipcService) { _logger = logger; _queueService = queueService; _fileMonitorService = fileMonitorService; _printerService = printerService; _documentProcessor = documentProcessor; _ipcService = ipcService; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("LAAPC Print Service starting at: {time}", DateTimeOffset.Now); try { // Start IPC server for CLI communication _ipcService.Start(); // Start file monitoring (optional - mainly using IPC for job creation) // _fileMonitorService.Start(); _logger.LogInformation("Print service started successfully"); _logger.LogInformation("Queue has {Count} pending jobs", _queueService.Count); // Main processing loop while (!stoppingToken.IsCancellationRequested) { try { if (_queueService.TryDequeue(out var job) && job != null) { await ProcessJob(job, stoppingToken); } else { // No jobs in queue, wait a bit await Task.Delay(500, stoppingToken); } } catch (OperationCanceledException) { // Expected during shutdown, exit gracefully break; } catch (Exception ex) { _logger.LogError(ex, "Error in processing loop"); try { await Task.Delay(1000, stoppingToken); } catch (OperationCanceledException) { // Shutdown requested during error delay break; } } } } catch (OperationCanceledException) { // Expected during shutdown _logger.LogInformation("Service shutdown requested"); } catch (Exception ex) { _logger.LogCritical(ex, "Fatal error in worker service"); throw; } finally { _logger.LogInformation("Print service stopping"); _ipcService.Stop(); _fileMonitorService.Stop(); } } /// /// Process a single print job /// private async Task ProcessJob(PrintJob job, CancellationToken cancellationToken) { _logger.LogInformation("Processing job {JobId} (Type: {DocType}, Order: {OrderNum})", job.Id, job.DocumentType, job.OrderNumber ?? "N/A"); job.Status = PrintJobStatus.Processing; job.UpdatedAt = DateTime.Now; try { // Get document configuration var config = _documentProcessor.GetDocumentConfig(job.DocumentType); if (config == null) { throw new InvalidOperationException($"No configuration found for document type: {job.DocumentType}"); } // Read file content if (!File.Exists(job.QueuedFilePath)) { throw new FileNotFoundException($"Queued file not found: {job.QueuedFilePath}"); } var content = _documentProcessor.ReadFile(job.QueuedFilePath); // Process/transform content var processedContent = _documentProcessor.ProcessDocument(content, config); // Print to Windows queue await Task.Run(() => _printerService.Print(processedContent, config, job.OriginalFilename), cancellationToken); // Post-process (archive or delete) _documentProcessor.PostProcess(job, config); // Mark as completed job.Status = PrintJobStatus.Completed; job.UpdatedAt = DateTime.Now; _logger.LogInformation("Job {JobId} completed successfully", job.Id); } catch (Exception ex) { _logger.LogError(ex, "Failed to process job {JobId}", job.Id); job.LastError = ex.Message; job.UpdatedAt = DateTime.Now; // Requeue for retry _queueService.Requeue(job); } } }