diff --git a/EpsonPrintService/PrintServerBootstrapper.cs b/EpsonPrintService/PrintServerBootstrapper.cs index 3c1c8e8..40f5906 100644 --- a/EpsonPrintService/PrintServerBootstrapper.cs +++ b/EpsonPrintService/PrintServerBootstrapper.cs @@ -1,6 +1,7 @@ using Inspectron.Epson; using Inspectron.Epson.PrintServer; using Inspectron.Epson.PrintServer.ConfigurationSources; +using Inspectron.Epson.PrintServer.Hooks; using Inspectron.Epson.PrintServer.JobSources; using Inspectron.Epson.PrintServer.JobStatusReporters; using Inspectron.Epson.PrintServer.PrinterAssinment; @@ -17,6 +18,7 @@ public class PrintServerBootstrapper { private readonly EpsonPrintServiceConfiguration _config; private readonly CancellationTokenSource _cts; + private readonly List _arrivedHandlers = new(); private StandardKernel? _kernel; public bool IsRunning { get; private set; } @@ -27,6 +29,17 @@ public class PrintServerBootstrapper _cts = cts; } + /// + /// Register a handler that fires once per print job as it arrives from the job source, + /// before it's enqueued on the printer queue. Register all handlers before calling . + /// Handler exceptions are logged and swallowed; they never block a print. + /// + public void OnPrintJobArrived(PrintJobArrivedHandler handler) + { + if (IsRunning) throw new InvalidOperationException("Register hooks before StartAsync()."); + _arrivedHandlers.Add(handler); + } + public async Task StartAsync() { _kernel = new StandardKernel(); @@ -80,6 +93,10 @@ public class PrintServerBootstrapper _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To(); _kernel.Bind().ToSelf().InSingletonScope(); + foreach (var handler in _arrivedHandlers) + { + _kernel.Bind().ToConstant(handler); + } _kernel.Bind().To().InSingletonScope(); _kernel.Bind().ToSelf().InSingletonScope(); _kernel.Bind().ToSelf().InSingletonScope(); diff --git a/Inspectron.Epson/PrintServer/Hooks/PrintJobArrivedHandler.cs b/Inspectron.Epson/PrintServer/Hooks/PrintJobArrivedHandler.cs new file mode 100644 index 0000000..e9ad144 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Hooks/PrintJobArrivedHandler.cs @@ -0,0 +1,75 @@ +using System.Text.Json; +using Inspectron.Epson.PrintServer.Printers.Utils; +using Inspectron.Epson.Queue; +using FinalReceiptModel = Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe.FinalReceipt; +using InvoiceReceiptModel = Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.InvoiceReceipt; +using KitchenReceiptModel = Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt.KitchenReceipt; +using OrderItemsReceiptModel = Inspectron.Epson.PrintServer.Printers.Utils.OrderItems.OrderItemsReceipt; + +namespace Inspectron.Epson.PrintServer.Hooks; + +public delegate Task PrintJobArrivedHandler(PrintJobArrivedContext ctx, CancellationToken cancellationToken); + +public sealed class PrintJobArrivedContext +{ + private KitchenReceiptModel? _kitchen; + private FinalReceiptModel? _final; + private InvoiceReceiptModel? _invoice; + private OrderItemsReceiptModel? _orderItems; + private bool _kitchenParsed, _finalParsed, _invoiceParsed, _orderItemsParsed; + + public PrintJob Job { get; } + public int ReceiptTypeId => Job.Document.ReceiptType; + public ReceiptConverterFactory.EReceiptType ReceiptType => (ReceiptConverterFactory.EReceiptType)Job.Document.ReceiptType; + public string ContentJson => Job.Document.Content; + + public PrintJobArrivedContext(PrintJob job) + { + Job = job; + } + + public KitchenReceiptModel? AsKitchen() + { + if (_kitchenParsed) return _kitchen; + _kitchenParsed = true; + if (ReceiptType is ReceiptConverterFactory.EReceiptType.WorkareaTicket + or ReceiptConverterFactory.EReceiptType.NextCourse) + { + _kitchen = JsonSerializer.Deserialize(ContentJson); + } + return _kitchen; + } + + public FinalReceiptModel? AsFinal() + { + if (_finalParsed) return _final; + _finalParsed = true; + if (ReceiptType == ReceiptConverterFactory.EReceiptType.Receipt) + { + _final = JsonSerializer.Deserialize(ContentJson); + } + return _final; + } + + public InvoiceReceiptModel? AsInvoice() + { + if (_invoiceParsed) return _invoice; + _invoiceParsed = true; + if (ReceiptType == ReceiptConverterFactory.EReceiptType.Invoice) + { + _invoice = JsonSerializer.Deserialize(ContentJson); + } + return _invoice; + } + + public OrderItemsReceiptModel? AsOrderItems() + { + if (_orderItemsParsed) return _orderItems; + _orderItemsParsed = true; + if (ReceiptType == ReceiptConverterFactory.EReceiptType.OrdersOverview) + { + _orderItems = JsonSerializer.Deserialize(ContentJson); + } + return _orderItems; + } +} diff --git a/Inspectron.Epson/PrintServer/PrintLoop.cs b/Inspectron.Epson/PrintServer/PrintLoop.cs index 7bf5074..6c24640 100644 --- a/Inspectron.Epson/PrintServer/PrintLoop.cs +++ b/Inspectron.Epson/PrintServer/PrintLoop.cs @@ -1,4 +1,5 @@ -using Inspectron.Epson.PrintServer.PrintServices; +using Inspectron.Epson.PrintServer.Hooks; +using Inspectron.Epson.PrintServer.PrintServices; using Inspectron.Epson.Queue; using Microsoft.Extensions.Logging; @@ -9,17 +10,19 @@ public class PrintLoop private readonly global::Inspectron.Epson.Queue.PrintServer _printServer; private readonly IPrintService _printService; private readonly IPrintJobSource _jobSource; - + private readonly IReadOnlyList _arrivedHandlers; + private readonly ILogger _logger; private CancellationTokenSource? _cancellationSource; private CancellationToken _cancellationToken; - public PrintLoop(global::Inspectron.Epson.Queue.PrintServer printServer,IPrintService printService, IPrintJobSource jobSource, ILogger logger) + public PrintLoop(global::Inspectron.Epson.Queue.PrintServer printServer, IPrintService printService, IPrintJobSource jobSource, ILogger logger, IEnumerable? arrivedHandlers = null) { _printServer = printServer; _printService = printService; _jobSource = jobSource; - + _arrivedHandlers = arrivedHandlers?.ToList() ?? (IReadOnlyList)Array.Empty(); + _logger = logger; } @@ -35,7 +38,23 @@ public class PrintLoop while (!_cancellationSource!.Token.IsCancellationRequested) { var job = await _jobSource.GetNextJobAsync(_cancellationToken); - + + if (_arrivedHandlers.Count > 0) + { + var ctx = new PrintJobArrivedContext(job); + foreach (var handler in _arrivedHandlers) + { + try + { + await handler(ctx, _cancellationToken); + } + catch (Exception ex) + { + _logger.LogError(ex, "Print job arrived hook threw (job {JobId})", job.JobId); + } + } + } + _printServer.SubmitJob(job.IP, job); } }