From 8d018d996c1eddb882dc64ebbd228bb0135944f3 Mon Sep 17 00:00:00 2001 From: sadbeast Date: Sun, 23 Jun 2024 15:36:59 -0700 Subject: wtf --- src/web/web.zig | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/web/web.zig (limited to 'src/web/web.zig') diff --git a/src/web/web.zig b/src/web/web.zig new file mode 100644 index 0000000..184a1a3 --- /dev/null +++ b/src/web/web.zig @@ -0,0 +1,109 @@ +pub const Templates = std.StringHashMap(Template); + +pub var templates: Templates = undefined; + +pub fn start(app: *App) !void { + const allocator = app.allocator; + + var server = try httpz.ServerCtx(*const Dispatcher, *Env).init(allocator, .{ + .address = "0.0.0.0", + .port = 5882, + }, undefined); + defer server.deinit(); + + templates = Templates.init(allocator); + defer { + var it = templates.valueIterator(); + while (it.next()) |t| { + t.deinit(allocator); + } + templates.deinit(); + } + + inline for (config.templates) |template| { + try templates.put(template, try loadTemplate(allocator, template)); + } + + server.dispatcher(Dispatcher.dispatch); + + var router = server.router(); + { + var routes = router.group("", .{ .ctx = &Dispatcher{ .app = app } }); + routes.get("/", index); + routes.get("/about", about); + routes.get("/drafts/:id", @import("drafts/show.zig").handler); + routes.get("/drafts/:id/pick", @import("drafts/pick.zig").handler); + routes.get("/leagues/:id", @import("leagues/show.zig").handler); + routes.post("/leagues", @import("leagues/create.zig").handler); + routes.get("/invites/:id", @import("leagues/invite.zig").handler); + } + + // use get/post/put/head/patch/options/delete + // you can also use "all" to attach to all methods + + // start the server in the current thread, blocking. + try server.listen(); +} + +fn pick(_: *Env, req: *httpz.Request, res: *httpz.Response) !void { + try render("pick", req, res); +} + +fn about(_: *Env, req: *httpz.Request, res: *httpz.Response) !void { + // try render(templates.get("about").?, req, res); + try renderWithData("about", .{ .title = "foo" }, req, res); +} + +fn index(_: *Env, req: *httpz.Request, res: *httpz.Response) !void { + try render("index", req, res); +} + +fn loadTemplate(allocator: std.mem.Allocator, comptime template_name: []const u8) !Template { + return switch (try mustache.parseText(allocator, @embedFile("../views/" ++ template_name ++ ".mustache"), .{}, .{ .copy_strings = false })) { + .success => |t| t, + .parse_error => @panic("layout parse error"), + }; +} + +fn loadTemplateFile(allocator: std.mem.Allocator, template_name: []const u8) !Template { + const file = std.fs.cwd().openFile(try std.fmt.allocPrint(allocator, "src/views/{s}.mustache", .{template_name}), .{}) catch @panic("could not find template"); + defer file.close(); + const template_bytes = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch @panic("couldn't read template file "); + + return switch (try mustache.parseText(allocator, template_bytes, .{}, .{ .copy_strings = false })) { + .success => |t| t, + .parse_error => @panic("layout parse error"), + }; +} + +pub fn renderWithDataPartials(template_name: []const u8, partials: anytype, data: anytype, req: *httpz.Request, res: *httpz.Response) !void { + var template: Template = undefined; + if (config.dev) { + template = try loadTemplateFile(res.arena, template_name); + } else { + template = templates.get(template_name).?; + } + const content = try mustache.allocRenderPartials(res.arena, template, partials, data); + if (req.header("hx-request")) |_| { + res.body = content; + } else { + res.body = try mustache.allocRender(res.arena, templates.get("layout").?, .{ .content = content }); + } +} + +pub fn renderWithData(template_name: []const u8, data: anytype, req: *httpz.Request, res: *httpz.Response) !void { + try renderWithDataPartials(template_name, .{}, data, req, res); +} + +pub fn render(template_name: []const u8, req: *httpz.Request, res: *httpz.Response) !void { + try renderWithData(template_name, .{}, req, res); +} + +const config = @import("config"); +const App = @import("../app.zig").App; +const Env = @import("../env.zig").Env; +const httpz = @import("httpz"); +const mustache = @import("mustache"); +const Template = mustache.Template; +const std = @import("std"); +const Dispatcher = @import("dispatcher.zig").Dispatcher; -- cgit v1.2.3