|
@@ -1,16 +1,47 @@
|
|
|
-#if NET6_0_OR_GREATER
|
|
|
|
|
|
|
+#if NETCOREAPP3_0_OR_GREATER
|
|
|
|
|
|
|
|
using System;
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
|
-using System.Diagnostics;
|
|
|
|
|
using System.Net.Http;
|
|
using System.Net.Http;
|
|
|
-using System.Net.Http.Json;
|
|
|
|
|
-using System.Threading;
|
|
|
|
|
|
|
+using System.Text;
|
|
|
|
|
+using System.Text.Json;
|
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks;
|
|
|
using QuestPDF.Drawing;
|
|
using QuestPDF.Drawing;
|
|
|
|
|
|
|
|
namespace QuestPDF.Previewer
|
|
namespace QuestPDF.Previewer
|
|
|
{
|
|
{
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ internal sealed class GenericError
|
|
|
|
|
+ {
|
|
|
|
|
+ public string ExceptionType { get; set; }
|
|
|
|
|
+ public string Message { get; set; }
|
|
|
|
|
+ public string StackTrace { get; set; }
|
|
|
|
|
+ public GenericError? InnerException { get; set; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ internal sealed class ShowLayoutErrorApiRequestVersion
|
|
|
|
|
+ {
|
|
|
|
|
+ public GenericError? Error { get; set; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ internal sealed class UpdateDocumentPreviewApiRequest
|
|
|
|
|
+ {
|
|
|
|
|
+ public ICollection<PageSnapshot> PageSnapshots { get; set; }
|
|
|
|
|
+
|
|
|
|
|
+ public class PageSnapshot
|
|
|
|
|
+ {
|
|
|
|
|
+ public string ResourceId { get; } = Guid.NewGuid().ToString("N");
|
|
|
|
|
+ public int PageNumber { get; set; }
|
|
|
|
|
+
|
|
|
|
|
+ public float Width { get; set; }
|
|
|
|
|
+ public float Height { get; set; }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
internal class PreviewerService
|
|
internal class PreviewerService
|
|
|
{
|
|
{
|
|
|
private int Port { get; }
|
|
private int Port { get; }
|
|
@@ -31,133 +62,193 @@ namespace QuestPDF.Previewer
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public async Task Connect()
|
|
|
|
|
|
|
+ public async Task ShowDocumentPreview(ICollection<PreviewerPicture> pictures)
|
|
|
{
|
|
{
|
|
|
- var isAvailable = await IsPreviewerAvailable();
|
|
|
|
|
-
|
|
|
|
|
- if (!isAvailable)
|
|
|
|
|
- {
|
|
|
|
|
- StartPreviewer();
|
|
|
|
|
- await WaitForConnection();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ using var multipartContent = new MultipartFormDataContent();
|
|
|
|
|
|
|
|
- var previewerVersion = await GetPreviewerVersion();
|
|
|
|
|
- CheckVersionCompatibility(previewerVersion);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private async Task<bool> IsPreviewerAvailable()
|
|
|
|
|
- {
|
|
|
|
|
- try
|
|
|
|
|
|
|
+ var pages = new List<UpdateDocumentPreviewApiRequest.PageSnapshot>();
|
|
|
|
|
+
|
|
|
|
|
+ foreach (var picture in pictures)
|
|
|
{
|
|
{
|
|
|
- using var result = await HttpClient.GetAsync("/ping");
|
|
|
|
|
- return result.IsSuccessStatusCode;
|
|
|
|
|
|
|
+ var page = new UpdateDocumentPreviewApiRequest.PageSnapshot
|
|
|
|
|
+ {
|
|
|
|
|
+ Width = picture.Size.Width,
|
|
|
|
|
+ Height = picture.Size.Height
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ pages.Add(page);
|
|
|
|
|
+
|
|
|
|
|
+ var pictureStream = picture.Picture.Serialize().AsStream();
|
|
|
|
|
+ multipartContent.Add(new StreamContent(pictureStream), "snapshots", page.ResourceId);
|
|
|
}
|
|
}
|
|
|
- catch
|
|
|
|
|
|
|
+
|
|
|
|
|
+ var request = new UpdateDocumentPreviewApiRequest
|
|
|
{
|
|
{
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private async Task<Version> GetPreviewerVersion()
|
|
|
|
|
- {
|
|
|
|
|
- using var result = await HttpClient.GetAsync("/version");
|
|
|
|
|
- return await result.Content.ReadFromJsonAsync<Version>();
|
|
|
|
|
|
|
+ PageSnapshots = pages
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ var json = JsonSerializer.Serialize(request);
|
|
|
|
|
+ var jsonContent = new StringContent(json, Encoding.UTF8, "application/json");
|
|
|
|
|
+ multipartContent.Add(jsonContent, "request");
|
|
|
|
|
+
|
|
|
|
|
+ using var response = await HttpClient.PostAsync("/v1/update/preview/document", multipartContent);
|
|
|
|
|
+ response.EnsureSuccessStatusCode();
|
|
|
|
|
+
|
|
|
|
|
+ foreach (var picture in pictures)
|
|
|
|
|
+ picture.Picture.Dispose();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private void StartPreviewer()
|
|
|
|
|
|
|
+ public async Task ShowGenericError(Exception exception)
|
|
|
{
|
|
{
|
|
|
- try
|
|
|
|
|
|
|
+ var payload = new ShowLayoutErrorApiRequestVersion
|
|
|
{
|
|
{
|
|
|
- var process = new Process
|
|
|
|
|
- {
|
|
|
|
|
- StartInfo = new()
|
|
|
|
|
- {
|
|
|
|
|
- FileName = "questpdf-previewer",
|
|
|
|
|
- Arguments = $"{Port}",
|
|
|
|
|
- UseShellExecute = false,
|
|
|
|
|
- CreateNoWindow = true
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- process.Start();
|
|
|
|
|
|
|
+ Error = MapException(exception)
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- Task.Run(async () =>
|
|
|
|
|
- {
|
|
|
|
|
- await process.WaitForExitAsync();
|
|
|
|
|
- process.Dispose();
|
|
|
|
|
- OnPreviewerStopped?.Invoke();
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- catch
|
|
|
|
|
|
|
+ await HttpClient.PostAsJsonAsync("/v1/update/error/generic", payload);
|
|
|
|
|
+
|
|
|
|
|
+ static GenericError? MapException(Exception? exception)
|
|
|
{
|
|
{
|
|
|
- throw new Exception("Cannot start the QuestPDF Previewer tool. " +
|
|
|
|
|
- "Please install it by executing in terminal the following command: 'dotnet tool install --global QuestPDF.Previewer'.");
|
|
|
|
|
|
|
+ if (exception == null)
|
|
|
|
|
+ return null;
|
|
|
|
|
+
|
|
|
|
|
+ return new GenericError
|
|
|
|
|
+ {
|
|
|
|
|
+ ExceptionType = exception.GetType().FullName,
|
|
|
|
|
+ Message = exception.Message,
|
|
|
|
|
+ StackTrace = exception.StackTrace,
|
|
|
|
|
+ InnerException = MapException(exception.InnerException)
|
|
|
|
|
+ };
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- private void CheckVersionCompatibility(Version version)
|
|
|
|
|
- {
|
|
|
|
|
- if (version.Major == RequiredPreviewerVersionMajor && version.Minor == RequiredPreviewerVersionMinor)
|
|
|
|
|
- return;
|
|
|
|
|
-
|
|
|
|
|
- throw new Exception($"Previewer version is not compatible. Possible solutions: " +
|
|
|
|
|
- $"1) Update the QuestPDF library to newer version. " +
|
|
|
|
|
- $"2) Update the QuestPDF previewer tool using the following command: 'dotnet tool update --global QuestPDF.Previewer --version {RequiredPreviewerVersionMajor}.{RequiredPreviewerVersionMinor}'");
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- private async Task WaitForConnection()
|
|
|
|
|
|
|
+ public async Task Connect()
|
|
|
{
|
|
{
|
|
|
- using var cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
|
- cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
|
|
|
|
|
-
|
|
|
|
|
- var cancellationToken = cancellationTokenSource.Token;
|
|
|
|
|
-
|
|
|
|
|
- while (true)
|
|
|
|
|
|
|
+ var isAvailable = await IsPreviewerAvailable();
|
|
|
|
|
+
|
|
|
|
|
+ if (!isAvailable)
|
|
|
{
|
|
{
|
|
|
- await Task.Delay(TimeSpan.FromMilliseconds(250));
|
|
|
|
|
-
|
|
|
|
|
- if (cancellationToken.IsCancellationRequested)
|
|
|
|
|
- throw new Exception($"Cannot connect to the QuestPDF Previewer tool. Please make sure that your Operating System does not block HTTP connections on port {Port}.");
|
|
|
|
|
-
|
|
|
|
|
- var isConnected = await IsPreviewerAvailable();
|
|
|
|
|
-
|
|
|
|
|
- if (isConnected)
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ //StartPreviewer();
|
|
|
|
|
+ //await WaitForConnection();
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ //var previewerVersion = await GetPreviewerVersion();
|
|
|
|
|
+ //CheckVersionCompatibility(previewerVersion);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public async Task RefreshPreview(ICollection<PreviewerPicture> pictures)
|
|
|
|
|
|
|
+ private async Task<bool> IsPreviewerAvailable()
|
|
|
{
|
|
{
|
|
|
- using var multipartContent = new MultipartFormDataContent();
|
|
|
|
|
-
|
|
|
|
|
- var pages = new List<PreviewerRefreshCommand.Page>();
|
|
|
|
|
-
|
|
|
|
|
- foreach (var picture in pictures)
|
|
|
|
|
|
|
+ try
|
|
|
{
|
|
{
|
|
|
- var page = new PreviewerRefreshCommand.Page
|
|
|
|
|
- {
|
|
|
|
|
- Width = picture.Size.Width,
|
|
|
|
|
- Height = picture.Size.Height
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- pages.Add(page);
|
|
|
|
|
-
|
|
|
|
|
- var pictureStream = picture.Picture.Serialize().AsStream();
|
|
|
|
|
- multipartContent.Add(new StreamContent(pictureStream), page.Id, page.Id);
|
|
|
|
|
|
|
+ using var result = await HttpClient.GetAsync("/ping");
|
|
|
|
|
+ return result.IsSuccessStatusCode;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- var command = new PreviewerRefreshCommand
|
|
|
|
|
|
|
+ catch
|
|
|
{
|
|
{
|
|
|
- Pages = pages
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- multipartContent.Add(JsonContent.Create(command), "command");
|
|
|
|
|
-
|
|
|
|
|
- using var _ = await HttpClient.PostAsync("/update/preview", multipartContent);
|
|
|
|
|
-
|
|
|
|
|
- foreach (var picture in pictures)
|
|
|
|
|
- picture.Picture.Dispose();
|
|
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ //
|
|
|
|
|
+ // private async Task<Version> GetPreviewerVersion()
|
|
|
|
|
+ // {
|
|
|
|
|
+ // using var result = await HttpClient.GetAsync("/version");
|
|
|
|
|
+ // return await result.Content.ReadFromJsonAsync<Version>();
|
|
|
|
|
+ // }
|
|
|
|
|
+ //
|
|
|
|
|
+ // private void StartPreviewer()
|
|
|
|
|
+ // {
|
|
|
|
|
+ // try
|
|
|
|
|
+ // {
|
|
|
|
|
+ // var process = new Process
|
|
|
|
|
+ // {
|
|
|
|
|
+ // StartInfo = new()
|
|
|
|
|
+ // {
|
|
|
|
|
+ // FileName = "questpdf-previewer",
|
|
|
|
|
+ // Arguments = $"{Port}",
|
|
|
|
|
+ // UseShellExecute = false,
|
|
|
|
|
+ // CreateNoWindow = true
|
|
|
|
|
+ // }
|
|
|
|
|
+ // };
|
|
|
|
|
+ //
|
|
|
|
|
+ // process.Start();
|
|
|
|
|
+ //
|
|
|
|
|
+ // Task.Run(async () =>
|
|
|
|
|
+ // {
|
|
|
|
|
+ // await process.WaitForExitAsync();
|
|
|
|
|
+ // process.Dispose();
|
|
|
|
|
+ // OnPreviewerStopped?.Invoke();
|
|
|
|
|
+ // });
|
|
|
|
|
+ // }
|
|
|
|
|
+ // catch
|
|
|
|
|
+ // {
|
|
|
|
|
+ // throw new Exception("Cannot start the QuestPDF Previewer tool. " +
|
|
|
|
|
+ // "Please install it by executing in terminal the following command: 'dotnet tool install --global QuestPDF.Previewer'.");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ //
|
|
|
|
|
+ // private void CheckVersionCompatibility(Version version)
|
|
|
|
|
+ // {
|
|
|
|
|
+ // if (version.Major == RequiredPreviewerVersionMajor && version.Minor == RequiredPreviewerVersionMinor)
|
|
|
|
|
+ // return;
|
|
|
|
|
+ //
|
|
|
|
|
+ // throw new Exception($"Previewer version is not compatible. Possible solutions: " +
|
|
|
|
|
+ // $"1) Update the QuestPDF library to newer version. " +
|
|
|
|
|
+ // $"2) Update the QuestPDF previewer tool using the following command: 'dotnet tool update --global QuestPDF.Previewer --version {RequiredPreviewerVersionMajor}.{RequiredPreviewerVersionMinor}'");
|
|
|
|
|
+ // }
|
|
|
|
|
+ //
|
|
|
|
|
+ // private async Task WaitForConnection()
|
|
|
|
|
+ // {
|
|
|
|
|
+ // using var cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
|
+ // cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
|
|
|
|
|
+ //
|
|
|
|
|
+ // var cancellationToken = cancellationTokenSource.Token;
|
|
|
|
|
+ //
|
|
|
|
|
+ // while (true)
|
|
|
|
|
+ // {
|
|
|
|
|
+ // await Task.Delay(TimeSpan.FromMilliseconds(250));
|
|
|
|
|
+ //
|
|
|
|
|
+ // if (cancellationToken.IsCancellationRequested)
|
|
|
|
|
+ // throw new Exception($"Cannot connect to the QuestPDF Previewer tool. Please make sure that your Operating System does not block HTTP connections on port {Port}.");
|
|
|
|
|
+ //
|
|
|
|
|
+ // var isConnected = await IsPreviewerAvailable();
|
|
|
|
|
+ //
|
|
|
|
|
+ // if (isConnected)
|
|
|
|
|
+ // break;
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ //
|
|
|
|
|
+ // public async Task RefreshPreview(ICollection<PreviewerPicture> pictures)
|
|
|
|
|
+ // {
|
|
|
|
|
+ // using var multipartContent = new MultipartFormDataContent();
|
|
|
|
|
+ //
|
|
|
|
|
+ // var pages = new List<PreviewerRefreshCommand.Page>();
|
|
|
|
|
+ //
|
|
|
|
|
+ // foreach (var picture in pictures)
|
|
|
|
|
+ // {
|
|
|
|
|
+ // var page = new PreviewerRefreshCommand.Page
|
|
|
|
|
+ // {
|
|
|
|
|
+ // Width = picture.Size.Width,
|
|
|
|
|
+ // Height = picture.Size.Height
|
|
|
|
|
+ // };
|
|
|
|
|
+ //
|
|
|
|
|
+ // pages.Add(page);
|
|
|
|
|
+ //
|
|
|
|
|
+ // var pictureStream = picture.Picture.Serialize().AsStream();
|
|
|
|
|
+ // multipartContent.Add(new StreamContent(pictureStream), page.Id, page.Id);
|
|
|
|
|
+ // }
|
|
|
|
|
+ //
|
|
|
|
|
+ // var command = new PreviewerRefreshCommand
|
|
|
|
|
+ // {
|
|
|
|
|
+ // Pages = pages
|
|
|
|
|
+ // };
|
|
|
|
|
+ //
|
|
|
|
|
+ // multipartContent.Add(JsonContent.Create(command), "command");
|
|
|
|
|
+ //
|
|
|
|
|
+ // using var _ = await HttpClient.PostAsync("/update/preview", multipartContent);
|
|
|
|
|
+ //
|
|
|
|
|
+ // foreach (var picture in pictures)
|
|
|
|
|
+ // picture.Picture.Dispose();
|
|
|
|
|
+ // }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|