diff --git a/Elwig/Documents/Document.cs b/Elwig/Documents/Document.cs index 20c5066..2f5364f 100644 --- a/Elwig/Documents/Document.cs +++ b/Elwig/Documents/Document.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using Elwig.Helpers.Printing; using MimeKit; +using System.Threading; namespace Elwig.Documents { public abstract partial class Document : IDisposable { @@ -98,7 +99,7 @@ namespace Elwig.Documents { return await Html.CompileRenderAsync(name, this); ; } - public async Task Generate(IProgress? progress = null) { + public async Task Generate(CancellationToken? cancelToken = null, IProgress? progress = null) { if (_pdfFile != null) return; progress?.Report(0.0); @@ -108,36 +109,50 @@ namespace Elwig.Documents { var pdf = new TempFile("pdf"); var tmpHtmls = new List(); var tmpFiles = new List(); - var n = m.Documents.Count(); - int i = 0; - foreach (var doc in m.Documents) { - if (doc is PdfDocument) { - tmpFiles.Add(doc.PdfPath!); - continue; + try { + var n = m.Documents.Count(); + int i = 0; + foreach (var doc in m.Documents) { + if (doc is PdfDocument) { + tmpFiles.Add(doc.PdfPath!); + continue; + } + if (cancelToken?.IsCancellationRequested ?? false) + throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!"); + var tmpHtml = new TempFile("html"); + await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8); + tmpHtmls.Add(tmpHtml); + tmpFiles.Add((doc is Letterhead ? "#" : "") + tmpHtml.FileName); + i++; + progress?.Report(GenerationProportion * 100 * i / n); + } + progress?.Report(GenerationProportion * 100); + var pages = await Pdf.Convert(tmpFiles, pdf.FileName, IsDoublePaged, cancelToken, new Progress(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion)))); + TotalPages = pages.Pages; + _pdfFile = pdf; + } catch { + pdf.Dispose(); + throw; + } finally { + foreach (var tmp in tmpHtmls) { + tmp.Dispose(); } - var tmpHtml = new TempFile("html"); - await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8); - tmpHtmls.Add(tmpHtml); - tmpFiles.Add((doc is Letterhead ? "#" : "") + tmpHtml.FileName); - i++; - progress?.Report(GenerationProportion * 100 * i / n); } - progress?.Report(GenerationProportion * 100); - var pages = await Pdf.Convert(tmpFiles, pdf.FileName, IsDoublePaged, new Progress(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion)))); - TotalPages = pages.Pages; - foreach (var tmp in tmpHtmls) { - tmp.Dispose(); - } - _pdfFile = pdf; } else { + if (cancelToken?.IsCancellationRequested ?? false) + throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!"); var pdf = new TempFile("pdf"); - using (var tmpHtml = new TempFile("html")) { + try { + using var tmpHtml = new TempFile("html"); await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8); progress?.Report(50.0); - var pages = await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, IsDoublePaged); + var pages = await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, IsDoublePaged, cancelToken); TotalPages = pages.Pages; + _pdfFile = pdf; + } catch { + pdf.Dispose(); + throw; } - _pdfFile = pdf; } progress?.Report(100.0); } diff --git a/Elwig/Helpers/Printing/Pdf.cs b/Elwig/Helpers/Printing/Pdf.cs index 653e0c5..438ae5a 100644 --- a/Elwig/Helpers/Printing/Pdf.cs +++ b/Elwig/Helpers/Printing/Pdf.cs @@ -1,15 +1,16 @@ -using System.Threading.Tasks; using Elwig.Windows; -using System.Diagnostics; +using PdfiumViewer; using System; -using System.IO; using System.Collections.Generic; -using System.Windows; -using System.Text.RegularExpressions; +using System.Diagnostics; +using System.Drawing.Printing; +using System.IO; using System.Linq; using System.Net.Sockets; -using PdfiumViewer; -using System.Drawing.Printing; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; namespace Elwig.Helpers.Printing { public static class Pdf { @@ -46,24 +47,45 @@ namespace Elwig.Helpers.Printing { return Task.CompletedTask; } - public static async Task<(int Pages, IEnumerable PerDoc)> Convert(string htmlPath, string pdfPath, bool doublePaged = false, IProgress? progress = null) { - return await Convert([htmlPath], pdfPath, doublePaged, progress); + public static async Task<(int Pages, IEnumerable PerDoc)> Convert(string htmlPath, string pdfPath, bool doublePaged = false, CancellationToken? cancelToken = null, IProgress? progress = null) { + return await Convert([htmlPath], pdfPath, doublePaged, cancelToken, progress); } - public static async Task<(int Pages, IEnumerable PerDoc)> Convert(IEnumerable htmlPath, string pdfPath, bool doublePaged = false, IProgress? progress = null) { + public static async Task<(int Pages, IEnumerable PerDoc)> Convert(IEnumerable htmlPath, string pdfPath, bool doublePaged = false, CancellationToken? cancelToken = null, IProgress? progress = null) { if (WinziPrintProc == null) throw new InvalidOperationException("The WinziPrint process has not been initialized yet"); progress?.Report(0.0); using var client = new TcpClient("127.0.0.1", 30983); using var stream = client.GetStream(); + string cnxId; + using var reader = new StreamReader(stream); + var first = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint"); + if (first.StartsWith("id:")) { + cnxId = first[3..].Trim(); + } else { + throw new IOException("Invalid response from WinziPrint"); + } await stream.WriteAsync(Utils.UTF8.GetBytes( "-e utf-8;-p;" + (doublePaged ? "-2;" : "") + $"{string.Join(';', htmlPath)};{pdfPath}" + "\r\n")); - using var reader = new StreamReader(stream); + bool cancelled = false; while (true) { + if (!cancelled && (cancelToken?.IsCancellationRequested ?? false)) { + try { + using var cancelClient = new TcpClient("127.0.0.1", 30983); + using var cancelStream = cancelClient.GetStream(); + using var cancelReader = new StreamReader(cancelStream); + await cancelReader.ReadLineAsync(); + await cancelStream.WriteAsync(Utils.UTF8.GetBytes($"cancel;{cnxId}\r\n")); + } catch { } + cancelled = true; + } var line = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint"); if (line.StartsWith("error:")) { - throw new IOException($"WinziPrint: {line[6..].Trim()}"); + var msg = line[6..].Trim(); + if (msg == "aborted") + throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!"); + throw new IOException($"WinziPrint: {msg}"); } else if (line.StartsWith("progress:")) { var parts = line[9..].Trim().Split('/').Select(int.Parse).ToArray(); progress?.Report(100.0 * parts[0] / parts[1]); diff --git a/Elwig/Windows/MailWindow.xaml b/Elwig/Windows/MailWindow.xaml index 8ed4002..2b39b93 100644 --- a/Elwig/Windows/MailWindow.xaml +++ b/Elwig/Windows/MailWindow.xaml @@ -302,6 +302,9 @@