const std = @import("std"); pub const Message = union(enum) { void: void, static: []const u8, streaming: std.Io.File, pub fn json(arena: std.mem.Allocator, value: anytype) !Message { var allocating: std.Io.Writer.Allocating = .init(arena); var jsonify: std.json.Stringify = .{ .writer = &allocating.writer }; try jsonify.write(value); return .string(try allocating.toOwnedSlice()); } pub fn string(content: []const u8) Message { return .{ .static = content }; } pub fn file(io: std.Io, path: []const u8) !Message { return .{ .streaming = try std.Io.Dir.cwd().openFile(io, path, .{ .allow_directory = false, }) }; } }; status: std.http.Status, message: Message, pub fn with(status: std.http.Status, message: Message) @This() { return .{ .status = status, .message = message }; } pub fn ok(message: Message) @This() { return with(.ok, message); } pub fn ok_or_error(message: anyerror!Message) @This() { return ok(message catch return with(.internal_server_error, .void)); } pub fn bad_request(message: Message) @This() { return with(.bad_request, message); } pub fn send( self: *const @This(), io: std.Io, request: *std.http.Server.Request, ) !void { switch (self.message) { .void => { try request.respond("", .{ .status = self.status }); }, .static => |content| { try request.respond(content, .{ .status = self.status }); }, .streaming => |file| { var write_buffer: [1024]u8 = undefined; var read_buffer: [1024]u8 = undefined; var body_writer = try request.respondStreaming(&write_buffer, .{ .respond_options = .{ .status = self.status, .transfer_encoding = .chunked, }, }); var file_reader = file.reader(io, &read_buffer); _ = try file_reader.interface.streamRemaining(&body_writer.writer); try body_writer.end(); }, } }