diff --git a/src/main/db.zig b/src/main/db.zig deleted file mode 100644 index d4802fd..0000000 --- a/src/main/db.zig +++ /dev/null @@ -1,143 +0,0 @@ -const std = @import("std"); -const util = @import("./util.zig"); -const Uuid = util.Uuid; -const ciutf8 = util.ciutf8; -const assert = std.debug.assert; - -pub const Account = struct { - id: Uuid, - handle: []const u8, -}; - -const IdSource = struct { - data: *anyopaque, - nextFn: fn (*anyopaque) Uuid, - - pub fn init(pointer: anytype, comptime nextFn: fn (ptr: @TypeOf(pointer)) Uuid) IdSource { - const Ptr = @TypeOf(pointer); - assert(@typeInfo(Ptr) == .Pointer); // Must be a pointer - assert(@typeInfo(Ptr).Pointer.size == .One); // Must be a single-item pointer - assert(@typeInfo(@typeInfo(Ptr).Pointer.child) == .Struct); // Must point to a struct - const gen = struct { - fn next(ptr: *anyopaque) Uuid { - const alignment = @typeInfo(Ptr).Pointer.alignment; - const self = @ptrCast(Ptr, @alignCast(alignment, ptr)); - return nextFn(self); - } - }; - - return .{ - .data = pointer, - .nextFn = gen.next, - }; - } - - fn next(self: *IdSource) Uuid { - return self.nextFn(self.data); - } -}; - -const ConstId = struct { - val: Uuid = Uuid.Nil, - fn next(self: *ConstId) Uuid { - return self.val; - } - - fn source(self: *ConstId) IdSource { - return IdSource.init(self, next); - } -}; - -pub const MemoryDb = struct { - const Self = @This(); - const Table = std.ArrayListUnmanaged; - - allocator: std.mem.Allocator, - id_source: IdSource, - - accounts: Table(Account), - - pub fn init(allocator: std.mem.Allocator, id_source: IdSource) Self { - return .{ - .allocator = allocator, - .id_source = id_source, - .accounts = Table(Account){}, - }; - } - - pub fn deinit(self: *Self) void { - self.accounts.deinit(self.allocator); - } - - pub fn createAccount(self: *Self, handle: []const u8) !Account { - const id = self.id_source.next(); - - for (self.accounts.items) |a| { - if (ciutf8.eql(handle, a.handle)) { - return error.DuplicateHandle; - } - - if (Uuid.eql(id, a.id)) { - return error.DuplicateId; - } - } - - const acc = .{ - .id = id, - .handle = handle, - }; - - try self.accounts.append(self.allocator, acc); - - return acc; - } - - pub fn lookupAccountByHandle(self: *Self, handle: []const u8) !?Account { - for (self.accounts.items) |a| { - if (ciutf8.eql(handle, a.handle)) return a; - } - - return null; - } -}; - -test "createAccount" { - var next_id = ConstId{}; - var db = MemoryDb.init(std.testing.allocator, next_id.source()); - defer db.deinit(); - - const admin_id = try Uuid.parse("00000000-ffff-0000-0000-000000000000"); - const sally_id = try Uuid.parse("00000000-eeee-0000-0000-000000000000"); - const other_id = try Uuid.parse("00000000-dddd-0000-0000-000000000000"); - - next_id.val = admin_id; - const admin = try db.createAccount("admin"); - try std.testing.expectEqual(admin_id, admin.id); - try std.testing.expectEqualStrings("admin", admin.handle); - - next_id.val = other_id; - try std.testing.expectError(error.DuplicateHandle, db.createAccount("admin")); - - next_id.val = sally_id; - const sally = try db.createAccount("sally"); - try std.testing.expectEqual(sally_id, sally.id); - try std.testing.expectEqualStrings("sally", sally.handle); - - next_id.val = admin_id; - try std.testing.expectError(error.DuplicateId, db.createAccount("jaina")); -} - -test "lookupAccountByHandle" { - var next_id = ConstId{}; - var db = MemoryDb.init(std.testing.allocator, next_id.source()); - defer db.deinit(); - - const admin_id = try Uuid.parse("00000000-ffff-0000-0000-000000000000"); - const sally_id = try Uuid.parse("00000000-eeee-0000-0000-000000000000"); - - next_id.val = admin_id; - _ = try db.createAccount("admin"); - - next_id.val = sally_id; - _ = try db.createAccount("sally"); -} diff --git a/src/main/db2.zig b/src/main/db2.zig deleted file mode 100644 index fdefaf5..0000000 --- a/src/main/db2.zig +++ /dev/null @@ -1,93 +0,0 @@ -const std = @import("std"); -const util = @import("util"); - -pub const Stream = std.io.StreamSource; - -pub const DocDb = struct { - const Keys = struct { - public_id: ?[]const u8, - local_id: u64, - }; - - const Entry = struct { - keys: Keys, - document: []const u8, - }; - - alloc: std.mem.Allocator, - docs: std.ArrayListUnmanaged(Entry) = .{}, - id_counter: u64 = 0, - - // TODO: hash shit - - pub fn init(alloc: std.mem.Allocator) DocDb { - return DocDb{ - .alloc = alloc, - }; - } - - fn getId(self: *DocDb, doc: []const u8) ?[]const u8 { - var ts = std.json.TokenStream.init(doc); - const HasId = struct { id: []const u8 }; - const parsed = std.json.parse(HasId, &ts, .{ .allocator = self.alloc, .ignore_unknown_fields = true }) catch return null; - return parsed.id; - } - - fn genLocalId(self: *DocDb) u64 { - self.id_counter += 1; - return self.id_counter; - } - - pub fn store(self: *DocDb, doc: []const u8) !u64 { - if (!std.json.validate(doc)) return error.InvalidJson; - - // todo: check for collisions - const clone = try dupe(self.alloc, doc); - errdefer self.alloc.free(clone); - - const local_id = self.genLocalId(); - const public_id = self.getId(clone); - - try self.docs.append(self.alloc, Entry{ - .keys = .{ - .public_id = public_id, - .local_id = local_id, - }, - .document = clone, - }); - - return local_id; - } - - pub fn getByLocalId(self: *DocDb, id: u64) !?Stream { - for (self.docs.items) |doc| { - if (id == doc.keys.local_id) { - return prepareDoc(doc); - } - } - - return null; - } - - pub fn getByPublicId(self: *DocDb, id: []const u8) !?Stream { - for (self.docs.items) |doc| { - if (doc.keys.public_id) |pub_id| { - if (util.ciutf8.eql(id, pub_id)) { - return prepareDoc(doc); - } - } - } - - return null; - } - - fn dupe(alloc: std.mem.Allocator, doc: []const u8) ![]u8 { - var clone = try alloc.alloc(u8, doc.len); - std.mem.copy(u8, clone, doc); - return clone; - } - - fn prepareDoc(e: Entry) Stream { - return std.io.StreamSource{ .const_buffer = std.io.fixedBufferStream(e.document) }; - } -}; diff --git a/src/main/main.zig b/src/main/main.zig index 19b5dd5..409aaa6 100644 --- a/src/main/main.zig +++ b/src/main/main.zig @@ -1,6 +1,6 @@ const std = @import("std"); +const builtin = @import("builtin"); const http = @import("http"); -const db = @import("./db2.zig"); // this thing is overcomplicated and weird. stop this const Router = http.Router(*RequestServer); @@ -8,55 +8,42 @@ const Route = Router.Route; const RouteArgs = http.RouteArgs; const router = Router{ .routes = &[_]Route{ - Route.new(.POST, "/object", postObject), - Route.new(.GET, "/object/:id", getObject), + Route.new(.GET, "/healthcheck", healthcheck), }, }; -fn postObject(srv: *RequestServer, ctx: *http.server.Context, _: RouteArgs) !void { +const json_options = if (builtin.mode == .Debug) +.{ + .whitespace = .{ + .indent = .{ .Space = 2 }, + .separator = true, + }, +} else .{ + .whitespace = .{ + .indent = .None, + .separator = false, + }, +}; + +fn healthcheck(srv: *RequestServer, ctx: *http.server.Context, _: RouteArgs) !void { const alloc = srv.alloc; const headers = http.Headers.init(alloc); var stream = try ctx.openResponse(&headers, .ok); - const writer = stream.writer(); defer stream.close(); - try writer.print("Page for {s}\n", .{ctx.request.path}); - - const id = srv.doc_db.store(ctx.request.body.?); - try writer.print("{}", .{id}); - - try stream.finish(); -} - -fn getObject(srv: *RequestServer, ctx: *http.server.Context, args: RouteArgs) !void { - const alloc = srv.alloc; - const headers = http.Headers.init(alloc); - - var stream = try ctx.openResponse(&headers, .ok); const writer = stream.writer(); - defer stream.close(); - - //try writer.print("id: {s}\n", .{args.get("id").?}); - const id = try std.fmt.parseInt(u64, args.get("id").?, 10); - var doc_stream = (try srv.doc_db.getByLocalId(id)).?; - const doc = doc_stream.reader(); - - var buf: [1 << 8]u8 = undefined; - const count = try doc.readAll(&buf); - try writer.writeAll(buf[0..count]); + try std.json.stringify(.{ .status = "ok" }, json_options, writer); try stream.finish(); } const RequestServer = struct { alloc: std.mem.Allocator, - doc_db: db.DocDb, fn init(alloc: std.mem.Allocator) RequestServer { return RequestServer{ .alloc = alloc, - .doc_db = db.DocDb.init(alloc), }; } @@ -73,25 +60,8 @@ const RequestServer = struct { defer ctx.close(); router.dispatch(self, &ctx, ctx.request.method, ctx.request.path) catch unreachable; - - //handleRequest(alloc, &ctx) catch unreachable; } } - - fn handleRequest(alloc: std.mem.Allocator, ctx: *http.server.Context) !void { - const headers = http.Headers.init(alloc); - - var stream = try ctx.openResponse(&headers, .ok); - const writer = stream.writer(); - defer stream.close(); - - try writer.print("Page for {s}\n", .{ctx.request.path}); - if (ctx.request.body) |body| { - try writer.print("Echoing body: \n{s}", .{body}); - } - - try stream.finish(); - } }; pub fn main() anyerror!void {