Something went wrong. Try again.
🦦 a tiny cute lua web framework
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127const std = @import("std");const Io = std.Io;const Allocator = std.mem.Allocator;
const fern = @import("fern");
const maivi = @import("root.zig");const Lua = maivi.lua.Lua;
pub fn generate(io: Io) !void { fern.info().ctx("gen.generate") .msg("generating") .str("path", maivi.config.buildroot).log();
var arena: std.heap.ArenaAllocator = .init(maivi.allocator); defer arena.deinit(); const allocator = arena.allocator();
Io.Dir.createDirAbsolute(io, maivi.config.buildroot, .default_dir) catch |err| switch (err) { error.PathAlreadyExists => {}, else => return err, }; const buildroot = try Io.Dir.openDirAbsolute(io, maivi.config.buildroot, .{ .access_sub_paths = true }); defer buildroot.close(io);
const count = maivi.router.luapaths.count(); var prg = std.Progress.start(io, .{ .estimated_total_items = count }); defer prg.end(); var it = maivi.router.luapaths.iterator(); while (true) { const entry = it.next() orelse break; const path = entry.key_ptr.*; const data = entry.value_ptr.*;
fern.debug().ctx("gen.generate").msg("generating path").str("path", path).log(); defer prg.completeOne();
genpath(maivi.lua.lua, io, allocator, buildroot, path, data) catch |err| { fern.err().ctx("gen.generate") .msg("could not generate path") .str("path", path) .err(err) .log(); continue; }; }}
fn genpath(l: *Lua, io: Io, arena: Allocator, dir: Io.Dir, path: []const u8, data: maivi.Router.LuaPath) !void { const outpath = blk: { const outpath_base = if (path.len == 1) "." else path[1..]; var it = std.mem.splitBackwardsScalar(u8, path, '/'); break :blk if (!std.mem.containsAtLeast(u8, it.first(), 1, ".")) try std.mem.join(arena, "/", &.{ outpath_base, "index.html" }) else outpath_base; };
fern.info().ctx("gen.writepath") .str("path", path) .str("outpath", outpath).log(); if (std.mem.cutScalarLast(u8, outpath, '/')) |outpath_parts| try mkdir(io, dir, outpath_parts[0]); const file = try dir.createFile(io, outpath, .{ .lock = .exclusive }); defer file.close(io);
var buf: [0x1000]u8 = undefined; var writer = file.writer(io, &buf); var stub: [0x0]u8 = undefined; var stub_reader: Io.Reader = .fixed(&stub); const stub_http_reader: std.http.Reader = .{ .in = &stub_reader, .interface = stub_reader, .max_head_len = 0, .state = .received_head, .body_err = null, }; var fake_server: std.http.Server = .{ .out = &writer.interface, .reader = stub_http_reader, }; const head_buf: []const u8 = "\r\n\r\n";
var fake_request: std.http.Server.Request = .{ .head = .{ .keep_alive = false, .method = .GET, .target = path, .transfer_compression = .compress, .transfer_encoding = .none, .version = .@"HTTP/1.1", .content_length = null, .content_type = null, .expect = null, }, .head_buffer = head_buf, .server = &fake_server, }; var fake_connection: maivi.handler.Connection = .{ .request = &fake_request, .io = io, .handle = file.handle, .path = path, .arena = arena, .lua = l, }; try maivi.Router.get(l, &fake_connection, &writer.interface, data);}
// helpers ====================================================================
fn mkdir(io: Io, dir: Io.Dir, path: []const u8) !void { if (path.len == 0) return;
var parts = std.mem.splitScalar(u8, path, '/');
while (parts.next()) |p| { if (p.len == 0) continue;
const sub_path = if (parts.index) |n| path[0 .. n - 1] else path;
Io.Dir.createDir(dir, io, sub_path, .default_dir) catch |err| switch (err) { error.PathAlreadyExists => {}, else => return err, }; }}