From 8cf48ddfc1aea0e0479f5f32228f79e8681a069a Mon Sep 17 00:00:00 2001 From: Rene Schallner Date: Sat, 23 Mar 2024 22:23:13 +0100 Subject: [PATCH 1/8] zig master: exit, get_env fixes --- build.zig | 4 ++-- examples/https/https.zig | 2 +- tools/announceybot.zig | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.zig b/build.zig index 85e6b1a..4fb6eaa 100644 --- a/build.zig +++ b/build.zig @@ -5,7 +5,7 @@ pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); if (target.result.os.tag == .windows) { std.log.err("\x1b[31mPlatform Not Supported\x1b[0m\nCurrently, Facil.io and Zap are not compatible with Windows. Consider using Linux or Windows Subsystem for Linux (WSL) instead.\nFor more information, please see:\n- https://github.com/zigzap/zap#most-faq\n- https://facil.io/#forking-contributing-and-all-that-jazz\n", .{}); - std.os.exit(1); + std.process.exit(1); } // Standard release options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. @@ -13,7 +13,7 @@ pub fn build(b: *std.Build) !void { const use_openssl = b.option(bool, "openssl", "Use system-installed openssl for TLS support in zap") orelse blk: { // Alternatively, use an os env var to determine whether to build openssl support - if (std.os.getenv("ZAP_USE_OPENSSL")) |val| { + if (std.posix.getenv("ZAP_USE_OPENSSL")) |val| { if (std.mem.eql(u8, val, "true")) break :blk true; } break :blk false; diff --git a/examples/https/https.zig b/examples/https/https.zig index 88c53a7..aeb7930 100644 --- a/examples/https/https.zig +++ b/examples/https/https.zig @@ -30,7 +30,7 @@ fn help_and_exit(filename: []const u8, err: anyerror) void { , .{ filename, err }, ); - std.os.exit(1); + std.process.exit(1); } pub fn main() !void { const CERT_FILE = "mycert.pem"; diff --git a/tools/announceybot.zig b/tools/announceybot.zig index 071085e..2b7e835 100644 --- a/tools/announceybot.zig +++ b/tools/announceybot.zig @@ -28,7 +28,7 @@ fn usage() void { \\ instructions ; std.debug.print("{s}", .{message}); - std.os.exit(1); + std.process.exit(1); } var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; @@ -336,7 +336,7 @@ fn command_announce(allocator: std.mem.Allocator, tag: []const u8) !void { defer allocator.free(url); sendToDiscord(allocator, url, announcement) catch |err| { std.debug.print("HTTP ERROR: {any}\n", .{err}); - std.os.exit(1); + std.process.exit(1); }; } From b2f4e292582c20f0d20bffa3a96aaae22dda628a Mon Sep 17 00:00:00 2001 From: Rene Schallner Date: Sat, 23 Mar 2024 22:35:49 +0100 Subject: [PATCH 2/8] re-write of zap.Router, fix #83 --- examples/simple_router/simple_router.zig | 10 +-- src/router.zig | 81 ++++++++++++++++++++---- src/util.zig | 17 ----- 3 files changed, 74 insertions(+), 34 deletions(-) diff --git a/examples/simple_router/simple_router.zig b/examples/simple_router/simple_router.zig index acff407..eb58839 100644 --- a/examples/simple_router/simple_router.zig +++ b/examples/simple_router/simple_router.zig @@ -82,17 +82,17 @@ pub fn main() !void { var somePackage = SomePackage.init(allocator, 1, 2); - try simpleRouter.handle_func("/", on_request_verbose); + try simpleRouter.handle_func_unbound("/", on_request_verbose); - try simpleRouter.handle_func("/geta", zap.RequestHandler(&somePackage, SomePackage.getA)); + try simpleRouter.handle_func("/geta", &somePackage, &SomePackage.getA); - try simpleRouter.handle_func("/getb", zap.RequestHandler(&somePackage, SomePackage.getB)); + try simpleRouter.handle_func("/getb", &somePackage, &SomePackage.getB); - try simpleRouter.handle_func("/inca", zap.RequestHandler(&somePackage, SomePackage.incrementA)); + try simpleRouter.handle_func("/inca", &somePackage, &SomePackage.incrementA); var listener = zap.HttpListener.init(.{ .port = 3000, - .on_request = zap.RequestHandler(&simpleRouter, &zap.Router.serve), + .on_request = simpleRouter.on_request_handler(), .log = true, .max_clients = 100000, }); diff --git a/src/router.zig b/src/router.zig index 6b490c3..c9ca7d5 100644 --- a/src/router.zig +++ b/src/router.zig @@ -2,6 +2,8 @@ const std = @import("std"); const zap = @import("zap.zig"); const Allocator = std.mem.Allocator; + +/// Errors returnable by init() const RouterError = error{ AlreadyExists, EmptyPath, @@ -9,46 +11,101 @@ const RouterError = error{ const Self = @This(); +/// This is a singleton +var _instance: *Self = undefined; + +/// Options to pass to init() pub const Options = struct { + /// an optional zap request function for 404 not found case not_found: ?zap.HttpRequestFn = null, }; -routes: std.StringHashMap(zap.HttpRequestFn), +const CallbackTag = enum { bound, unbound }; +const BoundHandler = *fn (*const anyopaque, zap.Request) void; +const Callback = union(CallbackTag) { + bound: struct { instance: usize, handler: usize }, + unbound: zap.HttpRequestFn, +}; + +routes: std.StringHashMap(Callback), not_found: ?zap.HttpRequestFn, +/// Create a new Router pub fn init(allocator: Allocator, options: Options) Self { return .{ - .routes = std.StringHashMap(zap.HttpRequestFn).init(allocator), + .routes = std.StringHashMap(Callback).init(allocator), .not_found = options.not_found, }; } +/// Deinit the router pub fn deinit(self: *Self) void { self.routes.deinit(); } -pub fn handle_func(self: *Self, path: []const u8, h: zap.HttpRequestFn) !void { +/// Call this to add a route with an unbound handler: a handler that is not member of a struct. +pub fn handle_func_unbound(self: *Self, path: []const u8, h: zap.HttpRequestFn) !void { if (path.len == 0) { return RouterError.EmptyPath; } - const route = self.routes.get(path); - - if (route != null) { + if (self.routes.contains(path)) { return RouterError.AlreadyExists; } - try self.routes.put(path, h); + try self.routes.put(path, Callback{ .unbound = h }); } -pub fn serve(self: *Self, r: zap.Request) void { - const path = if (r.path) |p| p else "/"; +/// Call this to add a route with a handler that is bound to an instance of a struct. +/// Example: +/// +/// ```zig +/// const HandlerType = struct { +/// pub fn getA(self: *HandlerType, r: zap.Request) void { +/// _ = self; +/// r.sendBody("hello\n\n") catch return; +/// } +/// } +/// var handler_instance = HandlerType{}; +/// +/// my_router.handle_func("/getA", &handler_instance, HandlerType.getA); +/// ``` +pub fn handle_func(self: *Self, path: []const u8, instance: *anyopaque, handler: anytype) !void { + // TODO: assert type of instance has handler - const route = self.routes.get(path); + if (path.len == 0) { + return RouterError.EmptyPath; + } - if (route) |handler| { - handler(r); + if (self.routes.contains(path)) { + return RouterError.AlreadyExists; + } + + try self.routes.put(path, Callback{ .bound = .{ + .instance = @intFromPtr(instance), + .handler = @intFromPtr(handler), + } }); +} + +/// Get the zap request handler function needed for a listener +pub fn on_request_handler(self: *Self) zap.HttpRequestFn { + _instance = self; + return zap_on_request; +} + +fn zap_on_request(r: zap.Request) void { + return serve(_instance, r); +} + +fn serve(self: *Self, r: zap.Request) void { + const path = r.path orelse "/"; + + if (self.routes.get(path)) |routeInfo| { + switch (routeInfo) { + .bound => |b| @call(.auto, @as(BoundHandler, @ptrFromInt(b.handler)), .{ @as(*anyopaque, @ptrFromInt(b.instance)), r }), + .unbound => |h| h(r), + } } else if (self.not_found) |handler| { // not found handler handler(r); diff --git a/src/util.zig b/src/util.zig index 21e9eaf..4b6a4c9 100644 --- a/src/util.zig +++ b/src/util.zig @@ -2,23 +2,6 @@ const std = @import("std"); const fio = @import("fio.zig"); const zap = @import("zap.zig"); -/// capture self for RequestFn signature support -pub inline fn RequestHandler(self: anytype, func: *const fn (@TypeOf(self), zap.Request) void) *const fn (zap.Request) void { - return (opaque { - var hidden_self: @TypeOf(self) = undefined; - var hidden_func: *const fn (@TypeOf(self), zap.Request) void = undefined; - pub fn init(h_self: @TypeOf(self), h_func: *const fn (@TypeOf(self), zap.Request) void) *const @TypeOf(run) { - hidden_self = h_self; - hidden_func = h_func; - return &run; - } - - fn run(req: zap.Request) void { - hidden_func(hidden_self, req); - } - }).init(self, func); -} - /// Used internally: convert a FIO object into its string representation. /// note: since this is called from within request functions, we don't make /// copies. Also, we return temp memory from fio. -> don't hold on to it outside From b718bc3f5a24f7d4c883c7313c55aa376a09a751 Mon Sep 17 00:00:00 2001 From: Rene Schallner Date: Sat, 23 Mar 2024 22:50:03 +0100 Subject: [PATCH 3/8] update docs --- docs/index.html | 1364 ++--------- docs/main.js | 6013 +++++++--------------------------------------- docs/main.wasm | Bin 0 -> 198203 bytes docs/sources.tar | Bin 0 -> 542208 bytes 4 files changed, 1146 insertions(+), 6231 deletions(-) create mode 100755 docs/main.wasm create mode 100644 docs/sources.tar diff --git a/docs/index.html b/docs/index.html index 73f903d..2238013 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,476 +1,158 @@ - + - - Documentation - Zig - + Zig Documentation - - - - -