From: patrick-scho Date: Sat, 9 Nov 2024 10:22:25 +0000 (+0100) Subject: dunno X-Git-Url: https://gitweb.ps.run/chirp/commitdiff_plain/8ce4f0b76cab1963cd0a8ad55bf5b30b9eae917f dunno --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be3ab7a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +db +zig-out +.zig-cache diff --git a/build.zig b/build.zig index 7a13429..f7d33f1 100644 --- a/build.zig +++ b/build.zig @@ -14,6 +14,15 @@ pub fn build(b: *std.Build) void { .optimize = optimize, }); + const epoll = b.addExecutable(.{ + .name = "epoll", + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = .{ .cwd_relative = "src/epoll.zig" }, + .target = target, + .optimize = optimize, + }); + const lmdb_mod = b.createModule(.{ .root_source_file = .{ .cwd_relative = "../ziglmdb/src/lmdb.zig" }, }); @@ -22,10 +31,13 @@ pub fn build(b: *std.Build) void { "./lmdb/libraries/liblmdb/midl.c", "./lmdb/libraries/liblmdb/mdb.c", } }); - exe.root_module.addImport("lmdb", lmdb_mod); + exe.root_module.addImport("lmdb", lmdb_mod); exe.linkLibC(); + epoll.root_module.addImport("lmdb", lmdb_mod); + epoll.linkLibC(); + b.installArtifact(exe); const run_cmd = b.addRunArtifact(exe); @@ -38,4 +50,8 @@ pub fn build(b: *std.Build) void { const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); + + const run_epoll_cmd = b.addRunArtifact(epoll); + const run_epoll_step = b.step("runepoll", "run epoll"); + run_epoll_step.dependOn(&run_epoll_cmd.step); } diff --git a/src/epoll.zig b/src/epoll.zig new file mode 100644 index 0000000..afca339 --- /dev/null +++ b/src/epoll.zig @@ -0,0 +1,80 @@ +const std = @import("std"); +const net = std.net; +const posix = std.posix; +const linux = std.os.linux; +const lmdb = @import("lmdb"); + +fn test_lmdb(env: *lmdb.Env) !void { + const txn = try env.txn(); + defer txn.abort(); + + const sessions = try txn.dbi("sessions", u64, u64); + var cursor = try sessions.cursor(); + + var key: u64 = undefined; + var user_id_maybe = cursor.get(&key, .First); + + while (user_id_maybe) |user_id| { + _ = user_id; + user_id_maybe = cursor.get(&key, .Next); + } +} + +pub fn main() !void { + const address = try std.net.Address.parseIp("127.0.0.1", 5882); + + const tpe: u32 = posix.SOCK.STREAM | posix.SOCK.NONBLOCK; + const protocol = posix.IPPROTO.TCP; + const listener = try posix.socket(address.any.family, tpe, protocol); + defer posix.close(listener); + + const BACKLOG = 256; + + try posix.setsockopt(listener, posix.SOL.SOCKET, posix.SO.REUSEADDR, &std.mem.toBytes(@as(c_int, 1))); + try posix.bind(listener, &address.any, address.getOsSockLen()); + try posix.listen(listener, BACKLOG); + + // epoll_create1 takes flags. We aren't using any in these examples + const efd = try posix.epoll_create1(0); + defer posix.close(efd); + + { + // monitor our listening socket + var event = linux.epoll_event{ .events = linux.EPOLL.IN, .data = .{ .fd = listener } }; + try posix.epoll_ctl(efd, linux.EPOLL.CTL_ADD, listener, &event); + } + + var env = lmdb.Env.open("db", 1024 * 100); + defer env.close(); + + var ready_list: [BACKLOG]linux.epoll_event = undefined; + while (true) { + const ready_count = posix.epoll_wait(efd, &ready_list, -1); + for (ready_list[0..ready_count]) |ready| { + const ready_socket = ready.data.fd; + if (ready_socket == listener) { + const client_socket = try posix.accept(listener, null, null, posix.SOCK.NONBLOCK); + errdefer posix.close(client_socket); + var event = linux.epoll_event{ .events = linux.EPOLL.IN, .data = .{ .fd = client_socket } }; + try posix.epoll_ctl(efd, linux.EPOLL.CTL_ADD, client_socket, &event); + } else { + var closed = false; + var buf: [4096]u8 = undefined; + const read = posix.read(ready_socket, &buf) catch 0; + if (read == 0) { + closed = true; + } else { + // std.debug.print("[{d}] got: {s}\n", .{ ready_socket, buf[0..read] }); + + try test_lmdb(&env); + + _ = try posix.write(ready_socket, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: 5\r\n\r\nabcde"); + } + + if (closed or ready.events & linux.EPOLL.RDHUP == linux.EPOLL.RDHUP) { + posix.close(ready_socket); + } + } + } + } +} diff --git a/src/main.zig b/src/main.zig index eeada2b..b016e1b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4,19 +4,18 @@ const lmdb = @import("lmdb"); // db {{{ const Prng = struct { - prng: std.Random.DefaultPrng = std.Random.DefaultPrng.init(0), + var prng: std.Random.DefaultPrng = std.Random.DefaultPrng.init(0); - pub fn gen_id(self: *Prng, dbi: anytype) Id { - var id = self.prng.next(); + pub fn gen_id(dbi: anytype) Id { + var id = Prng.prng.next(); while (dbi.has(id)) { - id = self.prng.next(); + id = Prng.prng.next(); } return id; } }; -var prng = Prng{}; // }}} @@ -114,116 +113,125 @@ pub fn verify_password(password: []const u8, hash: PasswordHash) bool { pub fn register_user(env: *lmdb.Env, username: []const u8, password: []const u8) !void { const username_array = try Username.fromSlice(username); - var user_id: Id = undefined; - - if (env.txn()) |*txn| { - defer txn.commit(); - if (txn.dbi("users", Id, User)) |users| { - user_id = prng.gen_id(users); - users.put(user_id, User{ - .username = username_array, - .password_hash = try hash_password(password), - }); - } + const txn = try env.txn(); + defer { + txn.commit(); + env.sync(); } - if (env.txn()) |txn| { - defer txn.commit(); - if (txn.dbi("user_ids", @TypeOf(username_array.buffer), Id)) |user_ids| { - user_ids.put(username_array.buffer, user_id); - } - } + const users = try txn.dbi("users", Id, User); + const user_id = Prng.gen_id(users); + users.put(user_id, User{ + .username = username_array, + .password_hash = try hash_password(password), + }); - env.sync(); + const user_ids = try txn.dbi("user_ids", Username, Id); + user_ids.put(username_array, user_id); } -pub fn login_user(env: *lmdb.Env, username: []const u8, password: []const u8) ?SessionToken { - const username_array = Username.fromSlice(username) catch return null; - - var user_id_maybe: ?Id = null; - var user_maybe: ?User = null; +pub fn login_user(env: *lmdb.Env, username: []const u8, password: []const u8) !SessionToken { + const username_array = try Username.fromSlice(username); - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("user_ids", @TypeOf(username_array.buffer), Id)) |user_ids| { - user_id_maybe = user_ids.get(username_array.buffer); - std.debug.print("id: {?}\n", .{user_id_maybe}); - } + const txn = try env.txn(); + defer { + txn.commit(); + env.sync(); } - if (user_id_maybe) |user_id| { - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("users", Id, User)) |users| { - user_maybe = users.get(user_id_maybe.?); - } + const user_ids = try txn.dbi("user_ids", Username, Id); + const user_id = user_ids.get(username_array) orelse return error.UnknownUsername; + std.debug.print("id: {}\n", .{user_id}); + + const users = try txn.dbi("users", Id, User); + if (users.get(user_id)) |user| { + if (verify_password(password, user.password_hash)) { + const sessions = try txn.dbi("sessions", Id, Id); + const session_token = Prng.gen_id(sessions); + sessions.put(session_token, user_id); + return session_token; + } else { + return error.IncorrectPassword; } + } else { + return error.UserNotFound; + } +} - if (user_maybe) |user| { - if (verify_password(password, user.password_hash)) { - if (env.txn()) |txn| { - defer txn.commit(); - if (txn.dbi("sessions", Id, Id)) |sessions| { - const session_token = prng.gen_id(sessions); - sessions.put(session_token, user_id); - return session_token; - } - } - } - } +fn logout_user(env: *lmdb.Env, session_token: SessionToken) !void { + const txn = try env.txn(); + defer { + txn.commit(); + env.sync(); } - return null; + const sessions = try txn.dbi("sessions", Id, Id); + sessions.del(session_token); } -fn logout_user(env: *lmdb.Env, session_token: SessionToken) void { - if (env.txn()) |txn| { - defer txn.commit(); - if (txn.dbi("sessions", Id, Id)) |sessions| { - sessions.del(session_token); - } +fn get_session_user(env: *lmdb.Env, session_token: SessionToken) !User { + const txn = try env.txn(); + defer txn.abort(); + + const sessions = try txn.dbi("sessions", Id, Id); + const users = try txn.dbi("users", Id, User); + + if (sessions.get(session_token)) |user_id| { + return users.get(user_id) orelse error.UnknownUser; + } else { + return error.SessionNotFound; } } -fn get_session_user(env: *lmdb.Env, session_token: SessionToken) ?User { - var user_id_maybe: ?Id = null; +// }}} - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("sessions", Id, Id)) |sessions| { - user_id_maybe = sessions.get(session_token); - } - } +fn list_users(env: *lmdb.Env) !void { + const txn = try env.txn(); + defer txn.abort(); - if (user_id_maybe) |user_id| { - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("users", Id, User)) |users| { - return users.get(user_id); - } - } + const users = try txn.dbi("users", Id, User); + var cursor = try users.cursor(); + + var key: Id = undefined; + var user_maybe = cursor.get(&key, .First); + + while (user_maybe) |user| { + std.debug.print("[{}] {s}\n", .{ key, user.username.constSlice() }); + + user_maybe = cursor.get(&key, .Next); } +} +fn list_user_ids(env: *lmdb.Env) !void { + const txn = try env.txn(); + defer txn.abort(); - return null; + const user_ids = try txn.dbi("user_ids", Username, Id); + var cursor = try user_ids.cursor(); + + var key: Username = undefined; + var user_id_maybe = cursor.get(&key, .First); + + while (user_id_maybe) |user_id| { + std.debug.print("[{s}] {}\n", .{ key.constSlice(), user_id }); + + user_id_maybe = cursor.get(&key, .Next); + } } -// }}} +fn list_sessions(env: *lmdb.Env) !void { + const txn = try env.txn(); + defer txn.abort(); -fn list_users(env: *lmdb.Env) void { - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("users", Id, User)) |users| { - var cursor = users.cursor(); + const sessions = try txn.dbi("sessions", SessionToken, Id); + var cursor = try sessions.cursor(); - var key: Id = undefined; - var user_maybe = cursor.get(&key, .First); + var key: SessionToken = undefined; + var user_id_maybe = cursor.get(&key, .First); - while (user_maybe) |user| { - std.debug.print("[{}] {s}\n", .{ key, user.username.constSlice() }); + while (user_id_maybe) |user_id| { + std.debug.print("[{}] {}\n", .{ key, user_id }); - user_maybe = cursor.get(&key, .Next); - } - } + user_id_maybe = cursor.get(&key, .Next); } } @@ -237,10 +245,15 @@ pub fn main() !void { defer server.deinit(); // lmdb - var env = lmdb.Env.open("db", 1024 * 1024 * 10); + var env = lmdb.Env.open("db", 1024 * 100); defer env.close(); - list_users(&env); + std.debug.print("Users:\n", .{}); + try list_users(&env); + std.debug.print("User IDs:\n", .{}); + try list_user_ids(&env); + std.debug.print("Sessions:\n", .{}); + try list_sessions(&env); accept: while (true) { const conn = try server.accept(); @@ -267,6 +280,8 @@ pub fn main() !void { .user = user, .session_token = session_token, }; + } else |err| { + std.debug.print("get_session_user err: {}\n", .{err}); } // TODO: delete session token // TODO: add changeable headers (set, delete cookies) @@ -339,12 +354,13 @@ pub fn main() !void { .{ .name = "Set-Cookie", .value = cookie_buffer.constSlice() }, }, }); - } else { + } else |err| { + std.debug.print("login_user err: {}\n", .{err}); try redirect(&req, "/login"); } } else if (std.mem.eql(u8, req.head.target, "/logout")) { if (logged_in) |login| { - logout_user(&env, login.session_token); + try logout_user(&env, login.session_token); try req.respond("", .{ .status = .see_other, .extra_headers = &.{ diff --git a/todo.md b/todo.md index ca69d6a..aa23f7e 100644 --- a/todo.md +++ b/todo.md @@ -3,6 +3,8 @@ - check - del - interface: dbi + - change optionals to errors + - self: *const Self -> self: Self - generate ids - Account - Register