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 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 {
|
||||||
|
|
Loading…
Reference in a new issue