cutelyst  4.6.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 
18 Q_LOGGING_CATEGORY(C_MEMCACHEDSESSIONSTORE, "cutelyst.plugin.sessionmemcached", QtWarningMsg)
19 
20 const QString MemcachedSessionStorePrivate::stashKeyMemcdSave{u"_c_session_store_memcd_save"_qs};
21 const QString MemcachedSessionStorePrivate::stashKeyMemcdData{u"_c_session_store_memcd_data"_qs};
22 
23 static QVariantHash
24  loadMemcSessionData(Context *c, const QByteArray &sid, const QByteArray &groupKey);
25 
26 MemcachedSessionStore::MemcachedSessionStore(Cutelyst::Application *app, QObject *parent)
27  : SessionStore(parent)
28  , d_ptr(new MemcachedSessionStorePrivate)
29 {
31  Q_ASSERT_X(app,
32  "construct MemachedSessionStore",
33  "you have to specifiy a pointer to the Application object");
34  const QVariantMap map = app->engine()->config(u"Cutelyst_MemcachedSessionStore_Plugin"_qs);
35  d->groupKey = map.value(u"group_key"_qs).toString().toLatin1();
36 }
37 
38 MemcachedSessionStore::~MemcachedSessionStore() = default;
39 
40 QVariant MemcachedSessionStore::getSessionData(Context *c,
41  const QByteArray &sid,
42  const QString &key,
43  const QVariant &defaultValue)
44 {
45  QVariant data;
47  const QVariantHash hash = loadMemcSessionData(c, sid, d->groupKey);
48  data = hash.value(key, defaultValue);
49  return data;
50 }
51 
52 bool MemcachedSessionStore::storeSessionData(Context *c,
53  const QByteArray &sid,
54  const QString &key,
55  const QVariant &value)
56 {
58  QVariantHash data = loadMemcSessionData(c, sid, d->groupKey);
59  data.insert(key, value);
60  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdData, data);
61  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdSave, true);
62 
63  return true;
64 }
65 
66 bool MemcachedSessionStore::deleteSessionData(Context *c, const QByteArray &sid, const QString &key)
67 {
69  QVariantHash data = loadMemcSessionData(c, sid, d->groupKey);
70  data.remove(key);
71  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdData, data);
72  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdSave, true);
73 
74  return true;
75 }
76 
77 bool MemcachedSessionStore::deleteExpiredSessions(Context *c, quint64 expires)
78 {
79  Q_UNUSED(c)
80  Q_UNUSED(expires)
81 
82  return true;
83 }
84 
85 void MemcachedSessionStore::setGroupKey(const QByteArray &groupKey)
86 {
88  d->groupKey = groupKey;
89 }
90 
91 QVariantHash loadMemcSessionData(Context *c, const QByteArray &sid, const QByteArray &groupKey)
92 {
93  QVariantHash data;
94  const QVariant sessionVariant = c->stash(MemcachedSessionStorePrivate::stashKeyMemcdData);
95  if (!sessionVariant.isNull()) {
96  data = sessionVariant.toHash();
97  return data;
98  }
99 
100  const static QByteArray sessionPrefix =
102  const QByteArray sessionKey = sessionPrefix + sid;
103 
105  if (!c->stash(MemcachedSessionStorePrivate::stashKeyMemcdSave).toBool()) {
106  return;
107  }
108 
109  const QVariantHash data =
110  c->stash(MemcachedSessionStorePrivate::stashKeyMemcdData).toHash();
111 
112  if (data.isEmpty()) {
113  bool ok = false;
114  if (groupKey.isEmpty()) {
115  ok = Memcached::remove(sessionKey);
116  } else {
117  ok = Memcached::removeByKey(groupKey, sessionKey);
118  }
119  if (!ok) {
120  qCWarning(C_MEMCACHEDSESSIONSTORE)
121  << "Failed to remove session from Memcached." << groupKey << sessionKey;
122  }
123  } else {
124  bool ok = false;
125  const auto expires = data.value(u"expires"_qs).value<time_t>();
126  if (groupKey.isEmpty()) {
127  ok = Memcached::set(sessionKey, data, expires);
128  } else {
129  ok = Memcached::setByKey(groupKey, sessionKey, data, expires);
130  }
131  if (!ok) {
132  qCWarning(C_MEMCACHEDSESSIONSTORE) << "Failed to store session to Memcached.";
133  }
134  }
135  });
136 
137  if (groupKey.isEmpty()) {
138  data = Memcached::get<QVariantHash>(sessionKey);
139  } else {
140  data = Memcached::getByKey<QVariantHash>(groupKey, sessionKey);
141  }
142 
143  c->setStash(MemcachedSessionStorePrivate::stashKeyMemcdData, data);
144 
145  return data;
146 }
147 
148 #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:212
The Cutelyst Context.
Definition: context.h:42
bool isNull() const const
void stash(const QVariantHash &unite)
Definition: context.cpp:562
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:91
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()