From 267bf440177dd0d974b4b23289bb41b7f70a7381 Mon Sep 17 00:00:00 2001 From: rimuspp Date: Wed, 7 Feb 2024 12:54:54 +0000 Subject: [PATCH] Middleware created --- src/app/views/zmpl.manifest.zig | 2 +- src/jetzig/http/Server.zig | 46 ++++++++++++++++++++++++++++++--- src/main.zig | 40 ++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/app/views/zmpl.manifest.zig b/src/app/views/zmpl.manifest.zig index 15cbd97..3fec5f6 100644 --- a/src/app/views/zmpl.manifest.zig +++ b/src/app/views/zmpl.manifest.zig @@ -3,6 +3,6 @@ // This file should _not_ be stored in version control. pub const templates = struct { pub const index = @import(".index.zmpl.compiled.zig"); - pub const quotes_get = @import("quotes/.get.zmpl.compiled.zig"); pub const users_get = @import("users/.get.zmpl.compiled.zig"); + pub const quotes_get = @import("quotes/.get.zmpl.compiled.zig"); }; diff --git a/src/jetzig/http/Server.zig b/src/jetzig/http/Server.zig index ec52d75..daed29f 100644 --- a/src/jetzig/http/Server.zig +++ b/src/jetzig/http/Server.zig @@ -2,6 +2,10 @@ const std = @import("std"); const jetzig = @import("../../jetzig.zig"); +const root_file = @import("root"); +const jetzig_server_options = if (@hasDecl(root_file, "jetzig_options")) root_file.jetzig_options else struct {}; +const middlewares: []const type = jetzig_server_options.middleware; + pub const ServerOptions = struct { cache: jetzig.caches.Cache, logger: jetzig.loggers.Logger, @@ -30,7 +34,7 @@ pub fn init( routes: []jetzig.views.Route, templates: []jetzig.TemplateFn, ) Self { - const server = std.http.Server.init( .{ .reuse_address = true }); + const server = std.http.Server.init(.{ .reuse_address = true }); return .{ .server = server, @@ -93,9 +97,36 @@ fn processNextRequest(self: *Self, response: *std.http.Server.Response) !void { var request = try jetzig.http.Request.init(arena.allocator(), self, response); defer request.deinit(); - const result = try self.pageContent(&request); + var middleware_data = std.BoundedArray(*anyopaque, middlewares.len).init(0) catch unreachable; + inline for (middlewares, 0..) |middleware, i| { + if (comptime !@hasDecl(middleware, "init")) continue; + const data = try @call(.always_inline, middleware.init, .{&request}); + middleware_data.insert(i, data) catch unreachable; // We cannot overflow here because we know the length of the array + } + + inline for (middlewares, 0..) |middleware, i| { + if (comptime !@hasDecl(middleware, "beforeRequest")) continue; + if (comptime @hasDecl(middleware, "init")) { + const data = middleware_data.get(i); + try @call(.always_inline, middleware.beforeRequest, .{ @as(*middleware, @ptrCast(@alignCast(data))), &request }); + } else { + try @call(.always_inline, middleware.beforeRequest, .{&request}); + } + } + + var result = try self.pageContent(&request); defer result.deinit(); + inline for (middlewares, 0..) |middleware, i| { + if (comptime !@hasDecl(middleware, "afterRequest")) continue; + if (comptime @hasDecl(middleware, "init")) { + const data = middleware_data.get(i); + try @call(.always_inline, middleware.afterRequest, .{ @as(*middleware, @ptrCast(@alignCast(data))), &request, &result }); + } else { + try @call(.always_inline, middleware.afterRequest, .{ &request, &result }); + } + } + response.transfer_encoding = .{ .content_length = result.value.content.len }; var cookie_it = request.cookies.headerIterator(); while (try cookie_it.next()) |header| { @@ -114,6 +145,15 @@ fn processNextRequest(self: *Self, response: *std.http.Server.Response) !void { const log_message = try self.requestLogMessage(&request, result); defer self.allocator.free(log_message); self.logger.debug("{s}", .{log_message}); + + inline for (middlewares, 0..) |middleware, i| { + if (comptime @hasDecl(middleware, "init")) { + if (comptime @hasDecl(middleware, "deinit")) { + const data = middleware_data.get(i); + @call(.always_inline, middleware.deinit, .{ @as(*middleware, @ptrCast(@alignCast(data))), &request }); + } + } + } } fn pageContent(self: *Self, request: *jetzig.http.Request) !jetzig.caches.Result { @@ -307,7 +347,7 @@ fn matchStaticResource(self: *Self, request: *jetzig.http.Request) !?StaticResou if (request.path.len < 2) return null; if (request.method != .GET) return null; - var iterable_dir = std.fs.cwd().openDir("public", .{.iterate = true}) catch |err| { + var iterable_dir = std.fs.cwd().openDir("public", .{ .iterate = true }) catch |err| { switch (err) { error.FileNotFound => return null, else => return err, diff --git a/src/main.zig b/src/main.zig index 72b2899..aecd608 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4,6 +4,10 @@ pub const jetzig = @import("jetzig"); pub const templates = @import("app/views/zmpl.manifest.zig").templates; pub const routes = @import("app/views/routes.zig").routes; +pub const jetzig_options = struct { + pub const middleware: []const type = &.{ TestMiddleware, IncompleteMiddleware, IncompleteMiddleware2 }; +}; + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer std.debug.assert(gpa.deinit() == .ok); @@ -17,3 +21,39 @@ pub fn main() !void { comptime jetzig.loadTemplates(templates), ); } + +const TestMiddleware = struct { + my_data: u8, + pub fn init(request: *jetzig.http.Request) !*TestMiddleware { + var mw = try request.allocator.create(TestMiddleware); + mw.my_data = 42; + return mw; + } + + pub fn beforeRequest(middleware: *TestMiddleware, request: *jetzig.http.Request) !void { + request.server.logger.debug("Before request, custom data: {d}", .{middleware.my_data}); + middleware.my_data = 43; + } + + pub fn afterRequest(middleware: *TestMiddleware, request: *jetzig.http.Request, result: *jetzig.caches.Result) !void { + request.server.logger.debug("After request, custom data: {d}", .{middleware.my_data}); + request.server.logger.debug("{s}", .{result.value.content}); + } + + pub fn deinit(middleware: *TestMiddleware, request: *jetzig.http.Request) void { + request.allocator.destroy(middleware); + } +}; + +const IncompleteMiddleware = struct { + pub fn beforeRequest(request: *jetzig.http.Request) !void { + request.server.logger.debug("Before request", .{}); + } +}; + +const IncompleteMiddleware2 = struct { + pub fn afterRequest(request: *jetzig.http.Request, result: *jetzig.caches.Result) !void { + request.server.logger.debug("After request", .{}); + _ = result; + } +};