cutelyst  4.9.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-2023 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/Context>
10 #include <Cutelyst/Engine>
11 #include <Cutelyst/Plugins/Memcached/Memcached>
12 
13 #include <QCoreApplication>
14 #include <QLoggingCategory>
15 
16 using namespace Cutelyst;
17 using namespace Qt::Literals::StringLiterals;
18 
19 Q_LOGGING_CATEGORY(C_MEMCACHEDSESSIONSTORE, "cutelyst.plugin.sessionmemcached", QtWarningMsg)
20 
21 const QString MemcachedSessionStorePrivate::stashKeyMemcdSave{u"_c_session_store_memcd_save"_s};
22 const QString MemcachedSessionStorePrivate::stashKeyMemcdData{u"_c_session_store_memcd_data"_s};
23 
24 static QVariantHash
25  loadMemcSessionData(Context *c, const QByteArray &sid, const QByteArray &groupKey);
26 
27 MemcachedSessionStore::MemcachedSessionStore(Cutelyst::Application *app, QObject *parent)
28  : SessionStore(parent)
29  , d_ptr(new MemcachedSessionStorePrivate)
30 {
32  Q_ASSERT_X(app,
33  "construct MemachedSessionStore",
34  "you have to specifiy a pointer to the Application object");
35  const QVariantMap map = app->engine()->config(u"Cutelyst_MemcachedSessionStore_Plugin"_s);
36  d->groupKey = map.value(u"group_key"_s).toString().toLatin1();
37 }
38 
39 MemcachedSessionStore::~MemcachedSessionStore() = default;
40 
41 QVariant MemcachedSessionStore::getSessionData(Context *c,
42  const QByteArray &sid,
43  const QString &key,
44  const QVariant &defaultValue)
45 {
46  QVariant data;
48  const QVariantHash hash = loadMemcSessionData(c, sid, d->groupKey);
49  data = hash.value(key, defaultValue);
50  return data;
51 }
52 
53 bool MemcachedSessionStore::storeSessionData(Context *c,
54  const QByteArray &sid,
55  const QString &key,
56  const QVariant &value)
57 {
59  QVariantHash data = loadMemcSessionData(c, sid, d->groupKey);
60  data.insert(key, value);
61  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdData, data);
62  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdSave, true);
63 
64  return true;
65 }
66 
67 bool MemcachedSessionStore::deleteSessionData(Context *c, const QByteArray &sid, const QString &key)
68 {
70  QVariantHash data = loadMemcSessionData(c, sid, d->groupKey);
71  data.remove(key);
72  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdData, data);
73  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdSave, true);
74 
75  return true;
76 }
77 
78 bool MemcachedSessionStore::deleteExpiredSessions(Context *c, quint64 expires)
79 {
80  Q_UNUSED(c)
81  Q_UNUSED(expires)
82 
83  return true;
84 }
85 
86 void MemcachedSessionStore::setGroupKey(const QByteArray &groupKey)
87 {
89  d->groupKey = groupKey;
90 }
91 
92 QVariantHash loadMemcSessionData(Context *c, const QByteArray &sid, const QByteArray &groupKey)
93 {
94  QVariantHash data;
95  const QVariant sessionVariant = c->stash(MemcachedSessionStorePrivate::stashKeyMemcdData);
96  if (!sessionVariant.isNull()) {
97  data = sessionVariant.toHash();
98  return data;
99  }
100 
101  const static QByteArray sessionPrefix =
103  const QByteArray sessionKey = sessionPrefix + sid;
104 
106  if (!c->stash(MemcachedSessionStorePrivate::stashKeyMemcdSave).toBool()) {
107  return;
108  }
109 
110  const QVariantHash data =
111  c->stash(MemcachedSessionStorePrivate::stashKeyMemcdData).toHash();
112 
113  if (data.isEmpty()) {
114  bool ok = false;
115  if (groupKey.isEmpty()) {
116  ok = Memcached::remove(sessionKey);
117  } else {
118  ok = Memcached::removeByKey(groupKey, sessionKey);
119  }
120  if (!ok) {
121  qCWarning(C_MEMCACHEDSESSIONSTORE)
122  << "Failed to remove session from Memcached." << groupKey << sessionKey;
123  }
124  } else {
125  bool ok = false;
126  const auto expires = data.value(u"expires"_s).value<time_t>();
127  if (groupKey.isEmpty()) {
128  ok = Memcached::set(sessionKey, data, expires);
129  } else {
130  ok = Memcached::setByKey(groupKey, sessionKey, data, expires);
131  }
132  if (!ok) {
133  qCWarning(C_MEMCACHEDSESSIONSTORE) << "Failed to store session to Memcached.";
134  }
135  }
136  });
137 
138  if (groupKey.isEmpty()) {
139  data = Memcached::get<QVariantHash>(sessionKey);
140  } else {
141  data = Memcached::getByKey<QVariantHash>(groupKey, sessionKey);
142  }
143 
144  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdData, data);
145 
146  return data;
147 }
148 
149 #include "moc_memcachedsessionstore.cpp"
Memcached based session store.
QHash< QString, QVariant > toHash() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool isEmpty() const const
T value() const const
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:213
The Cutelyst Context.
Definition: context.h:42
bool isNull() const const
void stash(const QVariantHash &unite)
Definition: context.cpp:563
QVariantMap config(const QString &entity) const
Definition: engine.cpp:263
The Cutelyst namespace holds all public Cutelyst API.
Application * app() const noexcept
Definition: context.cpp:92
void afterDispatch(Cutelyst::Context *c)
Abstract class to create a session store.
Definition: session.h:35
QByteArray toLatin1() const const
The Cutelyst application.
Definition: application.h:72
Engine * engine() const noexcept
QString applicationName()