Something went wrong. Try again.
🦦 a tiny cute lua web framework
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166const std = @import("std");const http = std.http;const Request = http.Server.Request;
const fern = @import("fern");const httpz = @import("httpz");const zlua = @import("zlua");const Lua = zlua.Lua;
const fragment = @import("fragment.zig");const handler = @import("handler.zig");const Connection = handler.Connection;const helpers = @import("helpers.zig");const maivi = @import("root.zig");
const Self = @This();
pub const Path = struct { action: Action, config: Config,
pub fn init(action: Action, cfg: ?Config) Path { return .{ .action = action, .config = cfg orelse .{} }; }
pub const Action = *const fn (conn: *Connection) anyerror!void; pub const Config = struct { allowed_methods: []const http.Method = &.{.GET}, }; // pub const Error = error{} || Request.ExpectContinueError;};
pub const LuaPath = struct { f: i32, props: i32,};
paths: std.hash_map.StringHashMap(Path),luapaths: std.hash_map.StringHashMap(LuaPath),
pub fn init() Self { return .{ .paths = .init(maivi.allocator), .luapaths = .init(maivi.allocator), };}
pub fn deinit(self: *Self) void { self.paths.deinit(); self.luapaths.deinit();}
pub fn add(self: *Self, path: []const u8, action: Path.Action, cfg: ?Path.Config) !void { fern.debug().ctx("router").msg("adding router path").str("path", path).log(); return try self.paths.put(path, .init(action, cfg));}
// lua ========================================================================
pub fn lua_openrouter(l: *Lua) !i32 { l.createTable(0, 1);
l.pushFunction(zlua.wrap(lua_add)); l.setField(-2, "add");
return 1;}
fn lua_add(l: *Lua) !i32 { fern.trace().ctx("router").msg("lua_add").log();
l.argCheck(l.isTable(1), 1, "table"); l.argCheck(l.isString(2), 2, "string"); l.argCheck(l.isFunction(3), 3, "function"); const noprops = l.getTop() < 4 or l.isNil(4); l.argCheck(noprops or l.isTable(4), 4, "table?"); // stack: -1 => props -2 => function -3 => string -4 => router (empty table)
const path = try l.toString(2);
const f = maivi.lua.toRef(l, 3);
const props = blk: { if (noprops) l.newTable() else l.pushValue(-1);
// set props.url _ = l.pushString(path); l.setField(-2, "url");
break :blk maivi.lua.toRef(l, null); };
try maivi.router.add(path, handle_lua, .{});
if (maivi.router.luapaths.contains(path)) return error.Clobber; try maivi.router.luapaths.put(path, .{ .f = f, .props = props, });
return 0;}
// TODO:// - set content// - caching?pub fn handle_lua(conn: *Connection) !void { const request = conn.request;
const content_type = helpers.content_type_for_file(conn.path) orelse .html;
var wbuf: [0x4000]u8 = undefined; var b = try maivi.helpers.respond(request, &wbuf, .{ // .content_length = size, .content_type = content_type, });
const data = maivi.router.luapaths.get(conn.path) orelse return error.FileNotFound; try get(conn.lua, conn, &b.writer, data); try b.end();}
pub fn get(l: *Lua, conn: *Connection, writer: *std.Io.Writer, data: LuaPath) !void { // call handler function _ = l.getIndexRaw(zlua.registry_index, data.f); if (!l.isFunction(-1)) return error.LuaValueNotAFunction; _ = l.getIndexRaw(zlua.registry_index, data.props); if (!l.isTable(-1)) return error.LuaValueNotATable;
// read content try blk: { // stack: -1 => getIndexRaw(props) const stack_size_on_entry = l.getTop(); const filepath = filepath: { const ltype_path = l.getField(-1, "path"); defer l.pop(1); // pops "path" if (ltype_path != .string) break :blk; break :filepath try l.toString(-1); };
try maivi.lua.read_data(l, conn.io, filepath); l.setField(-2, "content");
if (l.getTop() != stack_size_on_entry) break :blk error.UnexpectedStackSize; };
// prepare ctx try blk: { // stack: -1 => getIndexRaw(props) const stack_size_on_entry = l.getTop(); try maivi.lua.pushCtx(l, Connection, conn); l.pushValue(-3); l.setField(-2, "props"); l.setGlobal("ctx");
if (l.getTop() != stack_size_on_entry) break :blk error.UnexpectedStackSize; };
try maivi.lua.pcall(l, .{ .args = 1, .results = 1 });
try fragment.render(l, writer);}