cutelyst  5.0.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
sessionstorefile.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2015-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "sessionstorefile.h"
6 
7 #include <Cutelyst/Application>
8 #include <Cutelyst/Context>
9 
10 #include <QCoreApplication>
11 #include <QDataStream>
12 #include <QDir>
13 #include <QFile>
14 #include <QLockFile>
15 #include <QLoggingCategory>
16 
17 using namespace Cutelyst;
18 using namespace Qt::StringLiterals;
19 
20 Q_LOGGING_CATEGORY(C_SESSION_FILE, "cutelyst.plugin.sessionfile", QtWarningMsg)
21 
22 #define SESSION_STORE_FILE_SAVE u"_c_session_store_file_save"_s
23 #define SESSION_STORE_FILE_DATA u"_c_session_store_file_data"_s
24 
25 namespace {
26 QVariantHash loadSessionData(Context *c, const QByteArray &sid);
27 
28 inline QString rootPath()
29 {
30  static QString rootPath =
31  QDir::tempPath() + u'/' + QCoreApplication::applicationName() + u"/session/data";
32  return rootPath;
33 }
34 } // namespace
35 
37  : SessionStore(parent)
38 {
39 }
40 
42 {
43 }
44 
46  const QByteArray &sid,
47  const QString &key,
48  const QVariant &defaultValue)
49 {
50  const QVariantHash data = loadSessionData(c, sid);
51 
52  return data.value(key, defaultValue);
53 }
54 
56  const QByteArray &sid,
57  const QString &key,
58  const QVariant &value)
59 {
60  QVariantHash data = loadSessionData(c, sid);
61 
62  data.insert(key, value);
63  c->setStash(SESSION_STORE_FILE_DATA, data);
64  c->setStash(SESSION_STORE_FILE_SAVE, true);
65 
66  return true;
67 }
68 
70 {
71  QVariantHash data = loadSessionData(c, sid);
72 
73  data.remove(key);
74  c->setStash(SESSION_STORE_FILE_DATA, data);
75  c->setStash(SESSION_STORE_FILE_SAVE, true);
76 
77  return true;
78 }
79 
81 {
82  Q_UNUSED(c)
83  if (!expires) {
84  QDir dir(rootPath());
85  dir.removeRecursively();
86  }
87  return true;
88 }
89 
90 namespace {
91 QVariantHash loadSessionData(Context *c, const QByteArray &sid)
92 {
93  QVariantHash data;
94  const QVariant sessionVariant = c->stash(SESSION_STORE_FILE_DATA);
95  if (!sessionVariant.isNull()) {
96  data = sessionVariant.toHash();
97  return data;
98  }
99 
100  const QString root = rootPath();
101 
102  auto file = new QFile(root + u'/' + QString::fromLatin1(sid), c);
103  if (!file->open(QIODevice::ReadWrite)) {
104  if (!QDir().mkpath(root)) {
105  qCWarning(C_SESSION_FILE) << "Failed to create path for session object" << root;
106  return data;
107  }
108 
109  if (!file->open(QIODevice::ReadWrite)) {
110  return data;
111  }
112  }
113 
114  // Commit data when Context gets deleted
115  QObject::connect(c->app(), &Application::afterDispatch, c, [c, file] {
116  if (!c->stash(SESSION_STORE_FILE_SAVE).toBool()) {
117  return;
118  }
119 
120  const QVariantHash data = c->stash(SESSION_STORE_FILE_DATA).toHash();
121 
122  if (data.isEmpty()) {
123  QFile::remove(file->fileName());
124  } else {
125  QLockFile lock(file->fileName() + u".lock");
126  if (lock.lock()) {
127  QDataStream in(file);
128 
129  if (file->pos()) {
130  file->seek(0);
131  }
132 
133  in << data;
134 
135  if (file->pos() < file->size()) {
136  file->resize(file->pos());
137  }
138 
139  file->flush();
140  lock.unlock();
141  }
142  }
143  });
144 
145  // Load data
146  QLockFile lock(file->fileName() + u".lock");
147  if (lock.lock()) {
148  QDataStream in(file);
149  in >> data;
150  lock.unlock();
151  }
152 
153  c->setStash(SESSION_STORE_FILE_DATA, data);
154 
155  return data;
156 }
157 } // namespace
158 
159 #include "moc_sessionstorefile.cpp"
QHash< QString, QVariant > toHash() const const
virtual bool storeSessionData(Context *c, const QByteArray &sid, const QString &key, const QVariant &value) final
bool remove()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool removeRecursively()
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:213
SessionStoreFile(QObject *parent=nullptr)
The Cutelyst Context.
Definition: context.h:42
bool isNull() const const
QString tempPath()
void stash(const QVariantHash &unite)
Definition: context.cpp:562
The Cutelyst namespace holds all public Cutelyst API.
virtual QVariant getSessionData(Context *c, const QByteArray &sid, const QString &key, const QVariant &defaultValue) final
Application * app() const noexcept
Definition: context.cpp:92
QString fromLatin1(QByteArrayView str)
void afterDispatch(Cutelyst::Context *c)
Abstract class to create a session store.
Definition: session.h:35
virtual bool deleteExpiredSessions(Context *c, quint64 expires) final
virtual bool deleteSessionData(Context *c, const QByteArray &sid, const QString &key) final
bool mkpath(const QString &dirPath) const const
QString applicationName()