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, headers: []const std.http.Header = &.{}, pub fn with(status: std.http.Status, message: Message) @This() { return .{ .status = status, .message = message }; } pub fn withHeaders( status: std.http.Status, message: Message, headers: []const std.http.Header, ) @This() { return .{ .status = status, .message = message, .headers = headers, }; } pub fn ok(message: Message) @This() { return with(.ok, message); } pub fn okOrError(message: anyerror!Message) @This() { return ok(message catch return with(.internal_server_error, .void)); } pub fn badRequest(message: Message) @This() { return with(.bad_request, message); } pub const SendOptions = struct { headers: []const std.http.Header, }; pub fn send( self: *const @This(), io: std.Io, arena: std.mem.Allocator, request: *std.http.Server.Request, options: SendOptions, ) !void { const headers = hdrs: { if (options.headers.len == 0) { break :hdrs self.headers; } const h = try arena.alloc(std.http.Header, options.headers.len + self.headers.len); @memcpy(h[0..options.headers.len], options.headers); @memcpy(h[options.headers.len..], self.headers); break :hdrs h; }; switch (self.message) { .void => { try request.respond("", .{ .status = self.status, .extra_headers = headers, }); }, .static => |content| { try request.respond(content, .{ .status = self.status, .extra_headers = headers, }); }, .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, .extra_headers = headers, .transfer_encoding = .chunked, }, }); var file_reader = file.reader(io, &read_buffer); _ = try file_reader.interface.streamRemaining(&body_writer.writer); try body_writer.end(); }, } }