cleaning up
This commit is contained in:
parent
3bd1bfc972
commit
8d71846826
3 changed files with 17 additions and 283 deletions
143
src/main/db.zig
143
src/main/db.zig
|
@ -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");
|
||||
}
|
|
@ -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) };
|
||||
}
|
||||
};
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue