From 6340cb0cbedeee0e771801568510532f164f31ba Mon Sep 17 00:00:00 2001
From: Jeeves <guydoodlesdev@gmail.com>
Date: Mon, 3 Mar 2025 18:36:50 -0700
Subject: [PATCH] idk

---
 build.zig    |   2 +-
 src/main.zig |  47 +++++++++---------
 src/root.zig | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+), 24 deletions(-)
 create mode 100644 src/root.zig

diff --git a/build.zig b/build.zig
index 728c5ec..252b74f 100644
--- a/build.zig
+++ b/build.zig
@@ -5,7 +5,7 @@ pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const exe = b.addExecutable(.{
-        .name = "master",
+        .name = "httz",
         .root_source_file = b.path("src/main.zig"),
         .target = target,
         .optimize = optimize,
diff --git a/src/main.zig b/src/main.zig
index d95621b..5ede761 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,43 +1,44 @@
 const std = @import("std");
-const mem = std.mem;
 const net = std.net;
-const http = std.http;
-const heap = std.heap;
 
-pub const Application = @import("application.zig").Application;
+const Listener = @import("root.zig").Listener(Context);
+const Request = Listener.Request;
+const Response = Listener.Response;
+
+const Context = struct {};
 
 pub fn main() !void {
     var gpa = std.heap.GeneralPurposeAllocator(.{}){};
     defer _ = gpa.deinit();
     const allocator = gpa.allocator();
 
-    var router = Router.init(allocator, handleError);
-    defer router.deinit();
-
-    try router.putRoute("/", &handle);
-    // try listener.router.putRoute("/error", &handleError);
-    // try listener.router.putRoute("//pee", &handleError);
-    // try listener.router.putRoute("/error/*", &handleError);
-
-    const address = try net.Address.parseIp("0.0.0.0", 8080);
-    var listener = App.init(.{
+    const address = net.Address.initIp4(.{ 127, 0, 0, 1 }, 8080);
+    const listener = try Listener.init(.{
         .address = address,
         .allocator = allocator,
-        // .root_handler = ,
+        .handler = handle,
+        .errorHandler = handleError,
     });
     defer listener.deinit();
 
+    try std.io.getStdErr().writer().print("listening at {}\n", .{address});
     try listener.listen();
 }
 
-const App = Application(DummyContext);
-const Router = @import("application.zig").Router(App.HandlerFn);
-const DummyContext = struct {};
-
-fn handle(event: *App.Event) anyerror!void {
-    try event.res.body.appendSlice("hello there");
+fn handle(req: *const Request) anyerror!Response {
+    if (std.mem.eql(u8, req.uri.path.percent_encoded, "/")) {
+        return .{ .body = "home!" };
+    } else {
+        return .{ .body = "somewhere else!" };
+    }
 }
 
-fn handleError(event: *App.Event) anyerror!void {
-    try event.res.body.appendSlice("ahoy, an error occurred");
+fn handleError(_: *const Request, err: [:0]const u8) anyerror!Response {
+    return .{
+        .body = "oops! something went wrong on the server side.",
+        .options = .{
+            .status = .internal_server_error,
+            .reason = err,
+        },
+    };
 }
diff --git a/src/root.zig b/src/root.zig
new file mode 100644
index 0000000..ad8b365
--- /dev/null
+++ b/src/root.zig
@@ -0,0 +1,137 @@
+const std = @import("std");
+const mem = std.mem;
+const net = std.net;
+// const http = std.http;
+
+pub fn Listener(comptime Context: type) type {
+    _ = Context;
+    return struct {
+        // ctx: *Context,
+        server: *net.Server,
+        allocator: mem.Allocator,
+        handler: HandlerFn,
+        errorHandler: ErrorHandlerFn,
+
+        pub const InitOptions = struct {
+            address: net.Address,
+            allocator: mem.Allocator,
+            listen_options: net.Address.ListenOptions = .{ .reuse_address = true },
+            handler: HandlerFn,
+            errorHandler: ErrorHandlerFn,
+        };
+
+        pub fn init(options: InitOptions) !Self {
+            var server = try options.address.listen(options.listen_options);
+            return .{
+                // .ctx = options.ctx,
+                .server = &server,
+                .allocator = options.allocator,
+                .handler = options.handler,
+                .errorHandler = options.errorHandler,
+            };
+        }
+
+        pub fn deinit(self: Self) void {
+            self.server.deinit();
+        }
+
+        pub fn listen(self: Self) !void {
+            while (true) {
+                const read_buf = try self.allocator.alloc(u8, 1024 * 32);
+                defer self.allocator.free(read_buf);
+
+                const connection = try self.server.accept();
+                defer connection.stream.close();
+
+                var http = std.http.Server.init(connection, read_buf);
+                http: while (true) {
+                    var req = http.receiveHead() catch |e| if (e == error.HttpConnectionClosing) break :http else return e;
+                    const request = Request{
+                        .uri = try std.Uri.parseAfterScheme("http://", req.head.target),
+                        .http = &req,
+                    };
+                    const res: Response = self.handler(&request) catch |e| blk: {
+                        break :blk self.errorHandler(&request, @errorName(e)) catch |err| {
+                            try req.respond("ahoy, an internal error occurred.", .{
+                                .status = .internal_server_error,
+                                .reason = @errorName(err),
+                            });
+                            continue :http;
+                        };
+                    };
+                    try req.respond(res.body, res.options);
+                }
+            }
+        }
+
+        pub const Request = struct {
+            uri: std.Uri,
+            http: *std.http.Server.Request,
+        };
+
+        pub const Response = struct {
+            options: std.http.Server.Request.RespondOptions = .{},
+            body: []const u8,
+        };
+
+        const Self = @This();
+
+        pub const HandlerFn = *const fn (req: *const Request) anyerror!Response;
+        pub const ErrorHandlerFn = *const fn (req: *const Request, err: [:0]const u8) anyerror!Response;
+
+        // pub const Router = struct {
+        //     static_routes: std.StringHashMap(HandlerFn),
+
+        //     fallback_handler: HandlerFn,
+        //     error_handler: HandlerFn,
+
+        //     allocator: mem.Allocator,
+
+        //     pub const Options = struct {
+        //         allocator: mem.Allocator,
+        //         fallback_handler: HandlerFn,
+        //         error_handler: HandlerFn,
+        //     };
+
+        //     pub fn init(options: Options) Router {
+        //         return .{
+        //             .allocator = options.allocator,
+        //             .fallback_handler = options.fallback_handler,
+        //             .error_handler = options.error_handler,
+        //             .static_routes = std.StringHashMap(HandlerFn).init(options.allocator),
+        //         };
+        //     }
+
+        //     pub fn deinit(self: Router) void {
+        //         self.static_routes.deinit();
+        //     }
+
+        //     pub fn get(self: Router, path: []const u8) HandlerFn {
+        //         if (self.static_routes.get(path)) |handler_fn|
+        //             return handler_fn
+        //         else
+        //             return self.fallback_handler;
+        //     }
+
+        //     pub fn put(self: Router, path: []const u8, handler_fn: HandlerFn) !void {
+        //         if (mem.indexOfAny(u8, path, "*{}") != null) {
+        //             return error.UnsupportedRoute;
+        //         } else try self.static_routes.put(path, handler_fn);
+        //     }
+
+        //     pub fn remove(self: Router, path: []const u8) void {
+        //         if (mem.indexOfAny(u8, path, "*{}") != null) {
+        //             return;
+        //         } else _ = self.static_routes.remove(path);
+        //     }
+
+        //     pub fn handler(req: Request, ctx: Router) Response {
+        //         const uri = std.Uri.parseAfterScheme("http://", req.http.head.target);
+        //         if (ctx.get(uri.path.percent_encoded)) |handler_fn|
+        //             return handler_fn(req)
+        //         else
+        //             return ctx.fallback_handler(req);
+        //     }
+        // };
+    };
+}