this ain't it either, chief

This commit is contained in:
Jeeves 2024-03-25 16:33:38 -06:00
parent 65a426a786
commit f0f072ebab

View file

@ -4,34 +4,57 @@ const net = std.net;
const http = std.http;
const heap = std.heap;
const App = Listener(Router);
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const router = BasicRouter.init(allocator);
var router = Router.init(allocator, &handle, &handleError);
defer router.deinit();
try router.addRoute("/", &handle);
const address = try net.Address.parseIp("0.0.0.0", 8080);
var listener = Listener.init(address, allocator, &handle);
var listener = App.init(.{
.address = address,
.allocator = allocator,
.context = router,
.handler = router.handle,
});
defer listener.deinit();
try listener.listen();
}
pub fn handle(event: *Listener.Event) anyerror!void {
pub fn handle(_: *Router, event: *App.Event) anyerror!void {
try event.res.body.appendSlice("hello there");
}
pub const Listener = struct {
pub fn handleError(_: Router, event: *App.Event) anyerror!void {
try event.res.body.appendSlice("ahoy, an error occurred");
}
pub fn Listener(comptime Context: type) type {
return struct {
address: net.Address,
arena: heap.ArenaAllocator,
handlerFn: *const fn (event: *Event) anyerror!void,
ctx: *Context,
handlerFn: HandlerFn,
pub fn init(address: net.Address, allocator: mem.Allocator, handler: *const fn (event: *Event) anyerror!void) Listener {
pub const Options = struct {
address: net.Address,
allocator: mem.Allocator,
context: *Context,
handler: HandlerFn,
};
pub fn init(options: Options) Listener {
return .{
.address = address,
.arena = heap.ArenaAllocator.init(allocator),
.handlerFn = handler,
.address = options.address,
.arena = heap.ArenaAllocator.init(options.allocator),
.ctx = options.context,
.handlerFn = options.handler,
};
}
@ -72,7 +95,7 @@ pub const Listener = struct {
var header_it = req.iterateHeaders();
while (header_it.next()) |header| try event.req.headers.append(&header);
try self.handlerFn(&event);
try self.handlerFn(self.ctx, &event);
try self.respondFromEvent(&event, &req);
}
@ -105,34 +128,47 @@ pub const Listener = struct {
body: std.ArrayList(u8),
};
};
};
pub const BasicRouter = Router(Listener.Event);
pub fn Router(comptime Context: type) type {
return struct {
ctx: Context,
allocator: mem.Allocator,
static_routes: std.StringHashMap(*Node),
pub fn init(allocator: mem.Allocator, ctx: Context) Self {
return .{
.ctx = ctx,
.allocator = allocator,
.static_routes = std.StringHashMap(*Node).init(allocator),
pub const HandlerFn = *const fn (ctx: *Context, event: *Event) anyerror!void;
};
}
pub fn deinit(self: *Self) void {
pub const Router = struct {
allocator: mem.Allocator,
root_node: Node,
static_routes: std.StringHashMap(*Node),
error_handler: HandlerFn,
pub fn init(allocator: mem.Allocator, root_handler: HandlerFn, error_handler: HandlerFn) Router {
return .{
.allocator = allocator,
.root_node = .{
.type = .normal,
.max_depth = 64,
.children = std.StringHashMap(*Node).init(allocator),
.handler = root_handler,
.placeholder_children = std.ArrayList(*Node).init(allocator),
},
.static_routes = std.StringHashMap(*Node).init(allocator),
.error_handler = error_handler,
};
}
pub fn deinit(self: *Router) void {
self.static_routes.deinit();
}
pub fn addRoute(self: *Self, path: []const u8, handler: HandlerFn) !void {
pub fn handle(self: *Router, event: *Listener.Event) anyerror!void {
try self.route(event.req.uri.path)(self, event);
}
pub fn addRoute(self: *Router, path: []const u8, handler: HandlerFn) !void {
try self.addStaticRoute(path, handler);
}
fn addStaticRoute(self: *Self, path: []const u8, handler: HandlerFn) !void {
fn addStaticRoute(self: *Router, path: []const u8, handler: HandlerFn) !void {
try self.static_routes.put(path, .{
.type = .normal,
.max_depth = 1,
@ -142,6 +178,12 @@ pub fn Router(comptime Context: type) type {
});
}
pub fn route(self: *Router, path: []const u8) HandlerFn {
if (self.static_routes.get(path)) |rt| return rt.handler;
if (self.root_node.wildcard_child_node) |node| return node.handler;
return self.error_handler;
}
pub const Node = struct {
type: Type,
max_depth: usize, // TODO: what is best here
@ -154,8 +196,5 @@ pub fn Router(comptime Context: type) type {
pub const Type = enum { normal, wildcard, placeholder };
};
pub const HandlerFn = *const fn (ctx: *Context) anyerror!void;
const Self = @This();
pub const HandlerFn = *const fn (self: *Router, event: *App.Event) anyerror!void;
};
}