diff options
Diffstat (limited to 'zig-comments/src/main.zig')
-rw-r--r-- | zig-comments/src/main.zig | 123 |
1 files changed, 103 insertions, 20 deletions
diff --git a/zig-comments/src/main.zig b/zig-comments/src/main.zig index b8b820c..898b689 100644 --- a/zig-comments/src/main.zig +++ b/zig-comments/src/main.zig @@ -5,7 +5,35 @@ const mustache = @import("mustache"); const Params = zws.Params; -const Err = error{ Overflow, InvalidCharacter, StreamTooLong, ColumnNotFound } || pq.PqError || std.http.Server.Response.WaitError || std.http.Server.Response.DoError || std.http.Server.Response.ReadError || std.http.Server.Response.FinishError || zws.Path.ParseError; +const Err = error{ + Unexpected, + AccessDenied, + OutOfMemory, + InputOutput, + SystemResources, + IsDir, + OperationAborted, + BrokenPipe, + ConnectionResetByPeer, + ConnectionTimedOut, + NotOpenForReading, + NetNameDeleted, + WouldBlock, + StreamTooLong, + Malformatted, + InvalidLength, + InvalidCharacter, + NoSpaceLeft, + PqError, + ColumnNotFound, + DiskQuota, + FileTooBig, + DeviceBusy, + InvalidArgument, + NotOpenForWriting, + LockViolation, + InvalidRequestMethod, +}; const Ctx = struct { db: pq.Db, pub fn clone(self: @This()) Ctx { @@ -19,8 +47,56 @@ const Ctx = struct { }; var gpa = std.heap.GeneralPurposeAllocator(.{}){}; -const Rtr = zws.Router(Ctx, Err); +const Request = struct { + method: std.http.Method, + target: []const u8, +}; +const ResponseTransfer = union(enum) { + content_length: u64, + chunked: void, + none: void, +}; +const Headers = struct { + const Entry = struct { key: []const u8, val: []const u8 }; + _internal: std.ArrayList(Entry), + + fn init(allocator: std.mem.Allocator) Headers { + return .{ ._internal = std.ArrayList(Entry).init(allocator) }; + } + fn append(self: *@This(), key: []const u8, val: []const u8) !void { + try self._internal.append(.{ .key = key, .val = val }); + } +}; +const Response = struct { + allocator: std.mem.Allocator, + request: Request, + // TODO other fields and writer function to write headers and body to stdout + status: std.http.Status, + transfer_encoding: ResponseTransfer, + headers: Headers, + fn reader(_: @This()) std.fs.File.Reader { + return std.io.getStdIn().reader(); + } + fn do(self: @This()) !void { + for (self.headers._internal.items) |tup| { + try std.io.getStdOut().writeAll(tup.key); + try std.io.getStdOut().writeAll(": "); + try std.io.getStdOut().writeAll(tup.val); + try std.io.getStdOut().writeAll("\r\n"); + } + try std.io.getStdOut().writeAll("\r\n"); + } + fn writer(_: @This()) std.fs.File.Writer { + return std.io.getStdOut().writer(); + } + fn finish(_: @This()) !void { + // TODO Write empty lines? or just do nothing + } +}; + +const Rtr = zws.Router(*Response, Ctx, Err); const router = Rtr{ + .allocator = gpa.allocator(), .handlers = &[_]Rtr.Handler{ .{ .method = .GET, @@ -41,43 +117,51 @@ const router = Rtr{ .notfound = notfound, }; +/// Run as a CGI program! pub fn main() !void { + const allocator = gpa.allocator(); const db_url = std.os.getenv("DATABASE_URL") orelse "postgresql://comments@localhost/comments"; var db = try pq.Db.init(db_url); - try db.exec(@embedFile("migrations/0_init.sql")); - try db.exec(@embedFile("migrations/1_capcha.sql")); + // try db.exec(@embedFile("migrations/0_init.sql")); + // try db.exec(@embedFile("migrations/1_capcha.sql")); defer db.deinit(); - const server = zws.Server(Ctx, Rtr){ - .allocator = gpa.allocator(), - .address = std.net.Address{ .in = std.net.Ip4Address.init(.{ 127, 0, 0, 1 }, 5678) }, - .context = Ctx{ .db = db }, - .handler = router, + const req = Request{ + .method = std.meta.stringToEnum(std.http.Method, std.os.getenv("REQUEST_METHOD") orelse "GET") orelse { + return error.InvalidRequestMethod; + }, + .target = std.os.getenv("REQUEST_URI") orelse "/", }; - - try server.serve(); + var res = Response{ + .allocator = allocator, + .request = req, + .status = .bad_request, + .transfer_encoding = .none, + .headers = Headers.init(allocator), + }; + const ctx = Ctx{ .db = db }; + try router.handle(&res, ctx); } -fn notfound(res: *std.http.Server.Response, _: Ctx) Err!void { +fn notfound(res: *Response, _: Ctx) Err!void { const rr = @embedFile("templates/notfound.html"); try constresponse(res, rr, .not_found); } -fn badrequest(res: *std.http.Server.Response, _: Ctx) Err!void { +fn badrequest(res: *Response, _: Ctx) Err!void { const rr = @embedFile("templates/badrequest.html"); try constresponse(res, rr, .bad_request); } -fn constresponse(res: *std.http.Server.Response, rr: []const u8, status: std.http.Status) Err!void { +fn constresponse(res: *Response, rr: []const u8, status: std.http.Status) Err!void { res.status = status; res.transfer_encoding = .{ .content_length = rr.len }; try res.headers.append("content-type", "text/html"); try res.do(); - try res.writeAll(rr); + try res.writer().writeAll(rr); try res.finish(); } -fn get_comment(res: *std.http.Server.Response, ctx: Ctx, params: Params) Err!void { - _ = params; +fn get_comment(res: *Response, ctx: Ctx, _: Params) Err!void { var p = try zws.Path.parse(res.allocator, res.request.target); defer p.deinit(); const url: []const u8 = try p.get_query_param("url") orelse { @@ -100,7 +184,6 @@ fn get_comment(res: *std.http.Server.Response, ctx: Ctx, params: Params) Err!voi const cmt = try stmt.read_struct(Comment); try comments.append(cmt); } - std.log.debug("found {} comments for url {s}", .{ comments.items.len, url }); const rr = @embedFile("templates/comments.html"); const tt = comptime mustache.parseComptime(rr, .{}, .{}); @@ -117,7 +200,7 @@ fn get_comment(res: *std.http.Server.Response, ctx: Ctx, params: Params) Err!voi try res.finish(); } -fn post_comment(res: *std.http.Server.Response, ctx: Ctx, _: Params) Err!void { +fn post_comment(res: *Response, ctx: Ctx, _: Params) Err!void { var body_aa = std.ArrayList(u8).init(res.allocator); try res.reader().readAllArrayList(&body_aa, 1_000_000); var body = try body_aa.toOwnedSlice(); @@ -169,7 +252,7 @@ fn post_comment(res: *std.http.Server.Response, ctx: Ctx, _: Params) Err!void { try res.finish(); } -fn get_form(res: *std.http.Server.Response, ctx: Ctx, _: Params) Err!void { +fn get_form(res: *Response, ctx: Ctx, _: Params) Err!void { var p = try zws.Path.parse(res.allocator, res.request.target); defer p.deinit(); const url: []const u8 = try p.get_query_param("url") orelse { |