made generic, still broken

This commit is contained in:
Jeeves 2024-03-26 16:22:48 -06:00
parent c0511cebe0
commit a9eb927570

View file

@ -10,7 +10,7 @@ pub fn main() !void {
const allocator = gpa.allocator(); const allocator = gpa.allocator();
const address = try net.Address.parseIp("0.0.0.0", 8080); const address = try net.Address.parseIp("0.0.0.0", 8080);
var listener = Listener.init(.{ var listener = App.init(.{
.address = address, .address = address,
.allocator = allocator, .allocator = allocator,
.root_handler = &handleError, .root_handler = &handleError,
@ -18,22 +18,26 @@ pub fn main() !void {
defer listener.deinit(); defer listener.deinit();
try listener.router.putRoute("/", &handle); try listener.router.putRoute("/", &handle);
try listener.router.putRoute("/error", &handleError); // try listener.router.putRoute("/error", &handleError);
try listener.router.putRoute("//pee", &handleError); // try listener.router.putRoute("//pee", &handleError);
try listener.router.putRoute("/error/*", &handleError); // try listener.router.putRoute("/error/*", &handleError);
try listener.listen(); try listener.listen();
} }
pub fn handle(event: *Listener.Event) anyerror!void { pub const App = Listener(DummyContext);
pub const DummyContext = struct {};
pub fn handle(event: *App.Event) anyerror!void {
try event.res.body.appendSlice("hello there"); try event.res.body.appendSlice("hello there");
} }
pub fn handleError(event: *Listener.Event) anyerror!void { pub fn handleError(event: *App.Event) anyerror!void {
try event.res.body.appendSlice("ahoy, an error occurred"); try event.res.body.appendSlice("ahoy, an error occurred");
} }
pub const Listener = struct { pub fn Listener(comptime Context: type) type {
return struct {
allocator: mem.Allocator, allocator: mem.Allocator,
/// Listen address /// Listen address
@ -48,7 +52,9 @@ pub const Listener = struct {
root_handler: HandlerFn, root_handler: HandlerFn,
}; };
pub fn init(options: Options) Listener { const Self = @This();
pub fn init(options: Options) Self {
return .{ return .{
.address = options.address, .address = options.address,
.allocator = options.allocator, .allocator = options.allocator,
@ -56,12 +62,12 @@ pub const Listener = struct {
}; };
} }
pub fn deinit(self: *Listener) void { pub fn deinit(self: *Self) void {
self.router.deinit(); self.router.deinit();
} }
/// Listens for new connections forever /// Listens for new connections forever
pub fn listen(self: *Listener) !void { pub fn listen(self: *Self) !void {
var arena = heap.ArenaAllocator.init(self.allocator); var arena = heap.ArenaAllocator.init(self.allocator);
defer arena.deinit(); defer arena.deinit();
@ -78,11 +84,13 @@ pub const Listener = struct {
} }
} }
fn handle(self: *Listener, server: *http.Server, allocator: mem.Allocator) !void { fn handle(self: *Self, server: *http.Server, allocator: mem.Allocator) !void {
handler: while (true) { handler: while (true) {
var req = server.receiveHead() catch |e| if (e == error.HttpConnectionClosing) break :handler else return e; var req = server.receiveHead() catch |e| if (e == error.HttpConnectionClosing) break :handler else return e;
var ctx = Context{};
var event = Event{ var event = Event{
.ctx = &ctx,
.req = .{ .req = .{
.uri = try std.Uri.parseWithoutScheme(req.head.target), .uri = try std.Uri.parseWithoutScheme(req.head.target),
.headers = std.ArrayList(*const http.Header).init(allocator), .headers = std.ArrayList(*const http.Header).init(allocator),
@ -97,7 +105,8 @@ pub const Listener = struct {
var header_it = req.iterateHeaders(); var header_it = req.iterateHeaders();
while (header_it.next()) |header| try event.req.headers.append(&header); while (header_it.next()) |header| try event.req.headers.append(&header);
try self.router.handle(&event); const route = try self.router.getRoute(event.req.uri.path);
try route.handler(&event);
try respondFromEvent(&event, &req, allocator); try respondFromEvent(&event, &req, allocator);
} }
@ -117,6 +126,7 @@ pub const Listener = struct {
/// Single request-response context /// Single request-response context
pub const Event = struct { pub const Event = struct {
ctx: *Context,
req: Request, req: Request,
res: Response, res: Response,
@ -157,15 +167,15 @@ pub const Listener = struct {
} }
pub fn deinit(self: *Router) void { pub fn deinit(self: *Router) void {
self.root_node.deinit(self.arena.allocator()); self.root_node.deinit(self.arena.allocator(), null);
self.arena.deinit(); self.arena.deinit();
// self.static_routes.deinit(); // self.static_routes.deinit();
} }
pub fn handle(self: *Router, event: *Listener.Event) !void { // pub fn handle(self: *Router, event: *Listener.Event) !void {
const route = try self.getRoute(event.req.uri.path); // const route = try self.getRoute(event.req.uri.path);
try route.handler(event); // try route.handler(event);
} // }
/// Insert a route if the path is not already present, otherwise overwrite preexisting HandlerFn. /// Insert a route if the path is not already present, otherwise overwrite preexisting HandlerFn.
pub fn putRoute(self: *Router, path: []const u8, handler: HandlerFn) !void { pub fn putRoute(self: *Router, path: []const u8, handler: HandlerFn) !void {
@ -357,51 +367,54 @@ pub const Listener = struct {
pub fn deinit(self: *Node, allocator: mem.Allocator, section: ?[]const u8) void { pub fn deinit(self: *Node, allocator: mem.Allocator, section: ?[]const u8) void {
std.debug.print("deiniting node with {d} children.. and {d} placeholder_children\n", .{ self.children.count(), self.placeholder_children.items.len }); std.debug.print("deiniting node with {d} children.. and {d} placeholder_children\n", .{ self.children.count(), self.placeholder_children.items.len });
if (section) |sec| if (self.parent) |parent| parent.children.remove(sec); if (section) |sec| if (self.parent) |parent| {
_ = parent.children.remove(sec);
};
for (self.placeholder_children.items) |child| std.debug.print("child {any}\n", .{child}); // child.deinit(allocator); for (self.placeholder_children.items) |child| std.debug.print("child {any}\n", .{child}); // child.deinit(allocator);
self.placeholder_children.deinit(); self.placeholder_children.deinit();
var child_it = self.children.valueIterator(); var child_it = self.children.valueIterator();
while (child_it.next()) |child| child.*.deinit(allocator); while (child_it.next()) |child| child.*.deinit(allocator, section);
self.children.deinit(); self.children.deinit();
allocator.destroy(self); allocator.destroy(self);
} }
}; };
}; };
}; };
test "Router" {
var router = Listener.Router.init(std.testing.allocator, &dummyHandler);
defer router.deinit();
try router.putRoute("/foo", &hummyDandler);
try router.putRoute("/foo/bar", &hummyDandler);
try router.putRoute("/foo/foobar", &tummyCandler);
try router.putRoute("/bar", &hummyDandler);
try std.testing.expectEqual(&dummyHandler, (try router.getRoute("/")).handler);
try std.testing.expectEqual(&hummyDandler, (try router.getRoute("/foo")).handler);
try std.testing.expectEqual(&hummyDandler, (try router.getRoute("/foo/bar")).handler);
try std.testing.expectEqual(&tummyCandler, (try router.getRoute("/foo/foobar")).handler);
try std.testing.expectEqual(&hummyDandler, (try router.getRoute("/bar")).handler);
try std.testing.expect(router.removeRoute("/foo"));
try std.testing.expectEqual(&dummyHandler, (try router.getRoute("/foo/bar")).handler);
try std.testing.expectEqual(&dummyHandler, (try router.getRoute("/foo")).handler);
try std.testing.expectEqual(&dummyHandler, (try router.getRoute("/")).handler);
try router.putRoute("/foo", &hummyDandler);
try router.putRoute("/foo/**", &tummyCandler);
try router.putRoute("/bar/*", &tummyCandler);
try std.testing.expectEqual(&hummyDandler, (try router.getRoute("/foo")).handler);
try std.testing.expectEqual(&tummyCandler, (try router.getRoute("/foo/bar")).handler);
try std.testing.expectEqual(&tummyCandler, (try router.getRoute("/foo/bar/foo")).handler);
try std.testing.expectEqual(&tummyCandler, (try router.getRoute("/foo/foof")).handler);
try std.testing.expect(router.removeRoute("/bar/*"));
} }
fn dummyHandler(_: *Listener.Event) anyerror!void {} // test "Router" {
fn hummyDandler(_: *Listener.Event) anyerror!void {} // var router = Listener.Router.init(std.testing.allocator, &dummyHandler);
fn tummyCandler(_: *Listener.Event) anyerror!void {} // defer router.deinit();
// try router.putRoute("/foo", &hummyDandler);
// try router.putRoute("/foo/bar", &hummyDandler);
// try router.putRoute("/foo/foobar", &tummyCandler);
// try router.putRoute("/bar", &hummyDandler);
// try std.testing.expectEqual(&dummyHandler, (try router.getRoute("/")).handler);
// try std.testing.expectEqual(&hummyDandler, (try router.getRoute("/foo")).handler);
// try std.testing.expectEqual(&hummyDandler, (try router.getRoute("/foo/bar")).handler);
// try std.testing.expectEqual(&tummyCandler, (try router.getRoute("/foo/foobar")).handler);
// try std.testing.expectEqual(&hummyDandler, (try router.getRoute("/bar")).handler);
// try std.testing.expect(router.removeRoute("/foo"));
// try std.testing.expectEqual(&dummyHandler, (try router.getRoute("/foo/bar")).handler);
// try std.testing.expectEqual(&dummyHandler, (try router.getRoute("/foo")).handler);
// try std.testing.expectEqual(&dummyHandler, (try router.getRoute("/")).handler);
// try router.putRoute("/foo", &hummyDandler);
// try router.putRoute("/foo/**", &tummyCandler);
// try router.putRoute("/bar/*", &tummyCandler);
// try std.testing.expectEqual(&hummyDandler, (try router.getRoute("/foo")).handler);
// try std.testing.expectEqual(&tummyCandler, (try router.getRoute("/foo/bar")).handler);
// try std.testing.expectEqual(&tummyCandler, (try router.getRoute("/foo/bar/foo")).handler);
// try std.testing.expectEqual(&tummyCandler, (try router.getRoute("/foo/foof")).handler);
// try std.testing.expect(router.removeRoute("/bar/*"));
// }
// fn dummyHandler(_: *Listener.Event) anyerror!void {}
// fn hummyDandler(_: *Listener.Event) anyerror!void {}
// fn tummyCandler(_: *Listener.Event) anyerror!void {}