diff options
Diffstat (limited to '')
| -rw-r--r-- | src/main.zig | 91 |
1 files changed, 78 insertions, 13 deletions
diff --git a/src/main.zig b/src/main.zig index fa5b33b..4a87c86 100644 --- a/src/main.zig +++ b/src/main.zig @@ -123,7 +123,7 @@ const Cli = struct { \\ gen [-f, --force] [-l, --list] ROOT-DIR TARGET-DIR \\ runs build for relevant files \\ - \\ serve ROOT-DIR + \\ serve [-l, --listen PORT] ROOT-DIR \\ serves the site (using caddy) \\ \\ @@ -434,24 +434,89 @@ const Cli = struct { }); } - fn serve(io: Io, _: Allocator, _: FlagSet, args: [][]const u8) !void { + fn serve(io: Io, _: Allocator, flags: FlagSet, args: [][]const u8) !void { if (args.len != 1) return Cli.usage(); const root_path = args[0]; - const root_dir = try Io.Dir.cwd().openDir(io, root_path, .{}); - defer root_dir.close(io); + const root_dir = try Dir.init(io, Io.Dir.cwd(), root_path, .{}); + defer root_dir.fd.close(io); - const command = blk: { - root_dir.access(io, "Caddyfile", .{}) catch |err| - switch (err) { - error.FileNotFound => break :blk "caddy file-server -l :1414", - else => return err, - }; - break :blk "caddy fmt --overwrite && caddy run --watch"; + const progress = if (!DEBUG) std.Progress.start(io, .{ .root_name = "Serving" }); + defer if (!DEBUG) progress.end(); + + // TODO: comptime option? + caddy: { + root_dir.fd.access(io, "Caddyfile", .{}) catch break :caddy; + log.info("Caddy root={s}", .{root_path}); + + if (!DEBUG) progress.end(); + return try shell( + io, + "caddy fmt --overwrite && caddy run --watch", + .{ + .cwd = .{ .dir = root_dir.fd }, + }, + ); + } + + const addrStr = flags.get("-l") orelse flags.get("--listen") orelse "127.0.0.1:1414"; + + const addr = blk: { + const idx = std.mem.lastIndexOfScalar(u8, addrStr, ':') orelse + return error.AddrMissingPort; + + const port = try std.fmt.parseInt(u16, addrStr[idx + 1 ..], 0); + const host = blk2: { + const h = addrStr[0..idx]; + if (std.mem.eql(u8, h, "")) break :blk2 "127.0.0.1"; + if (std.mem.eql(u8, h, "localhost")) break :blk2 "127.0.0.1"; + break :blk2 h; + }; + break :blk try Io.net.IpAddress.parse(host, port); }; - log.info("Serving root={s}", .{root_path}); - try shell(io, command, .{ .cwd = .{ .dir = root_dir } }); + log.info("Serving root={s} addr={s}", .{ root_path, addrStr }); + + const serverNode = if (!DEBUG) progress.start(addrStr, 0); + defer if (!DEBUG) progress.end(); + + // tcp server + var server = try addr.listen(io, .{ .reuse_address = true }); + defer server.deinit(io); + + while (true) { + const stream = try server.accept(io); + defer stream.close(io); + + var stream_read_buffer: [BUFFER_SIZE]u8 = undefined; + var stream_reader = stream.reader(io, &stream_read_buffer); + var stream_write_buffer: [BUFFER_SIZE]u8 = undefined; + var stream_writer = stream.writer(io, &stream_write_buffer); + + var http_server = std.http.Server.init(&stream_reader.interface, &stream_writer.interface); + var req = try http_server.receiveHead(); + + log.info("{s} {s}", .{ @tagName(req.head.method), req.head.target }); + + const streamNode = if (!DEBUG) serverNode.start(req.head.target, 0); + defer if (!DEBUG) streamNode.end(); + + switch (req.head.method) { + .GET, .HEAD => {}, + else => return, + } + + var fd = File.init(io, root_dir, req.head.target[1..], null) catch |err| { + switch (err) { + error.FileNotFound => try req.respond("", .{ .status = .not_found }), + else => try req.respond("", .{ .status = .internal_server_error }), + } + continue; + }; + defer fd.close(io); + + try req.respond(fd.mmap.memory, .{ .status = .ok }); + } } }; |