cutelyst  3.7.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
memcachedsessionstore.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2017-2022 Matthias Fehring <mf@huessenbergnetz.de>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include "memcachedsessionstore_p.h"
7 
8 #include <Cutelyst/Application>
9 #include <Cutelyst/Engine>
10 #include <Cutelyst/Context>
11 #include <Cutelyst/Plugins/Memcached/Memcached>
12 
13 #include <QLoggingCategory>
14 #include <QCoreApplication>
15 
16 using namespace Cutelyst;
17 
18 Q_LOGGING_CATEGORY(C_MEMCACHEDSESSIONSTORE, "cutelyst.plugin.memcachedsessionstore", QtWarningMsg)
19 
20 #define SESSION_STORE_MEMCD_SAVE QStringLiteral("_c_session_store_memcd_save")
21 #define SESSION_STORE_MEMCD_DATA QStringLiteral("_c_session_store_memcd_data")
22 
23 static QVariantHash loadMemcSessionData(Context *c, const QString &sid, const QString &groupKey);
24 
26  SessionStore(parent), d_ptr(new MemcachedSessionStorePrivate)
27 {
29  Q_ASSERT_X(app, "construct MemachedSessionStore", "you have to specifiy a pointer to the Application object");
30  const QVariantMap map = app->engine()->config(QStringLiteral("Cutelyst_MemcachedSessionStore_Plugin"));
31  d->groupKey = map.value(QStringLiteral("group_key")).toString();
32 }
33 
35 {
36 
37 }
38 
39 QVariant MemcachedSessionStore::getSessionData(Context *c, const QString &sid, const QString &key, const QVariant &defaultValue)
40 {
41  QVariant data;
43  const QVariantHash hash = loadMemcSessionData(c, sid, d->groupKey);
44  data = hash.value(key, defaultValue);
45  return data;
46 }
47 
48 bool MemcachedSessionStore::storeSessionData(Context *c, const QString &sid, const QString &key, const QVariant &value)
49 {
51  QVariantHash data = loadMemcSessionData(c, sid, d->groupKey);
52  data.insert(key, value);
53  c->setStash(SESSION_STORE_MEMCD_DATA, data);
54  c->setStash(SESSION_STORE_MEMCD_SAVE, true);
55 
56  return true;
57 }
58 
59 bool MemcachedSessionStore::deleteSessionData(Context *c, const QString &sid, const QString &key)
60 {
62  QVariantHash data = loadMemcSessionData(c, sid, d->groupKey);
63  data.remove(key);
64  c->setStash(SESSION_STORE_MEMCD_DATA, data);
65  c->setStash(SESSION_STORE_MEMCD_SAVE, true);
66 
67  return true;
68 }
69 
71 {
72  Q_UNUSED(c)
73  Q_UNUSED(expires)
74 
75  return true;
76 }
77 
78 void MemcachedSessionStore::setGroupKey(const QString &groupKey)
79 {
81  d->groupKey = groupKey;
82 }
83 
84 QVariantHash loadMemcSessionData(Context *c, const QString &sid, const QString &groupKey)
85 {
86  QVariantHash data;
87  const QVariant sessionVariant = c->stash(SESSION_STORE_MEMCD_DATA);
88  if (!sessionVariant.isNull()) {
89  data = sessionVariant.toHash();
90  return data;
91  }
92 
93  const static QString sessionPrefix = QCoreApplication::applicationName() + QLatin1String("_sess_");
94  const QString sessionKey = sessionPrefix + sid;
95 
96  QObject::connect(c->app(), &Application::afterDispatch, c, [=] () {
97  if (!c->stash(SESSION_STORE_MEMCD_SAVE).toBool()) {
98  return;
99  }
100 
101  const QVariantHash data = c->stash(SESSION_STORE_MEMCD_DATA).toHash();
102 
103  if (data.isEmpty()) {
104  bool ok = false;
105  if (groupKey.isEmpty()) {
106  ok = Memcached::remove(sessionKey);
107  } else {
108  ok = Memcached::removeByKey(groupKey, sessionKey);
109  }
110  if (!ok) {
111  qCWarning(C_MEMCACHEDSESSIONSTORE, "Failed to remove session from Memcached.");
112  }
113  } else {
114  bool ok = false;
115  const time_t expires = data.value(QStringLiteral("expires")).value<time_t>();
116  if (groupKey.isEmpty()) {
117  ok = Memcached::set(sessionKey, data, expires);
118  } else {
119  ok = Memcached::setByKey(groupKey, sessionKey, data, expires);
120  }
121  if (!ok) {
122  qCWarning(C_MEMCACHEDSESSIONSTORE, "Failed to store session to Memcached.");
123  }
124  }
125  });
126 
127  if (groupKey.isEmpty()) {
128  data = Memcached::get<QVariantHash>(sessionKey);
129  } else {
130  data = Memcached::getByKey<QVariantHash>(groupKey, sessionKey);
131  }
132 
133  c->setStash(SESSION_STORE_MEMCD_DATA, data);
134 
135  return data;
136 }
137 
138 #include "moc_memcachedsessionstore.cpp"
The Cutelyst Application.
Definition: application.h:43
Engine * engine() const noexcept
void afterDispatch(Cutelyst::Context *c)
The Cutelyst Context.
Definition: context.h:39
void stash(const QVariantHash &unite)
Definition: context.cpp:546
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:218
Application * app() const noexcept
Definition: context.cpp:91
QVariantMap config(const QString &entity) const
user configuration for the application
Definition: engine.cpp:292
Memcached based session store.
virtual bool storeSessionData(Context *c, const QString &sid, const QString &key, const QVariant &value) final
MemcachedSessionStore(Application *app, QObject *parent=nullptr)
void setGroupKey(const QString &groupKey)
virtual QVariant getSessionData(Context *c, const QString &sid, const QString &key, const QVariant &defaultValue) final
virtual bool deleteSessionData(Context *c, const QString &sid, const QString &key) final
virtual bool deleteExpiredSessions(Context *c, quint64 expires) final
static bool set(const QString &key, const QByteArray &value, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:233
static bool setByKey(const QString &groupKey, const QString &key, const QByteArray &value, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:272
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:8