Sfoglia il codice sorgente

refactor(compression): remove legacy Compression class and fix registration

Remove the old Compression class in favor of specific compressor implementations
(GzipCompressor, ZstdCompressor, BrotliCompressor). Fix WebApplication.use_compression()
to use add_component<>() instead of container.register_scoped<>() for proper pipeline
integration.

Also includes:
- Add skip optimization for content ≤ 10 bytes in Compressor base class
- Add default field initializers to compressor classes
- Refactor MarkupNodeList to extend Invercargill.Enumerable with Tracker pattern
- Simplify iteration in DocumentBuilder example
Billy Barrow 1 settimana fa
parent
commit
affb610462

+ 2 - 6
examples/DocumentBuilder.vala

@@ -535,12 +535,8 @@ class XPathDemoEndpoint : Object, Endpoint {
             pre.append_text("(no matches)");
         } else {
             var results_text = new Series<string>();
-            var enumerator = results.iterator();
-            while (enumerator.move_next()) {
-                var node = enumerator.get();
-                if (node != null) {
-                    results_text.add(@"<$(node.tag_name)>");
-                }
+            foreach (var node in results) {
+                results_text.add(@"<$(node.tag_name)>");
             }
             pre.append_text(results_text.to_immutable_buffer()
                 .aggregate<string>("", (acc, s) => acc + (acc == "" ? "" : ", ") + s));

+ 1 - 1
src/Components/BrotliCompressor.vala

@@ -5,7 +5,7 @@ namespace Astralis {
 
     public class BrotliCompressor : Compressor {
 
-        private int _quality;
+        private int _quality = 9;
 
         public BrotliCompressor(int quality = 9, uint64 max_buffer_size = 1024 * 1024 * 16) {
             base(max_buffer_size);

+ 0 - 38
src/Components/Compression.vala

@@ -1,38 +0,0 @@
-
-namespace Astralis {
-
-    public class Compression : Object, PipelineComponent {
-
-        public async HttpResult process_request (HttpContext http_context, PipelineContext pipeline_context) throws Error {
-            var result  = yield pipeline_context.next();
-            var accept_encoding = http_context.request.headers.get_any_or_default("Accept-Encoding");
-            if(accept_encoding != null && accept_encoding.contains("gzip")) {
-                return new CompressionResult (result, ZlibCompressorFormat.GZIP)
-                    .set_header("Content-Encoding", "gzip");
-            }
-            return result;
-        }
-
-        private class CompressionResult : HttpResult {
-            private HttpResult inner_result;
-            private ZlibCompressorFormat format;
-
-            public CompressionResult(HttpResult result, ZlibCompressorFormat format) {
-                base(result.status, result.content_length);
-                replace_headers(result.headers);
-
-                this.inner_result = result;
-                this.format = format;
-            }
-
-            public async override void send_body (AsyncOutput output) throws Error {
-                var converter = new ZlibCompressor(format);
-                var converter_output = new ConverterAsyncOutput(output, converter);
-                yield inner_result.send_body(converter_output);
-            }
-            
-        }
-
-    }
-
-}

+ 6 - 1
src/Components/Compressor.vala

@@ -6,7 +6,7 @@ namespace Astralis {
 
     public abstract class Compressor : Object, PipelineComponent {
 
-        protected uint64 max_buffer_size;
+        protected uint64 max_buffer_size = 1024 * 1024 * 16;
 
         protected Compressor(uint64 max_buffer_size = 1024 * 1024 * 16) {
             this.max_buffer_size = max_buffer_size;
@@ -32,6 +32,11 @@ namespace Astralis {
                 return result;
             }
 
+            // Don't event bother compressing if the length is less than 10 bytes (length of GZip header)
+            if(result.content_length != null && result.content_length <= 10) {
+                return result;
+            }
+
             // Case 1: Content length known and within threshold -> buffer and compress
             if (result.content_length != null && result.content_length <= max_buffer_size) {
                 var buffered_result = yield buffer_and_compress(result);

+ 1 - 1
src/Components/GzipCompressor.vala

@@ -5,7 +5,7 @@ namespace Astralis {
 
     public class GzipCompressor : Compressor {
 
-        private int _compression_level;
+        private int _compression_level = 7;
 
         public GzipCompressor(int compression_level = 7, uint64 max_buffer_size = 1024 * 1024 * 16) {
             base(max_buffer_size);

+ 1 - 1
src/Components/ZstdCompressor.vala

@@ -5,7 +5,7 @@ namespace Astralis {
 
     public class ZstdCompressor : Compressor {
 
-        private int _compression_level;
+        private int _compression_level = 14;
 
         public ZstdCompressor(int compression_level = 14, uint64 max_buffer_size = 1024 * 1024 * 16) {
             base(max_buffer_size);

+ 3 - 3
src/Core/WebApplication.vala

@@ -58,9 +58,9 @@ namespace Astralis {
         }
 
         public void use_compression() {
-            container.register_scoped<GzipCompressor>();
-            container.register_scoped<ZstdCompressor>();
-            container.register_scoped<BrotliCompressor>();
+            add_component<GzipCompressor>();
+            add_component<ZstdCompressor>();
+            add_component<BrotliCompressor>();
         }
     }
 

+ 31 - 18
src/Markup/MarkupNode.vala

@@ -364,7 +364,7 @@ namespace Astralis {
     /// <summary>
     /// A list of HTML nodes supporting iteration and manipulation
     /// </summary>
-    public class MarkupNodeList : GLib.Object {
+    public class MarkupNodeList : Invercargill.Enumerable<MarkupNode> {
         private MarkupDocument document;
         private List<Xml.Node*> nodes;
 
@@ -398,7 +398,7 @@ namespace Astralis {
         /// <summary>
         /// Gets the first node, or null if empty
         /// </summary>
-        public MarkupNode? first {
+        public new MarkupNode? first {
             owned get {
                 if (nodes.is_empty()) {
                     return null;
@@ -411,7 +411,7 @@ namespace Astralis {
         /// <summary>
         /// Gets the last node, or null if empty
         /// </summary>
-        public MarkupNode? last {
+        public new MarkupNode? last {
             owned get {
                 if (nodes.is_empty()) {
                     return null;
@@ -471,44 +471,57 @@ namespace Astralis {
         }
 
         /// <summary>
-        /// Gets an enumerator for iterating over the nodes
+        /// Gets information about this enumerable
         /// </summary>
-        public Enumerator iterator() {
-            return new Enumerator(document, nodes);
+        public override Invercargill.EnumerableInfo get_info() {
+            return new Invercargill.EnumerableInfo.infer_ultimate(this, Invercargill.EnumerableCategory.IN_MEMORY);
         }
 
         /// <summary>
-        /// Enumerator for iterating over MarkupNodeList
+        /// Gets a tracker for iterating over the nodes
         /// </summary>
-        public class Enumerator {
+        public override Invercargill.Tracker<MarkupNode> get_tracker() {
+            return new NodeTracker(document, nodes);
+        }
+
+        /// <summary>
+        /// Peeks at the count without full enumeration
+        /// </summary>
+        public override uint? peek_count() {
+            return (uint)nodes.length();
+        }
+
+        /// <summary>
+        /// Tracker for iterating over MarkupNodeList
+        /// </summary>
+        private class NodeTracker : Invercargill.Tracker<MarkupNode> {
             private MarkupDocument document;
             private unowned List<Xml.Node*> nodes;
             private unowned List<Xml.Node*>? current;
 
-            internal Enumerator(MarkupDocument doc, List<Xml.Node*> nodes) {
+            internal NodeTracker(MarkupDocument doc, List<Xml.Node*> nodes) {
                 this.document = doc;
                 this.nodes = nodes;
                 this.current = null;
             }
 
-            public bool move_next() {
+            public override MarkupNode get_next() {
                 if (current == null) {
                     current = nodes.first();
                 } else {
                     current = current.next;
                 }
-                return current != null;
+                // has_next() should be called before get_next()
+                // Returning null here would violate the non-nullable contract
+                assert(current != null);
+                return new MarkupNode(document, current.data);
             }
 
-            public MarkupNode? get() {
+            public override bool has_next() {
                 if (current == null) {
-                    return null;
+                    return !nodes.is_empty();
                 }
-                return new MarkupNode(document, current.data);
-            }
-
-            public void reset() {
-                current = null;
+                return current.next != null;
             }
         }
     }