1 module vibe.db.redis.sessionstore;
2
3 import vibe.data.json;
4 import vibe.db.redis.redis;
5 import vibe.http.session;
6 import core.time;
7 import std.typecons : Nullable;
8 import std.variant;
9
10
11 final class RedisSessionStore : SessionStore {
12 private {
13 RedisDatabase m_db;
14 Duration m_expirationTime = Duration.max;
15 }
16
17 /** Constructs a new Redis session store.
18
19 Params:
20 host = Host name of the Redis instance to connect to
21 database = Database number to select on the server
22 port = Optional port number to use when connecting to the server
23 */
24 this(string host, long database, ushort port = RedisClient.defaultPort)
25 {
26 m_db = connectRedis(host, port).getDatabase(database);
27 }
28
29 /** Release all connections that are not in use. Call this at the end of
30 * your program to clean up unused sockets that may be held by the GC.
31 */
32 void releaseUnusedConnections() @safe
33 {
34 m_db.client.releaseUnusedConnections();
35 }
36
37 /** The duration without access after which a session expires.
38 */
39 @property Duration expirationTime() const { return m_expirationTime; }
40 /// ditto
41 @property void expirationTime(Duration dur) { m_expirationTime = dur; }
42
43 @property SessionStorageType storageType() const { return SessionStorageType.json; }
44
45 Session create()
46 {
47 auto s = createSessionInstance();
48 m_db.hset(s.id, "__SESS", true); // set place holder to avoid create empty hash
49 assert(m_db.exists(s.id));
50 if (m_expirationTime != Duration.max)
51 m_db.expire(s.id, m_expirationTime);
52 return s;
53 }
54
55 Session open(string id)
56 {
57 if (m_db.exists(id))
58 {
59 auto s = createSessionInstance(id);
60 if (m_expirationTime != Duration.max)
61 m_db.expire(s.id, m_expirationTime);
62 return s;
63 }
64 return Session.init;
65 }
66
67 void set(string id, string name, Variant value)
68 @trusted {
69 m_db.hset(id, name, value.get!Json.toString());
70 }
71
72 Variant get(string id, string name, lazy Variant defaultVal)
73 @trusted {
74 auto v = m_db.hget!(Nullable!string)(id, name);
75 return v.isNull ? defaultVal : Variant(parseJsonString(v.get));
76 }
77
78 bool isKeySet(string id, string key)
79 {
80 return m_db.hexists(id, key);
81 }
82
83 void remove(string id, string key)
84 {
85 m_db.hdel(id, key);
86 }
87
88 void destroy(string id)
89 {
90 m_db.del(id);
91 }
92
93 int delegate(int delegate(ref string key, ref Variant value)) iterateSession(string id)
94 {
95 assert(false, "Not available for RedisSessionStore");
96 }
97
98 int iterateSession(string id, scope int delegate(string key) @safe del)
99 {
100 auto res = m_db.hkeys(id);
101 while (!res.empty) {
102 auto key = res.front;
103 res.popFront();
104 if (auto ret = del(key))
105 return ret;
106 }
107 return 0;
108 }
109 }