]> gitweb.ps.run Git - chirp/commitdiff
dunno
authorpatrick-scho <patrick.schoenberger@posteo.de>
Sat, 9 Nov 2024 10:22:25 +0000 (11:22 +0100)
committerpatrick-scho <patrick.schoenberger@posteo.de>
Sat, 9 Nov 2024 10:22:25 +0000 (11:22 +0100)
.gitignore [new file with mode: 0644]
build.zig
src/epoll.zig [new file with mode: 0644]
src/main.zig
todo.md

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..be3ab7a
--- /dev/null
@@ -0,0 +1,3 @@
+db
+zig-out
+.zig-cache
index 7a13429b26b04e000cb321bdca628429b744ac39..f7d33f1ff32c99d370d09672b90a403c8fcdd268 100644 (file)
--- 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 (file)
index 0000000..afca339
--- /dev/null
@@ -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);
+                }
+            }
+        }
+    }
+}
index eeada2b20562ae4805d1cf201465d3ba80ecba5a..b016e1b89c93320fb87e8a87ea9c4d63b6caf4ba 100644 (file)
@@ -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 ca69d6ad2e6e0ebbaa0469617880d2decd4e2f74..aa23f7ec55e6928bbfc889a3ccb091d0d6e6a96d 100644 (file)
--- a/todo.md
+++ b/todo.md
@@ -3,6 +3,8 @@
   - check
   - del
   - interface: dbi <KEY, VAL>
+  - change optionals to errors
+  - self: *const Self -> self: Self
 - generate ids
 - Account
   - Register