Initial commit: LAAPC Print Service - Windows service with multi-tray printing, IPC queue management, PDF testing support, and self-installing CLI
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
using PrintService.Models;
|
||||
using PrintService.Services;
|
||||
|
||||
namespace PrintService;
|
||||
|
||||
/// <summary>
|
||||
/// Main worker service that coordinates all components
|
||||
/// </summary>
|
||||
public class Worker : BackgroundService
|
||||
{
|
||||
private readonly ILogger<Worker> _logger;
|
||||
private readonly PrintQueueService _queueService;
|
||||
private readonly FileMonitorService _fileMonitorService;
|
||||
private readonly PrinterService _printerService;
|
||||
private readonly DocumentProcessor _documentProcessor;
|
||||
private readonly IpcService _ipcService;
|
||||
|
||||
public Worker(
|
||||
ILogger<Worker> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a single print job
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user