From c0f39a81a8a4f835525d2eb011273d4104942c47 Mon Sep 17 00:00:00 2001 From: Harald Wolff-Thobaben Date: Mon, 14 Aug 2023 14:24:09 +0200 Subject: [PATCH] Added ln.patterns, introduced usage of Optional<> for better exception description via http --- ln.templates.service/HttpTemplateEndpoints.cs | 26 ++++++-- ln.templates.service/TemplateService.cs | 54 ++++++++++------ .../ln.templates.service.csproj | 5 +- .../render/PuppeteerRenderer.cs | 61 +++++++++++-------- ln.templates.test/ln.templates.test.csproj | 2 +- ln.templates/ln.templates.csproj | 2 +- 6 files changed, 97 insertions(+), 53 deletions(-) diff --git a/ln.templates.service/HttpTemplateEndpoints.cs b/ln.templates.service/HttpTemplateEndpoints.cs index 7d5890e..bc7aee7 100644 --- a/ln.templates.service/HttpTemplateEndpoints.cs +++ b/ln.templates.service/HttpTemplateEndpoints.cs @@ -4,6 +4,7 @@ using Jint; using Jint.Native; using Jint.Native.Json; using Jint.Native.Object; +using Jint.Runtime; using ln.http; using ln.json; using ln.json.mapping; @@ -61,8 +62,17 @@ namespace ln.templates.service ) { ObjectInstance jsonObject = new JsonParser(new Engine()).Parse(postContent) as ObjectInstance; - if (_templateService.RenderTemplate(templatePath, jsonObject, out Stream templateStream)) - return HttpResponse.OK().ContentType("text/html").Content(templateStream); + + var templateStream = _templateService.RenderTemplate(templatePath, jsonObject); + if (templateStream) + return HttpResponse.OK().ContentType("text/html").Content(templateStream.Value); + + if (templateStream.Is(out FileNotFoundException e)) + return HttpResponse.NotFound().Content(e.FileName); + if (templateStream.Is(out JavaScriptException jse)) + return HttpResponse.BadRequest() + .Content(String.Format("JavaScript exception: {0}", jse.Error.ToString())); + return HttpResponse.InternalServerError(); } @@ -74,8 +84,16 @@ namespace ln.templates.service ) { ObjectInstance jsonObject = new JsonParser(new Engine()).Parse(postContent) as ObjectInstance; - if (_templateService.RenderPDF(templatePath, jsonObject, out Stream templateStream)) - return HttpResponse.OK().ContentType("application/pdf").Content(templateStream); + var pdfStream = _templateService.RenderPDF(templatePath, jsonObject); + if (pdfStream) + return HttpResponse.OK().ContentType("application/pdf").Content(pdfStream.Value); + + if (pdfStream.Is(out FileNotFoundException e)) + return HttpResponse.NotFound().Content(e.FileName); + if (pdfStream.Is(out JavaScriptException jse)) + return HttpResponse.BadRequest() + .Content(String.Format("JavaScript exception: {0}", jse.Error.ToString())); + return HttpResponse.InternalServerError(); } diff --git a/ln.templates.service/TemplateService.cs b/ln.templates.service/TemplateService.cs index 65809a6..af41357 100644 --- a/ln.templates.service/TemplateService.cs +++ b/ln.templates.service/TemplateService.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.IO; -using Jint.Native; using Jint.Native.Object; +using ln.patterns; using ln.templates.service.render; namespace ln.templates.service @@ -121,48 +121,64 @@ namespace ln.templates.service } public bool RenderTemplate(string templatePath, ObjectInstance o, out Stream templateStream) + => RenderTemplate(templatePath, o).TryGetValue(out templateStream); + + public Optional RenderTemplate(string templatePath, ObjectInstance o) { if (templatePath is null) throw new NullReferenceException(); string directoryPath = Path.GetDirectoryName(templatePath); string templateFilename = Path.GetFileName(templatePath); + + var resolver = Resolver + .FindResolver(directoryPath); + if (resolver is null) + return new FileNotFoundException("", directoryPath); + + Template template = resolver.GetTemplate(templateFilename); + if (template is null) + return new FileNotFoundException("", templatePath); TempFileStream tempFileStream = new TempFileStream(".html"); - - Template template = Resolver - .FindResolver(directoryPath) - .GetTemplate(templateFilename); - Context context = new Context(template.Resolver, new StreamWriter(tempFileStream)); - context.Engine.Realm.GlobalEnv.SetMutableBinding("$baseurl", String.Format("file://{0}",Path.Combine(StoragePath, "resources/")), false); - template.Render(context, o); + try + { + template.Render(context, o); + } + catch (Exception e) + { + return e; + } tempFileStream.Position = 0; - templateStream = tempFileStream; - - return true; + return tempFileStream; } - public bool RenderPDF(string templatePath, ObjectInstance o, out Stream targetStream) + public bool RenderPDF(string templatePath, ObjectInstance o, out Stream targetStream) => + RenderPDF(templatePath, o).TryGetValue(out targetStream); + + public Optional RenderPDF(string templatePath, ObjectInstance o) { if (templatePath is null) throw new NullReferenceException(); string directoryPath = Path.GetDirectoryName(templatePath); string templateFilename = Path.GetFileName(templatePath); - - TempFileStream tempFileStream = new TempFileStream(".html"); - Template template = Resolver - .FindResolver(directoryPath) - .GetTemplate(templateFilename); + var resolver = Resolver + .FindResolver(directoryPath); + if (resolver is null) + return new FileNotFoundException("", directoryPath); + + Template template = resolver.GetTemplate(templateFilename); + if (template is null) + return new FileNotFoundException("", templatePath); return PuppeteerRenderer.RenderTemplate( template, String.Format("file://{0}", Path.Combine(StoragePath, "resources/")), - o, - out targetStream + o ); } diff --git a/ln.templates.service/ln.templates.service.csproj b/ln.templates.service/ln.templates.service.csproj index af67e65..66ff0e5 100644 --- a/ln.templates.service/ln.templates.service.csproj +++ b/ln.templates.service/ln.templates.service.csproj @@ -4,7 +4,7 @@ Exe disable enable - net6.0;net5.0 + net6.0;net7.0 @@ -15,6 +15,7 @@ + @@ -61,4 +62,6 @@ + + diff --git a/ln.templates.service/render/PuppeteerRenderer.cs b/ln.templates.service/render/PuppeteerRenderer.cs index 0fc79ef..0b27d8d 100644 --- a/ln.templates.service/render/PuppeteerRenderer.cs +++ b/ln.templates.service/render/PuppeteerRenderer.cs @@ -1,5 +1,7 @@ +using System; using System.IO; using Jint.Native.Object; +using ln.patterns; using PuppeteerSharp; namespace ln.templates.service.render @@ -8,27 +10,28 @@ namespace ln.templates.service.render { private static BrowserFetcher _browserFetcher; - public static bool RenderTemplate(Template template, string resourcePath, ObjectInstance globals, - out Stream pdfStream) + public static Optional RenderTemplate(Template template, string resourcePath, ObjectInstance globals) { using (StringWriter htmlWriter = new StringWriter()) { - Context context = new Context(template.Resolver, htmlWriter); - template.Render(context, globals); - - using (var browser = Puppeteer.LaunchAsync(new LaunchOptions - { - Headless = true, - }).Result) + try { - using (var page = browser.NewPageAsync().Result) + Context context = new Context(template.Resolver, htmlWriter); + template.Render(context, globals); + + using (var browser = Puppeteer.LaunchAsync(new LaunchOptions + { + Headless = true, + }).Result) { - page.GoToAsync(resourcePath).Wait(); - page.SetContentAsync(htmlWriter.ToString(),new NavigationOptions() + using (var page = browser.NewPageAsync().Result) { - }).Wait(); - - var footerTemplate = page.EvaluateFunctionAsync($@"()=>{{ + page.GoToAsync(resourcePath).Wait(); + page.SetContentAsync(htmlWriter.ToString(), new NavigationOptions() + { + }).Wait(); + + var footerTemplate = page.EvaluateFunctionAsync($@"()=>{{ let footers = document.getElementsByTagName('footer'); if (footers.length){{ let footerHtml = footers[0].outerHTML; @@ -37,21 +40,25 @@ if (footers.length){{ }} return null; }}").Result; - - page.SetContentAsync(page.GetContentAsync().Result).Wait(); - - TempFileStream pdfTempStream = new TempFileStream(".pdf"); - page.PdfAsync(pdfTempStream.Name, new PdfOptions() - { - HeaderTemplate = "
", - FooterTemplate = footerTemplate, - DisplayHeaderFooter = true, - }).Wait(); - pdfStream = pdfTempStream; - return true; + page.SetContentAsync(page.GetContentAsync().Result).Wait(); + + TempFileStream pdfTempStream = new TempFileStream(".pdf"); + page.PdfAsync(pdfTempStream.Name, new PdfOptions() + { + HeaderTemplate = "
", + FooterTemplate = footerTemplate, + DisplayHeaderFooter = true, + }).Wait(); + + return pdfTempStream; + } } } + catch (Exception e) + { + return e; + } } } diff --git a/ln.templates.test/ln.templates.test.csproj b/ln.templates.test/ln.templates.test.csproj index 0c28a43..6ec6c2a 100644 --- a/ln.templates.test/ln.templates.test.csproj +++ b/ln.templates.test/ln.templates.test.csproj @@ -4,7 +4,7 @@ false - net5.0;net6.0 + net6.0;net7.0 default diff --git a/ln.templates/ln.templates.csproj b/ln.templates/ln.templates.csproj index 3240394..524335e 100644 --- a/ln.templates/ln.templates.csproj +++ b/ln.templates/ln.templates.csproj @@ -2,7 +2,7 @@ 0.4.2 - net5.0;net6.0 + net6.0;net7.0 default true