const std = @import("std"); const config = @import("../../config.zig"); const Storage = @import("../root.zig"); pub const Session = @import("session.zig"); const Self = @This(); pub const empty: Self = .{ .cache = .empty, }; cache: std.StringHashMapUnmanaged(Session), rw_lock: std.Thread.RwLock = .{}, pub fn add(self: *Self, storage: *Storage, info: Storage.User.Info) !*Session { self.rw_lock.lock(); defer self.rw_lock.unlock(); const session = try Session.init(storage.allocator, info); errdefer session.deinit(storage.allocator); try self.cache.put(storage.allocator, session.fingerprint, session); return self.cache.getPtr(session.fingerprint) orelse unreachable; } pub fn renew(self: *Self, storage: *Storage, fingerprint: []const u8) !*Session { self.rw_lock.lockShared(); if (self.cache.get(fingerprint)) |s| { self.rw_lock.unlockShared(); self.rw_lock.lock(); defer self.rw_lock.unlock(); var session = s; try session.reset(); try self.cache.put(storage.allocator, session.fingerprint, session); _ = self.cache.remove(fingerprint); return self.cache.getPtr(session.fingerprint) orelse unreachable; } else { self.rw_lock.unlockShared(); } return error.SessionNotFound; } pub fn remove(self: *Self, storage: *Storage, fingerprint: []const u8) void { self.rw_lock.lockShared(); if (self.cache.getPtr(fingerprint)) |session| { self.rw_lock.unlockShared(); self.rw_lock.lock(); defer self.rw_lock.unlock(); session.deinit(storage.allocator); _ = self.cache.remove(fingerprint); } else { self.rw_lock.unlockShared(); } } pub fn get(self: *Self, storage: *Storage, fingerprint: []const u8) ?*Session { self.rw_lock.lockShared(); defer self.rw_lock.unlockShared(); if (self.cache.getPtr(fingerprint)) |session| { const now = std.time.Instant.now() catch return null; const since = now.since(session.age); if (since > storage.config.session_expires_after) { session.deinit(storage.allocator); _ = self.cache.remove(fingerprint); return null; } return session; } return null; }