const std = @import("std"); const log = std.log.scoped(.server); const routes = @import("routes/root.zig"); const Storage = @import("storage/root.zig"); const config = @import("config"); const Self = @This(); storage: Storage = undefined, net_server: std.net.Server = undefined, pool: std.Thread.Pool = undefined, pub fn init( self: *Self, address: std.net.Address, allocator: std.mem.Allocator, ) !void { self.storage = try .init(allocator); self.net_server = try address.listen(.{ .reuse_address = true }); try self.pool.init(.{ .allocator = allocator }); log.info("listing on {f}", .{address}); if (comptime config.disable_auth) { log.warn("authentication is disabled", .{}); } } pub fn run(self: *Self, allocator: std.mem.Allocator) void { while (true) { const connection = self.net_server.accept() catch |err| { log.err("error: {}", .{err}); continue; }; self.pool.spawn(handle_connection, .{self, allocator, connection}) catch |err| { std.log.err("failed to spawn thread: {}", .{err}); }; } } fn handle_connection( self: *Self, allocator: std.mem.Allocator, connection: std.net.Server.Connection, ) void { defer connection.stream.close(); var read_buf: [1024 * 8]u8 = undefined; var write_buf: [1024 * 8]u8 = undefined; var reader = connection.stream.reader(&read_buf); var writer = connection.stream.writer(&write_buf); var http_server = std.http.Server.init(reader.interface(), &writer.interface); while (true) { var request = http_server.receiveHead() catch return; log.info("{s} {s}", .{ std.enums.tagName(std.http.Method, request.head.method) orelse "", request.head.target, }); const handler_info = routes.get(request.head.target); handler_info.handle(&request, &self.storage, allocator) catch |err| { std.log.err("{}", .{err}); }; } } pub fn deinit(self: *Self) void { log.info("shutdown", .{}); self.net_server.deinit(); self.storage.deinit(); }