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 }