Move api to package

This commit is contained in:
jaina heartles 2022-10-08 13:47:54 -07:00
parent 1aec8031e6
commit 581159963f
14 changed files with 43 additions and 74 deletions

View File

@ -17,10 +17,16 @@ const sql_pkg = std.build.Pkg{
.dependencies = &.{util_pkg},
};
const api_pkg = std.build.Pkg{
.name = "api",
.source = std.build.FileSource.relative("src/api/lib.zig"),
.dependencies = &.{ util_pkg, sql_pkg },
};
const main_pkg = std.build.Pkg{
.name = "main",
.source = std.build.FileSource.relative("src/main/main.zig"),
.dependencies = &.{ util_pkg, http_pkg, sql_pkg },
.dependencies = &.{ util_pkg, http_pkg, sql_pkg, api_pkg },
};
pub fn build(b: *std.build.Builder) void {
@ -41,6 +47,7 @@ pub fn build(b: *std.build.Builder) void {
exe.addPackage(sql_pkg);
exe.addPackage(util_pkg);
exe.addPackage(http_pkg);
exe.addPackage(api_pkg);
exe.linkSystemLibrary("sqlite3");
exe.linkSystemLibrary("pq");

View File

@ -1,18 +1,16 @@
const std = @import("std");
const util = @import("util");
const builtin = @import("builtin");
const sql = @import("sql");
const DateTime = util.DateTime;
const Uuid = util.Uuid;
const Config = @import("./main.zig").Config;
const services = struct {
const communities = @import("./api/communities.zig");
const users = @import("./api/users.zig");
const auth = @import("./api/auth.zig");
const invites = @import("./api/invites.zig");
const notes = @import("./api/notes.zig");
const communities = @import("./services/communities.zig");
const users = @import("./services/users.zig");
const auth = @import("./services/auth.zig");
const invites = @import("./services/invites.zig");
const notes = @import("./services/notes.zig");
};
pub const RegistrationRequest = struct {
@ -59,38 +57,6 @@ pub const NoteResponse = struct {
pub const CommunityQueryArgs = services.communities.QueryArgs;
// Frees an api struct and its fields allocated from alloc
pub fn free(alloc: std.mem.Allocator, val: anytype) void {
switch (@typeInfo(@TypeOf(val))) {
.Pointer => |ptr_info| switch (ptr_info.size) {
.One => {
free(alloc, val.*);
alloc.destroy(val);
},
.Slice => {
for (val) |elem| free(alloc, elem);
alloc.free(val);
},
else => unreachable,
},
.Struct => inline for (std.meta.fields(@TypeOf(val))) |f| free(alloc, @field(val, f.name)),
.Array => for (val) |elem| free(alloc, elem),
.Optional => if (val) |opt| free(alloc, opt),
.Bool, .Int, .Float, .Enum => {},
else => unreachable,
}
}
threadlocal var prng: std.rand.DefaultPrng = undefined;
pub fn initThreadPrng(seed: u64) void {
prng = std.rand.DefaultPrng.init(seed +% std.Thread.getCurrentId());
}
pub fn getRandom() std.rand.Random {
return prng.random();
}
pub fn isAdminSetup(db: sql.Db) !bool {
_ = services.communities.adminCommunityId(db) catch |err| switch (err) {
error.NotFound => return false,
@ -129,16 +95,14 @@ pub fn setupAdmin(db: sql.Db, origin: []const u8, username: []const u8, password
pub const ApiSource = struct {
db_conn: *sql.Conn,
config: Config,
pub const Conn = ApiConn(sql.Db);
const root_username = "root";
pub fn init(cfg: Config, db_conn: *sql.Conn) !ApiSource {
pub fn init(db_conn: *sql.Conn) !ApiSource {
return ApiSource{
.db_conn = db_conn,
.config = cfg,
};
}

View File

@ -3,8 +3,6 @@ const builtin = @import("builtin");
const util = @import("util");
const sql = @import("sql");
const getRandom = @import("../api.zig").getRandom;
const Uuid = util.Uuid;
const DateTime = util.DateTime;
@ -70,7 +68,7 @@ pub fn create(db: anytype, origin: []const u8, options: CreateOptions, alloc: st
// Require TLS on production builds
if (scheme != .https and builtin.mode != .Debug) return error.UnsupportedScheme;
const id = Uuid.randV4(getRandom());
const id = Uuid.randV4(util.getThreadPrng());
// TODO: wrap this in TX
if (db.queryRow(

View File

@ -1,7 +1,6 @@
const std = @import("std");
const builtin = @import("builtin");
const util = @import("util");
const getRandom = @import("../api.zig").getRandom;
const Uuid = util.Uuid;
const DateTime = util.DateTime;
@ -47,10 +46,10 @@ pub const InviteOptions = struct {
};
pub fn create(db: anytype, created_by: Uuid, community_id: ?Uuid, options: InviteOptions, alloc: std.mem.Allocator) !Uuid {
const id = Uuid.randV4(getRandom());
const id = Uuid.randV4(util.getThreadPrng());
var code_bytes: [rand_len]u8 = undefined;
getRandom().bytes(&code_bytes);
util.getThreadPrng().bytes(&code_bytes);
const code = try alloc.alloc(u8, code_len);
defer alloc.free(code);

View File

@ -4,7 +4,6 @@ const sql = @import("sql");
const Uuid = util.Uuid;
const DateTime = util.DateTime;
const getRandom = @import("../api.zig").getRandom;
pub const Note = struct {
id: Uuid,
@ -23,7 +22,7 @@ pub fn create(
content: []const u8,
alloc: std.mem.Allocator,
) CreateError!Uuid {
const id = Uuid.randV4(getRandom());
const id = Uuid.randV4(util.getThreadPrng());
db.insert("note", .{
.id = id,

View File

@ -4,7 +4,6 @@ const auth = @import("./auth.zig");
const Uuid = util.Uuid;
const DateTime = util.DateTime;
const getRandom = @import("../api.zig").getRandom;
pub const CreateError = error{
UsernameTaken,
@ -81,7 +80,7 @@ pub fn create(
kind: Kind,
alloc: std.mem.Allocator,
) CreateError!Uuid {
const id = Uuid.randV4(getRandom());
const id = Uuid.randV4(util.getThreadPrng());
try validateUsername(username);

View File

@ -2,9 +2,8 @@ const std = @import("std");
const root = @import("root");
const builtin = @import("builtin");
const http = @import("http");
const api = @import("./api.zig");
const api = @import("api");
const util = @import("util");
const Uuid = util.Uuid;
pub const auth = @import("./controllers/auth.zig");
pub const communities = @import("./controllers/communities.zig");

View File

@ -4,7 +4,6 @@ const builtin = @import("builtin");
const http = @import("http");
const Uuid = @import("util").Uuid;
const RegistrationInfo = @import("../api.zig").RegistrationInfo;
const utils = @import("../controllers.zig").utils;
const RequestServer = root.RequestServer;
@ -20,7 +19,6 @@ pub const login = struct {
var api = try utils.getApiConn(srv, ctx);
defer api.close();
std.log.debug("connected to api", .{});
const token = try api.login(credentials.username, credentials.password);
try utils.respondJson(ctx, .ok, token);

View File

@ -15,7 +15,7 @@ pub const create = struct {
// TODO: get rid of this temporary struct, find json library that lets me extend
// it to parse UUIDs/etc in place
const InviteRequest = struct {
const Kind = @import("../api.zig").InviteRequest.Kind;
const Kind = @import("api").InviteRequest.Kind;
name: ?[]const u8 = null,

View File

@ -3,13 +3,11 @@ const http = @import("http");
const Uuid = @import("util").Uuid;
const utils = @import("../controllers.zig").utils;
const NoteCreateInfo = @import("../api.zig").NoteCreateInfo;
const NoteCreateInfo = @import("api").NoteCreateInfo;
const RequestServer = root.RequestServer;
const RouteArgs = http.RouteArgs;
//pub const reacts = @import("./notes/reacts.zig");
pub const create = struct {
pub const method = .POST;
pub const path = "/notes";

View File

@ -1,10 +1,9 @@
const std = @import("std");
const root = @import("root");
const builtin = @import("builtin");
const http = @import("http");
const Uuid = @import("util").Uuid;
const RegistrationRequest = @import("../api.zig").RegistrationRequest;
const RegistrationRequest = @import("api").RegistrationRequest;
const utils = @import("../controllers.zig").utils;
const RequestServer = root.RequestServer;

View File

@ -4,8 +4,8 @@ const sql = @import("sql");
const http = @import("http");
const util = @import("util");
pub const api = @import("./api.zig");
pub const migrations = @import("./migrations.zig");
const api = @import("api");
const migrations = @import("./migrations.zig");
const Uuid = util.Uuid;
const c = @import("./controllers.zig");
@ -112,7 +112,6 @@ fn runAdminSetup(db: sql.Db, alloc: std.mem.Allocator) !void {
fn prepareDb(db: sql.Db, alloc: std.mem.Allocator) !void {
try migrations.up(db);
api.initThreadPrng(@bitCast(u64, std.time.milliTimestamp()));
if (!try api.isAdminSetup(db)) {
std.log.info("Performing first-time admin creation...", .{});
@ -136,14 +135,14 @@ fn prepareDb(db: sql.Db, alloc: std.mem.Allocator) !void {
}
pub fn main() !void {
try util.seedThreadPrng();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var cfg = try loadConfig(gpa.allocator());
var db_conn = try sql.Conn.open(cfg.db);
try prepareDb(try db_conn.acquire(), gpa.allocator());
//try migrations.up(&db_conn);
//try api.setupAdmin(&db_conn, "http://localhost:8080", "root", "password", gpa.allocator());
var api_src = try api.ApiSource.init(cfg, &db_conn);
var api_src = try api.ApiSource.init(&db_conn);
var srv = try RequestServer.init(gpa.allocator(), &api_src, cfg);
return srv.listenAndRun(std.net.Address.parseIp("0.0.0.0", 8080) catch unreachable);
}

View File

@ -169,9 +169,19 @@ pub fn deepClone(alloc: std.mem.Allocator, val: anytype) !@TypeOf(val) {
return result;
}
test {
_ = ciutf8;
_ = Uuid;
_ = PathIter;
_ = DateTime;
threadlocal var prng: ?std.rand.DefaultPrng = null;
pub fn getThreadPrng() std.rand.Random {
if (prng) |*p| return p.random();
@panic("Thread PRNG not seeded");
}
pub fn seedThreadPrng() !void {
@setCold(true);
var buf: [8]u8 = undefined;
try std.os.getrandom(&buf);
prng = std.rand.DefaultPrng.init(@bitCast(u64, buf));
}