aboutsummaryrefslogtreecommitdiff
path: root/zig-comments/src/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'zig-comments/src/main.zig')
-rw-r--r--zig-comments/src/main.zig123
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 {