web: some stuff

This commit is contained in:
2026-03-07 21:08:22 +01:00
parent f02ece22fa
commit 66d49ea8d5
14 changed files with 38964 additions and 101 deletions

164
packages/web/src/main.zig Normal file
View File

@@ -0,0 +1,164 @@
const std = @import("std");
const http = @import("http.zig");
const Connection = @import("Connection.zig");
const Response = @import("Response.zig");
const RequestHandler = @import("RequestHandler.zig");
const RequestRouter = @import("RequestRouter.zig");
const Route = @import("Route.zig");
const Server = @import("Server.zig");
const UUID = @import("UUID.zig");
const Worker = @import("Worker.zig");
const linux = std.os.linux;
const errno = linux.E.init;
var running: std.atomic.Value(bool) = .init(true);
fn interruptionHandler(signal: i32) callconv(.c) void {
switch (signal) {
linux.SIG.INT, linux.SIG.TERM => {
running.store(false, .release);
},
else => {},
}
}
const Router = struct {
allocator: std.mem.Allocator,
fn init(allocator: std.mem.Allocator) Router {
return .{
.allocator = allocator,
};
}
fn interface(self: *Router) RequestRouter {
return .{
.ptr = self,
.vtable = &.{
.route = onRoute,
},
};
}
fn onRoute(ctx: *anyopaque, route: Route) !RequestHandler {
const self: *Router = @ptrCast(@alignCast(ctx));
const handler = try self.allocator.create(Handler);
handler.* = .init(self.allocator, route);
return handler.interface();
}
};
const Handler = struct {
allocator: std.mem.Allocator,
route: Route,
uuid: UUID,
timer: std.time.Timer,
accept: ?[]const u8 = null,
accept_encoding: ?[]const u8 = null,
accept_language: ?[]const u8 = null,
user_agent: ?[]const u8 = null,
fn init(allocator: std.mem.Allocator, route: Route) Handler {
return .{
.allocator = allocator,
.route = route,
.uuid = UUID.v7(),
.timer = .start(),
};
}
fn interface(self: *Handler) RequestHandler {
return .{
.ptr = self,
.vtable = &.{
.header = onHeader,
.body = onBody,
.finalize = onFinalize,
},
};
}
fn onHeader(ctx: *anyopaque, response: *Response, header: http.Header) void {
const self: *Handler = @ptrCast(@alignCast(ctx));
switch (header.name) {
.known => |k| switch (k) {
.Accept => {
self.accept = header.value;
},
.@"Accept-Encoding" => {
self.accept_encoding = header.value;
},
.@"Accept-Language" => {
self.accept_language = header.value;
},
.@"User-Agent" => {
self.user_agent = header.value;
},
},
.other => {},
}
_ = response;
}
fn onBody(ctx: *anyopaque, response: *Response, body: []const u8) !void {
const self: *Handler = @ptrCast(@alignCast(ctx));
try response.sendResponse(.{
.media_type = "application/json",
.response_body = "{\"ok\":true}",
});
_ = self;
_ = body;
}
fn onFinalize(ctx: *anyopaque) void {
const self: *Handler = @ptrCast(@alignCast(ctx));
const time_ns = self.timer.read();
const time_us = time_ns / std.time.ns_per_us;
std.log.info("{s} {s} [{d}]", .{ @tagName(self.route.method), self.route.pathname, time_us });
self.allocator.destroy(self);
}
};
pub fn main() !void {
var gpa: std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}) = .init;
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var router: Router = .init(allocator);
var server = try Server.init(allocator, .{
.request_router = router.interface(),
});
defer server.deinit(allocator);
const sigaction: linux.Sigaction = .{
.handler = .{ .handler = interruptionHandler },
.mask = linux.sigemptyset(),
.flags = linux.SA.RESETHAND,
};
const rc = linux.sigaction(linux.SIG.INT, &sigaction, null);
switch (errno(rc)) {
.SUCCESS => {},
else => |e| {
std.log.err("Error while estabilishing interruption handler: {s}", .{@tagName(e)});
return error.SystemError;
},
}
try server.listen(&running);
}