Browse Source

Previewer ConnectionService refactoring

MarcinZiabek 3 years ago
parent
commit
423c630a47

+ 1 - 1
QuestPDF.Examples/QuestPDF.Examples.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>netcoreapp3.1</TargetFramework>
+        <TargetFramework>net6.0</TargetFramework>
         <IsPackable>false</IsPackable>
     </PropertyGroup>
 

+ 2 - 0
QuestPDF.ReportSample/Layouts/SectionTemplate.cs

@@ -83,6 +83,8 @@ namespace QuestPDF.ReportSample.Layouts
                     .Range(0, model.PhotoCount)
                     .ToList()
                     .ForEach(x => grid.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>());
+
+                //grid.Item().AspectRatio(4 / 3f).Width(100000).Component<ImagePlaceholder>();
             });
         }
     }

+ 1 - 1
QuestPDF.ReportSample/Tests.cs

@@ -25,7 +25,7 @@ namespace QuestPDF.ReportSample
         [Test] 
         public void GenerateAndShowPdf()
         {
-            Report.ShowInPreviewer();
+            Report.ShowInPreviewer(5000);
             
             //ImagePlaceholder.Solid = true;
             //

+ 1 - 1
QuestPDF.UnitTests/QuestPDF.UnitTests.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>netcoreapp3.1</TargetFramework>
+        <TargetFramework>net6.0</TargetFramework>
         <IsPackable>false</IsPackable>
     </PropertyGroup>
 

+ 1 - 1
QuestPDF/Drawing/Proxy/Helpers.cs

@@ -10,7 +10,7 @@ namespace QuestPDF.Drawing.Proxy;
 
 internal static class Helpers
 {
-    public static IEnumerable<DocumentElementProperty> GetElementConfiguration(this IElement element)
+    public static IReadOnlyCollection<DocumentElementProperty> GetElementConfiguration(this IElement element)
     {
         return element
             .GetType()

+ 44 - 0
QuestPDF/Previewer/ApiRequests.cs

@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using QuestPDF.Previewer.Inspection;
+
+namespace QuestPDF.Previewer;
+
+internal sealed class IncompatibleVersionApiRequest
+{
+    
+}
+
+internal sealed class NotifyPresenceApiRequest
+{
+    public string Id { get; set; }
+    public string LibraryVersion { get; set; }
+    public bool IsDotnet6OrBeyond { get; set; }
+    public bool IsDotnet3OrBeyond { get; set; }
+    public bool IsExecutedInUnitTest { get; set; }
+}
+
+internal sealed class DocumentPreviewApiRequest
+{
+    public ICollection<PageSnapshot> PageSnapshots { get; set; }
+    public InspectionElement DocumentHierarchy { 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 sealed class GenericErrorApiRequest
+{
+    public GenericError? Error { get; set; }
+}
+    
+internal sealed class LayoutErrorApiRequest
+{
+    public LayoutRenderingTrace? Trace { get; set; }
+}

+ 17 - 1
QuestPDF/Previewer/Models.cs

@@ -1,6 +1,8 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using QuestPDF.Drawing;
 using QuestPDF.Infrastructure;
+using QuestPDF.Previewer.Inspection;
 
 namespace QuestPDF.Previewer;
 
@@ -32,3 +34,17 @@ internal sealed class LayoutRenderingTrace
     public SpacePlan SpacePlan { get; set; }
     public IReadOnlyCollection<LayoutRenderingTrace> Children { get; set; }
 }
+
+
+    
+internal sealed class GenericError
+{
+    public string ExceptionType { get; set; }
+    public string Message { get; set; }
+    public string StackTrace { get; set; }
+    public GenericError? InnerException { get; set; }
+}
+
+
+
+

+ 7 - 8
QuestPDF/Previewer/PreviewerExtensions.cs

@@ -12,19 +12,19 @@ namespace QuestPDF.Previewer
 {
     public static class Extensions
     {
-        public static void ShowInPreviewer(this IDocument document, int port = 5000)
+        public static void ShowInPreviewer(this IDocument document, int port = 12500)
         {
             document.ShowInPreviewerAsync(port).ConfigureAwait(true).GetAwaiter().GetResult();
         }
         
-        public static async Task ShowInPreviewerAsync(this IDocument document, int port = 5000, CancellationToken cancellationToken = default)
+        public static async Task ShowInPreviewerAsync(this IDocument document, int port = 12500, CancellationToken cancellationToken = default)
         {
             QuestPDF.Settings.EnableDebugging = true;
             
             var previewerService = new PreviewerService(port);
             
             using var cancellationTokenSource = new CancellationTokenSource();
-            previewerService.OnPreviewerStopped += () => cancellationTokenSource.Cancel();
+            previewerService.OnLostConnection += () => cancellationTokenSource.Cancel();
             
             await previewerService.Connect();
             await RefreshPreview();
@@ -35,14 +35,13 @@ namespace QuestPDF.Previewer
 
             while (true)
             {
-                //if (cancellationToken.IsCancellationRequested)
-                //    break;
+                if (cancellationToken.IsCancellationRequested)
+                    break;
 
+                // ReSharper disable once MethodSupportsCancellation
                 await Task.Delay(TimeSpan.FromMilliseconds(1000));
             }
-            
-            //await previewerService.Disconnect();
-            
+
             Task RefreshPreview()
             {
                 try

+ 114 - 143
QuestPDF/Previewer/PreviewerService.cs

@@ -4,72 +4,29 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Net.Http;
+using System.Net.Http.Json;
 using System.Text;
 using System.Text.Json;
 using System.Text.Json.Serialization;
+using System.Threading;
 using System.Threading.Tasks;
-using QuestPDF.Drawing;
 using QuestPDF.Drawing.Exceptions;
 using QuestPDF.Previewer.Inspection;
 
 namespace QuestPDF.Previewer
 {
-    internal sealed class NotifyPresenceRequest
-    {
-        public string Id { get; set; }
-        public string LibraryVersion { get; set; }
-        public bool IsDotnet6OrBeyond { get; set; }
-        public bool IsDotnet3OrBeyond { get; set; }
-        public bool IsExecutedInUnitTest { get; set; }
-    }
-    
-    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 ShowGenericErrorApiRequest
-    {
-        public GenericError? Error { get; set; }
-    }
-    
-    internal sealed class ShowLayoutErrorApiRequest
-    {
-        public LayoutRenderingTrace? Trace { get; set; }
-    }
-
-
-    internal sealed class UpdateDocumentPreviewApiRequest
-    {
-        public ICollection<PageSnapshot> PageSnapshots { get; set; }
-        public InspectionElement DocumentHierarchy { 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
     {
         private string ClientId { get; } = Guid.NewGuid().ToString("D");
+        private string LibraryVersion { get; } = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString();
         
         private int Port { get; }
         private HttpClient HttpClient { get; }
         
-        public  event Action? OnPreviewerStopped;
-
-        private const int RequiredPreviewerVersionMajor = 2022;
-        private const int RequiredPreviewerVersionMinor = 11;
+        public event Action? OnLostConnection;
+        
+        private const int RequiredPreviewerVersionMajor = 2023;
+        private const int RequiredPreviewerVersionMinor = 1;
         
         public PreviewerService(int port)
         {
@@ -80,7 +37,48 @@ namespace QuestPDF.Previewer
                 Timeout = TimeSpan.FromSeconds(1)
             };
         }
+        
+        internal static readonly JsonSerializerOptions JsonSerializerOptions = new()
+        {
+            PropertyNameCaseInsensitive = true,
+            MaxDepth = 256,
+            Converters =
+            {
+                new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
+            }
+        };
+
+        #region Connection
+        
+        public async Task Connect()
+        {
+            var isAvailable = await IsPreviewerAvailable();
+        
+            if (!isAvailable)
+            {
+                StartPreviewer();
+                await WaitForConnection();
+            }
+            
+            var previewerVersion = await GetPreviewerVersion();
+            CheckVersionCompatibility(previewerVersion);
 
+            StartNotifyPresenceTask();
+        }
+        
+        private async Task<bool> IsPreviewerAvailable()
+        {
+            try
+            {
+                using var result = await HttpClient.GetAsync("/ping");
+                return result.IsSuccessStatusCode;
+            }
+            catch
+            {
+                return false;
+            }
+        }
+        
         private void StartPreviewer()
         {
             try
@@ -105,72 +103,99 @@ namespace QuestPDF.Previewer
             }
         }
         
-        public async Task Connect()
+        private async Task WaitForConnection()
         {
-            var isAvailable = await IsPreviewerAvailable();
-        
-            if (!isAvailable)
+            using var cancellationTokenSource = new CancellationTokenSource();
+            cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
+            
+            var cancellationToken = cancellationTokenSource.Token; 
+            
+            while (true)
             {
-                //StartPreviewer();
-                //await WaitForConnection();
+                // ReSharper disable once MethodSupportsCancellation
+                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;
             }
-            
-            //var previewerVersion = await GetPreviewerVersion();
-            //CheckVersionCompatibility(previewerVersion);
-
-            StartNotifyPresenceTask();
+        }
+        
+        #endregion
+        
+        #region Checking compatibility
+        
+        private async Task<Version> GetPreviewerVersion()
+        {
+            using var result = await HttpClient.GetAsync("/version");
+            return await result.Content.ReadFromJsonAsync<Version>();
         }
 
-        private async Task<bool> IsPreviewerAvailable()
+        private async Task CheckVersionCompatibility(Version version)
         {
-            try
-            {
-                using var result = await HttpClient.GetAsync("/ping");
-                return result.IsSuccessStatusCode;
-            }
-            catch
-            {
-                return false;
-            }
+            if (version.Major == RequiredPreviewerVersionMajor && version.Minor == RequiredPreviewerVersionMinor)
+                return;
+
+            await ShowIncompatibleVersion();
+            
+            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}'");
         }
 
-        public void StartNotifyPresenceTask()
+        private async Task ShowIncompatibleVersion()
+        {
+            var payload = new IncompatibleVersionApiRequest();
+            await HttpClient.PostAsJsonAsync("/update/incompatibleVersion", payload, JsonSerializerOptions);
+        }
+        
+        #endregion
+        
+        #region Reporting presence
+        
+        private void StartNotifyPresenceTask()
         {
             Task.Run(async () =>
             {
                 while (true)
                 {
-                    NotifyPresence();
+                    await NotifyPresence();
                     await Task.Delay(1000);
                 }
             });
         }
         
-        public async Task NotifyPresence()
+        private async Task NotifyPresence()
         {
-            var payload = new NotifyPresenceRequest
+            var payload = new NotifyPresenceApiRequest
             {
                 Id = ClientId,
-                LibraryVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString(),
+                LibraryVersion = LibraryVersion,
                 IsDotnet6OrBeyond = RuntimeDetector.IsNet6OrGreater,
                 IsDotnet3OrBeyond = RuntimeDetector.IsNet3OrGreater,
                 IsExecutedInUnitTest = UnitTestDetector.RunningInUnitTest
             };
  
-            await HttpClient.PostAsJsonAsync("/v1/notify/presence", payload);
+            await HttpClient.PostAsJsonAsync("/update/notifyPresence", payload);
         }
         
+        #endregion
         
-        
+        #region Updating state
+
         public async Task ShowDocumentPreview(DocumentPreviewResult documentPreviewResult)
         {
             using var multipartContent = new MultipartFormDataContent();
             
-            var pages = new List<UpdateDocumentPreviewApiRequest.PageSnapshot>();
+            var pages = new List<DocumentPreviewApiRequest.PageSnapshot>();
             
             foreach (var snapshot in documentPreviewResult.PageSnapshots)
             {
-                var page = new UpdateDocumentPreviewApiRequest.PageSnapshot
+                var page = new DocumentPreviewApiRequest.PageSnapshot
                 {
                     PageNumber = documentPreviewResult.PageSnapshots.IndexOf(snapshot) + 1,
                     Width = snapshot.Size.Width,
@@ -183,17 +208,17 @@ namespace QuestPDF.Previewer
                 multipartContent.Add(new StreamContent(pictureStream), "snapshots", page.ResourceId);
             }
             
-            var request = new UpdateDocumentPreviewApiRequest
+            var request = new DocumentPreviewApiRequest
             {
-                PageSnapshots = pages,
+                PageSnapshots = pages, 
                 DocumentHierarchy = documentPreviewResult.DocumentHierarchy
             };
             
-            var json = JsonSerializer.Serialize(request);
+            var json = JsonSerializer.Serialize(request, JsonSerializerOptions);
             var jsonContent = new StringContent(json, Encoding.UTF8, "application/json");
             multipartContent.Add(jsonContent, "request");
             
-            using var response = await HttpClient.PostAsync("/v1/update/preview/document", multipartContent);
+            using var response = await HttpClient.PostAsync("/update/documentPreview", multipartContent);
             response.EnsureSuccessStatusCode();
             
             foreach (var picture in documentPreviewResult.PageSnapshots)
@@ -202,12 +227,12 @@ namespace QuestPDF.Previewer
         
         public async Task ShowGenericError(Exception exception)
         {
-            var payload = new ShowGenericErrorApiRequest
+            var payload = new GenericErrorApiRequest
             {
                 Error = MapException(exception)
             };
 
-            await HttpClient.PostAsJsonAsync("/v1/update/error/generic", payload);
+            await HttpClient.PostAsJsonAsync("/update/genericError", payload, JsonSerializerOptions);
             
             static GenericError? MapException(Exception? exception)
             {
@@ -226,69 +251,15 @@ namespace QuestPDF.Previewer
         
         public async Task ShowLayoutError(DocumentLayoutException exception)
         {
-            var payload = new ShowLayoutErrorApiRequest
+            var payload = new LayoutErrorApiRequest
             {
                 Trace = exception.ElementTrace
             };
-
-            var jsonSerializerOptions = new JsonSerializerOptions
-            {
-                MaxDepth = 256,
-                Converters =
-                {
-                    new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
-                }
-            };
             
-            await HttpClient.PostAsJsonAsync("/v1/update/error/layout", payload, jsonSerializerOptions);
+            await HttpClient.PostAsJsonAsync("/update/layoutError", payload, JsonSerializerOptions);
         }
         
-
-        
-
-        //
-        // private async Task<Version> GetPreviewerVersion()
-        // {
-        //     using var result = await HttpClient.GetAsync("/version");
-        //     return await result.Content.ReadFromJsonAsync<Version>();
-        // }
-        //
-
-        
-
-        
-        
-        //
-        // 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;
-        //     }
-        // }
+        #endregion
     }
 }