create more zig-friendly request interface

This commit is contained in:
Emil Lerch 2023-05-30 16:03:40 -07:00
parent 31bece93fc
commit 76497fe22c
Signed by: lobo
GPG Key ID: A7B62D657EF764F8
2 changed files with 33 additions and 7 deletions

View File

@ -1,5 +1,6 @@
const std = @import("std"); const std = @import("std");
// C interfaces between main and libraries
pub const Header = extern struct { pub const Header = extern struct {
name_ptr: [*]u8, name_ptr: [*]u8,
name_len: usize, name_len: usize,
@ -26,6 +27,13 @@ pub const Request = extern struct {
headers_len: usize, headers_len: usize,
}; };
// If the library is Zig, we can use these helpers
pub const ZigRequest = struct {
method: [:0]u8,
content: []u8,
headers: []Header,
};
pub fn toHeaders(alloc: std.mem.Allocator, headers: std.StringHashMap([]const u8)) ![*]Header { pub fn toHeaders(alloc: std.mem.Allocator, headers: std.StringHashMap([]const u8)) ![*]Header {
var header_array = try std.ArrayList(Header).initCapacity(alloc, headers.count()); var header_array = try std.ArrayList(Header).initCapacity(alloc, headers.count());
var iterator = headers.iterator(); var iterator = headers.iterator();
@ -56,7 +64,7 @@ pub fn zigInit(parent_allocator: *anyopaque) callconv(.C) void {
allocator = @ptrCast(*std.mem.Allocator, @alignCast(@alignOf(*std.mem.Allocator), parent_allocator)); allocator = @ptrCast(*std.mem.Allocator, @alignCast(@alignOf(*std.mem.Allocator), parent_allocator));
} }
pub const ZigRequestHandler = *const fn (std.mem.Allocator, Request, ZigResponse) anyerror!void; pub const ZigRequestHandler = *const fn (std.mem.Allocator, ZigRequest, ZigResponse) anyerror!void;
const log = std.log.scoped(.interface); const log = std.log.scoped(.interface);
pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?*Response { pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?*Response {
@ -69,10 +77,18 @@ pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?*
// setup headers // setup headers
var headers = std.StringHashMap([]const u8).init(alloc); var headers = std.StringHashMap([]const u8).init(alloc);
zigRequestHandler(alloc, request.*, .{ zigRequestHandler(
alloc,
.{
.method = request.method[0..request.method_len :0],
.content = request.content[0..request.content_len],
.headers = request.headers[0..request.headers_len],
},
.{
.body = &response, .body = &response,
.headers = &headers, .headers = &headers,
}) catch |e| { },
) catch |e| {
log.err("Unexpected error processing request: {any}", .{e}); log.err("Unexpected error processing request: {any}", .{e});
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace.*); std.debug.dumpStackTrace(trace.*);

View File

@ -8,10 +8,20 @@ const log = std.log.scoped(.@"main-lib");
// request. Useful for deallocating memory // request. Useful for deallocating memory
// export fn request_deinit() void { // export fn request_deinit() void {
// } // }
/// handle_request will be called on a single request, but due to the preservation
/// of restrictions imposed by the calling interface, it should generally be more
/// useful to call into the interface library to let it do the conversion work
/// on your behalf
export fn handle_request(request: *interface.Request) callconv(.C) ?*interface.Response { export fn handle_request(request: *interface.Request) callconv(.C) ?*interface.Response {
return interface.handleRequest(request, handleRequest); return interface.handleRequest(request, handleRequest);
} }
// zigInit is an optional export called at the beginning of a request. It will
// be passed an allocator (which...shh...is an arena allocator). Since the
// interface library provides a request handler that requires a built-in allocator,
// if you are using the interface library, you will need to also include this
// export
comptime { comptime {
@export( @export(
interface.zigInit, interface.zigInit,
@ -25,12 +35,12 @@ comptime {
// //
// handleRequest function here is the last line of boilerplate and the // handleRequest function here is the last line of boilerplate and the
// entry to a request // entry to a request
fn handleRequest(allocator: std.mem.Allocator, request: interface.Request, response: interface.ZigResponse) !void { fn handleRequest(allocator: std.mem.Allocator, request: interface.ZigRequest, response: interface.ZigResponse) !void {
_ = allocator; _ = allocator;
// setup // setup
var response_writer = response.body.writer(); var response_writer = response.body.writer();
// real work // real work
response_writer.print(" {d}", .{request.headers_len}) catch unreachable; response_writer.print(" {d}", .{request.headers.len}) catch unreachable;
try response.headers.put("X-custom-foo", "bar"); try response.headers.put("X-custom-foo", "bar");
log.info("handlerequest header count {d}", .{response.headers.count()}); log.info("handlerequest header count {d}", .{response.headers.count()});
} }