Added ln.patterns, introduced usage of Optional<> for better exception description via http

master
Harald Wolff 2023-08-14 14:24:09 +02:00
parent d30f8c6576
commit c0f39a81a8
6 changed files with 97 additions and 53 deletions

View File

@ -4,6 +4,7 @@ using Jint;
using Jint.Native; using Jint.Native;
using Jint.Native.Json; using Jint.Native.Json;
using Jint.Native.Object; using Jint.Native.Object;
using Jint.Runtime;
using ln.http; using ln.http;
using ln.json; using ln.json;
using ln.json.mapping; using ln.json.mapping;
@ -61,8 +62,17 @@ namespace ln.templates.service
) )
{ {
ObjectInstance jsonObject = new JsonParser(new Engine()).Parse(postContent) as ObjectInstance; 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(); return HttpResponse.InternalServerError();
} }
@ -74,8 +84,16 @@ namespace ln.templates.service
) )
{ {
ObjectInstance jsonObject = new JsonParser(new Engine()).Parse(postContent) as ObjectInstance; ObjectInstance jsonObject = new JsonParser(new Engine()).Parse(postContent) as ObjectInstance;
if (_templateService.RenderPDF(templatePath, jsonObject, out Stream templateStream)) var pdfStream = _templateService.RenderPDF(templatePath, jsonObject);
return HttpResponse.OK().ContentType("application/pdf").Content(templateStream); 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(); return HttpResponse.InternalServerError();
} }

View File

@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Jint.Native;
using Jint.Native.Object; using Jint.Native.Object;
using ln.patterns;
using ln.templates.service.render; using ln.templates.service.render;
namespace ln.templates.service namespace ln.templates.service
@ -121,48 +121,64 @@ namespace ln.templates.service
} }
public bool RenderTemplate(string templatePath, ObjectInstance o, out Stream templateStream) public bool RenderTemplate(string templatePath, ObjectInstance o, out Stream templateStream)
=> RenderTemplate(templatePath, o).TryGetValue(out templateStream);
public Optional<Stream> RenderTemplate(string templatePath, ObjectInstance o)
{ {
if (templatePath is null) if (templatePath is null)
throw new NullReferenceException(); throw new NullReferenceException();
string directoryPath = Path.GetDirectoryName(templatePath); string directoryPath = Path.GetDirectoryName(templatePath);
string templateFilename = Path.GetFileName(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"); TempFileStream tempFileStream = new TempFileStream(".html");
Template template = Resolver
.FindResolver(directoryPath)
.GetTemplate(templateFilename);
Context context = new Context(template.Resolver, new StreamWriter(tempFileStream)); Context context = new Context(template.Resolver, new StreamWriter(tempFileStream));
context.Engine.Realm.GlobalEnv.SetMutableBinding("$baseurl", String.Format("file://{0}",Path.Combine(StoragePath, "resources/")), false); try
template.Render(context, o); {
template.Render(context, o);
}
catch (Exception e)
{
return e;
}
tempFileStream.Position = 0; tempFileStream.Position = 0;
templateStream = tempFileStream; return tempFileStream;
return true;
} }
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<Stream> RenderPDF(string templatePath, ObjectInstance o)
{ {
if (templatePath is null) if (templatePath is null)
throw new NullReferenceException(); throw new NullReferenceException();
string directoryPath = Path.GetDirectoryName(templatePath); string directoryPath = Path.GetDirectoryName(templatePath);
string templateFilename = Path.GetFileName(templatePath); string templateFilename = Path.GetFileName(templatePath);
TempFileStream tempFileStream = new TempFileStream(".html");
Template template = Resolver var resolver = Resolver
.FindResolver(directoryPath) .FindResolver(directoryPath);
.GetTemplate(templateFilename); if (resolver is null)
return new FileNotFoundException("", directoryPath);
Template template = resolver.GetTemplate(templateFilename);
if (template is null)
return new FileNotFoundException("", templatePath);
return PuppeteerRenderer.RenderTemplate( return PuppeteerRenderer.RenderTemplate(
template, template,
String.Format("file://{0}", Path.Combine(StoragePath, "resources/")), String.Format("file://{0}", Path.Combine(StoragePath, "resources/")),
o, o
out targetStream
); );
} }

View File

@ -4,7 +4,7 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<TargetFrameworks>net6.0;net5.0</TargetFrameworks> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -15,6 +15,7 @@
<PackageReference Include="ln.bootstrap" Version="1.5.0-preview0" /> <PackageReference Include="ln.bootstrap" Version="1.5.0-preview0" />
<PackageReference Include="ln.http" Version="0.9.7-test0" /> <PackageReference Include="ln.http" Version="0.9.7-test0" />
<PackageReference Include="ln.json" Version="1.2.4" /> <PackageReference Include="ln.json" Version="1.2.4" />
<PackageReference Include="ln.patterns" Version="0.1.0-preview6" />
<PackageReference Include="PuppeteerSharp" Version="10.1.2" /> <PackageReference Include="PuppeteerSharp" Version="10.1.2" />
</ItemGroup> </ItemGroup>
@ -61,4 +62,6 @@
<Folder Include="storage\" /> <Folder Include="storage\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,7 @@
using System;
using System.IO; using System.IO;
using Jint.Native.Object; using Jint.Native.Object;
using ln.patterns;
using PuppeteerSharp; using PuppeteerSharp;
namespace ln.templates.service.render namespace ln.templates.service.render
@ -8,27 +10,28 @@ namespace ln.templates.service.render
{ {
private static BrowserFetcher _browserFetcher; private static BrowserFetcher _browserFetcher;
public static bool RenderTemplate(Template template, string resourcePath, ObjectInstance globals, public static Optional<Stream> RenderTemplate(Template template, string resourcePath, ObjectInstance globals)
out Stream pdfStream)
{ {
using (StringWriter htmlWriter = new StringWriter()) using (StringWriter htmlWriter = new StringWriter())
{ {
Context context = new Context(template.Resolver, htmlWriter); try
template.Render(context, globals);
using (var browser = Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true,
}).Result)
{ {
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(); using (var page = browser.NewPageAsync().Result)
page.SetContentAsync(htmlWriter.ToString(),new NavigationOptions()
{ {
}).Wait(); page.GoToAsync(resourcePath).Wait();
page.SetContentAsync(htmlWriter.ToString(), new NavigationOptions()
var footerTemplate = page.EvaluateFunctionAsync<string>($@"()=>{{ {
}).Wait();
var footerTemplate = page.EvaluateFunctionAsync<string>($@"()=>{{
let footers = document.getElementsByTagName('footer'); let footers = document.getElementsByTagName('footer');
if (footers.length){{ if (footers.length){{
let footerHtml = footers[0].outerHTML; let footerHtml = footers[0].outerHTML;
@ -37,21 +40,25 @@ if (footers.length){{
}} }}
return null; return null;
}}").Result; }}").Result;
page.SetContentAsync(page.GetContentAsync().Result).Wait();
TempFileStream pdfTempStream = new TempFileStream(".pdf");
page.PdfAsync(pdfTempStream.Name, new PdfOptions()
{
HeaderTemplate = "<div></div>",
FooterTemplate = footerTemplate,
DisplayHeaderFooter = true,
}).Wait();
pdfStream = pdfTempStream; page.SetContentAsync(page.GetContentAsync().Result).Wait();
return true;
TempFileStream pdfTempStream = new TempFileStream(".pdf");
page.PdfAsync(pdfTempStream.Name, new PdfOptions()
{
HeaderTemplate = "<div></div>",
FooterTemplate = footerTemplate,
DisplayHeaderFooter = true,
}).Wait();
return pdfTempStream;
}
} }
} }
catch (Exception e)
{
return e;
}
} }
} }

View File

@ -4,7 +4,7 @@
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<TargetFrameworks>net5.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<LangVersion>default</LangVersion> <LangVersion>default</LangVersion>
</PropertyGroup> </PropertyGroup>

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<PackageVersion>0.4.2</PackageVersion> <PackageVersion>0.4.2</PackageVersion>
<TargetFrameworks>net5.0;net6.0</TargetFrameworks> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<LangVersion>default</LangVersion> <LangVersion>default</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup> </PropertyGroup>