using Microsoft.Extensions.Logging; using Inspectron.Epson.PrintServer.Printers; using Inspectron.Epson.PrintServer.Printers.Utils; namespace Inspectron.Epson.PrintServer.PrintServices; public class EpsonPrintService: IPrintService { private readonly ILogger _logger; private readonly IPrinterFactory _printerFactory; private readonly IWrapperPrinterFactory _wrapperPrinterFactory; private readonly IPrinterConfigurationSource _printerConfigurationSource; private readonly IReceiptConverterFactory _receiptConverterFactory; public EpsonPrintService(ILogger logger, IPrinterFactory printerFactory, IWrapperPrinterFactory wrapperPrinterFactory, IPrinterConfigurationSource printerConfigurationSource, IReceiptConverterFactory receiptConverterFactory) { _logger = logger; _printerFactory = printerFactory; _wrapperPrinterFactory = wrapperPrinterFactory; _printerConfigurationSource = printerConfigurationSource; _receiptConverterFactory = receiptConverterFactory; } public async Task PrintAsync(string printerIp, PrintJob job) { try { var configuration = _printerConfigurationSource.GetConfiguration(printerIp); await using var epsonPrinter = _printerFactory.CreatePrinter(); string address = printerIp; int port = 9100; await epsonPrinter.ConnectAsync(address, port); var printerId = await epsonPrinter.GetPrinterIdAsync(); var status = await epsonPrinter.GetPrinterStatusAsync(); if (!status.IsOnline) { throw new InvalidOperationException("Printer is offline or out of paper."); } var printerAdapter = _wrapperPrinterFactory.CreatePrinterFromId(printerId.Value, epsonPrinter); await printerAdapter.InitAsync(); if (!string.IsNullOrEmpty(job.Document.LogoUrl)) { // Download logo image var logoFileName = Path.GetFileName(new Uri(job.Document.LogoUrl).LocalPath); var ext = Path.GetExtension(logoFileName).ToLowerInvariant(); var encodedName = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(logoFileName)); logoFileName = $"{encodedName}{ext}"; var logoCachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logos"); // Ensure logos cache directory exists if (!Directory.Exists(logoCachePath)) { Directory.CreateDirectory(logoCachePath); } var cachedLogoPath = Path.Combine(logoCachePath, logoFileName); // Download only if not already cached if (!File.Exists(cachedLogoPath)) { using var httpClient = new HttpClient(); httpClient.Timeout = TimeSpan.FromSeconds(10); var logoData = await httpClient.GetByteArrayAsync(job.Document.LogoUrl); await File.WriteAllBytesAsync(cachedLogoPath, logoData); _logger.LogInformation("Downloaded logo {LogoFileName} from {LogoUrl}", logoFileName, job.Document.LogoUrl); } else { _logger.LogDebug("Using cached logo {LogoFileName}", logoFileName); } await printerAdapter.PrintImageAsync(cachedLogoPath); } await printerAdapter.SetFontSizeAsync(configuration.FontSize); // Convert receipt content to print commands using the factory var converter = _receiptConverterFactory.Create(job.Document.ReceiptType, lineWidth: 48, bigFontLineWidth: 24); var commands = converter.Convert(job.Document.Content); await printerAdapter.PrintAsync(commands); await Task.Delay(200); status = await epsonPrinter.GetPrinterStatusAsync(); if (!status.IsOnline) { throw new InvalidOperationException("Printer is offline or out of paper."); } await printerAdapter.Cut(); } catch (Exception e) { _logger.LogWarning( e, "Failed to print job for printer {PrinterUid}", printerIp); return false; } return true; } }