aboutsummaryrefslogtreecommitdiff
path: root/src/routes
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2025-11-17 13:09:02 +0100
committerNathan Reiner <nathan@nathanreiner.xyz>2025-11-17 13:09:02 +0100
commit6201307fecf8398a1b53bf276bc08bfbb3524899 (patch)
tree2e623f4779b310a81b49dbb146146f8a694d9ec8 /src/routes
parent9c979a6fefdfc6709b3576014520d219e02c3649 (diff)
implement memora.Stream
Diffstat (limited to 'src/routes')
-rw-r--r--src/routes/api/image/load.zig7
-rw-r--r--src/routes/handler-info.zig29
-rw-r--r--src/routes/static.zig10
3 files changed, 25 insertions, 21 deletions
diff --git a/src/routes/api/image/load.zig b/src/routes/api/image/load.zig
index 51c0e26..4f0a072 100644
--- a/src/routes/api/image/load.zig
+++ b/src/routes/api/image/load.zig
@@ -6,11 +6,8 @@ const Storage = memora.Storage;
pub const access = .users;
-pub fn get(ctx: *Context) ![]const u8 {
+pub fn get(ctx: *Context) !memora.Stream {
const id = ctx.request.head.target["/api/image/load/".len..];
var image = Storage.Image { .id = id };
- var file = try image.file(ctx.storage);
- defer file.close();
-
- return try file.readToEndAlloc(ctx.allocator, std.math.maxInt(usize));
+ return .from_file(try image.file(ctx.storage));
}
diff --git a/src/routes/handler-info.zig b/src/routes/handler-info.zig
index e8c9dfb..97eb9bd 100644
--- a/src/routes/handler-info.zig
+++ b/src/routes/handler-info.zig
@@ -12,7 +12,7 @@ const log = std.log.scoped(.handler_info);
const Self = @This();
-const Handler = *const fn (*Context) anyerror![]const u8;
+const Handler = *const fn (*Context) anyerror!memora.Stream;
get: ?Handler,
head: ?Handler,
@@ -95,7 +95,7 @@ pub fn handle(
}
}
- const response = handler(&context) catch |err| {
+ var stream = handler(&context) catch |err| {
const response, const status_code: std.http.Status = switch (err) {
error.BadRequest => .{ "{ \"error\": \"Bad Request\" }", .bad_request },
error.Unauthorized => .{ "{ \"error\": \"Unauthorized\" }", .unauthorized },
@@ -109,6 +109,7 @@ pub fn handle(
return request.respond(response, .{ .status = status_code });
};
+ defer stream.close();
var headers: std.ArrayList(std.http.Header) = .empty;
defer headers.deinit(allocator);
@@ -129,9 +130,19 @@ pub fn handle(
});
}
- try request.respond(response, .{
- .extra_headers = headers.items
+ var read_buffer: [1024]u8 = undefined;
+ var reader = stream.reader(&read_buffer);
+
+ var write_buffer: [1024]u8 = undefined;
+ var body_writer = try request.respondStreaming(&write_buffer, .{
+ .respond_options = .{
+ .extra_headers = headers.items,
+ .transfer_encoding = .chunked,
+ },
});
+
+ _ = try reader.streamRemaining(&body_writer.writer);
+ try body_writer.end();
}
fn HandlerWrapper(T: type, name: []const u8) type {
@@ -140,7 +151,7 @@ fn HandlerWrapper(T: type, name: []const u8) type {
const payload_type = @typeInfo(return_type).error_union.payload;
return struct {
- pub fn call(ctx: *Context) anyerror![]const u8 {
+ pub fn call(ctx: *Context) anyerror!memora.Stream {
const args = args: {
const tuple = std.meta.fields(std.meta.ArgsTuple(@TypeOf(@field(T, name))));
@@ -161,7 +172,7 @@ fn HandlerWrapper(T: type, name: []const u8) type {
Body,
ctx.allocator,
writer.written(),
- .{}
+ .{},
) catch return error.BadRequest;
break :args .{ ctx, body };
} else {
@@ -169,16 +180,16 @@ fn HandlerWrapper(T: type, name: []const u8) type {
}
};
- if (payload_type == []const u8) {
+ if (payload_type == memora.Stream) {
return @call(.auto, @field(T, name), args);
} else if (payload_type == void) {
try @call(.auto, @field(T, name), args);
- return "";
+ return memora.Stream.from_buffer("");
} else {
var writer = std.Io.Writer.Allocating.init(ctx.allocator);
var stringify = std.json.Stringify { .writer = &writer.writer };
try stringify.write(try @call(.auto, @field(T, name), args));
- return writer.written();
+ return memora.Stream.from_buffer(writer.written());
}
}
};
diff --git a/src/routes/static.zig b/src/routes/static.zig
index ef7d493..f52d178 100644
--- a/src/routes/static.zig
+++ b/src/routes/static.zig
@@ -8,16 +8,14 @@ const log = std.log.scoped(.fallback);
pub const access = .everyone;
-pub fn get(ctx: *Context) anyerror![]const u8 {
+pub fn get(ctx: *Context) anyerror!memora.Stream {
var static = try std.fs.cwd().openDir("static", .{});
defer static.close();
if (static.openFile(ctx.request.head.target[1..], .{})) |file| {
- defer file.close();
- const content = file.readToEndAlloc(ctx.allocator, std.math.maxInt(usize));
const mime_type = mime.get_type(ctx.request.head.target);
ctx.response.headers.content_type = mime_type;
- return content;
+ return .from_file(file);
} else |_| {
var subdir = if (ctx.request.head.target.len == 1) static
else (static.openDir(ctx.request.head.target[1..], .{}) catch {
@@ -26,10 +24,8 @@ pub fn get(ctx: *Context) anyerror![]const u8 {
defer if (ctx.request.head.target.len > 1) subdir.close();
if (subdir.openFile("index.html", .{})) |file| {
- defer file.close();
- const content = file.readToEndAlloc(ctx.allocator, std.math.maxInt(usize));
ctx.response.headers.content_type = "text/html";
- return content;
+ return .from_file(file);
} else |_| {
log.warn("File '{s}' Not Found", .{ ctx.request.head.target });
return error.NotFound;