cleaning up

This commit is contained in:
jaina heartles 2022-07-10 15:19:21 -07:00
parent 3bd1bfc972
commit 8d71846826
3 changed files with 17 additions and 283 deletions

View file

@ -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");
}

View file

@ -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) };
}
};

View file

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin");
const http = @import("http"); const http = @import("http");
const db = @import("./db2.zig");
// this thing is overcomplicated and weird. stop this // this thing is overcomplicated and weird. stop this
const Router = http.Router(*RequestServer); const Router = http.Router(*RequestServer);
@ -8,55 +8,42 @@ const Route = Router.Route;
const RouteArgs = http.RouteArgs; const RouteArgs = http.RouteArgs;
const router = Router{ const router = Router{
.routes = &[_]Route{ .routes = &[_]Route{
Route.new(.POST, "/object", postObject), Route.new(.GET, "/healthcheck", healthcheck),
Route.new(.GET, "/object/:id", getObject),
}, },
}; };
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 alloc = srv.alloc;
const headers = http.Headers.init(alloc); const headers = http.Headers.init(alloc);
var stream = try ctx.openResponse(&headers, .ok); var stream = try ctx.openResponse(&headers, .ok);
const writer = stream.writer();
defer stream.close(); 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(); const writer = stream.writer();
defer stream.close(); try std.json.stringify(.{ .status = "ok" }, json_options, writer);
//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 stream.finish(); try stream.finish();
} }
const RequestServer = struct { const RequestServer = struct {
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
doc_db: db.DocDb,
fn init(alloc: std.mem.Allocator) RequestServer { fn init(alloc: std.mem.Allocator) RequestServer {
return RequestServer{ return RequestServer{
.alloc = alloc, .alloc = alloc,
.doc_db = db.DocDb.init(alloc),
}; };
} }
@ -73,25 +60,8 @@ const RequestServer = struct {
defer ctx.close(); defer ctx.close();
router.dispatch(self, &ctx, ctx.request.method, ctx.request.path) catch unreachable; 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 { pub fn main() anyerror!void {