aboutsummaryrefslogtreecommitdiff
path: root/src/server.zig
blob: 5a9be74cafc2d67ff5ea4226669a01fee6dcbf47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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 "<unknown>",
            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();
}