const std = @import("std"); const log = std.log; const net = std.Io.net; const Io = std.Io; const Request = std.http.Server.Request; const MAX_BUF = 1024; const Endpoint = enum { root_get, login_get, }; pub fn serve(io: std.Io, address: []const u8, port: u16) !void { const addr = try net.IpAddress.parse(address, port); var server = try addr.listen(io, .{ .reuse_address = true }); defer server.deinit(io); log.info("Start HTTP server at {f}", .{addr}); while (true) { const stream = server.accept(io) catch |err| { log.err("failed to accept connection: {s}", .{@errorName(err)}); continue; }; const thread = std.Thread.spawn(.{}, accept, .{ stream, io }) catch |err| { log.err("unable to spawn connection thread: {s}", .{@errorName(err)}); stream.close(io); continue; }; thread.detach(); } } fn accept(stream: net.Stream, io: Io) !void { defer stream.close(io); log.info("Got new client!", .{}); var recv_buffer: [1024]u8 = undefined; var send_buffer: [100]u8 = undefined; var stream_reader = stream.reader(io, &recv_buffer); var stream_writer = stream.writer(io, &send_buffer); var server = std.http.Server.init(&stream_reader.interface, &stream_writer.interface); while (server.reader.state == .ready) { var request = server.receiveHead() catch |err| switch (err) { error.HttpConnectionClosing => return, else => return err, }; try serveHTTP(&request); } } fn endpointFromRequest(request: *Request) !Endpoint { const head = request.head; if (head.method == .GET and std.mem.eql(u8, head.target, "/")) { return .root_get; } else if (head.method == .GET and std.mem.eql(u8, head.target, "/login")) { return .login_get; } return error.InvalidEndpoint; } fn serveHTTP(request: *Request) !void { log.info("Received request: {s}", .{request.head.target}); const endpoint = endpointFromRequest(request) catch { try respondNotFound(request); return; }; switch (endpoint) { .root_get => try handleRoot(request), .login_get => try handleLogin(request), } } fn respondNotFound(request: *Request) !void { try request.respond("", .{ .status = .not_found }); } fn handleRoot(request: *Request) !void { try request.respond("Welcome to Coinvane!\n", .{}); } fn handleLogin(request: *Request) !void { try request.respond("Login page\n", .{}); }