cutelyst  4.4.0
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 
19 Q_LOGGING_CATEGORY(C_SESSION_FILE, "cutelyst.plugin.sessionfile", QtWarningMsg)
20 
21 #define SESSION_STORE_FILE_SAVE QStringLiteral("_c_session_store_file_save")
22 #define SESSION_STORE_FILE_DATA QStringLiteral("_c_session_store_file_data")
23 
24 static QVariantHash loadSessionData(Context *c, const QByteArray &sid);
25 
27  : SessionStore(parent)
28 {
29 }
30 
32 {
33 }
34 
36  const QByteArray &sid,
37  const QString &key,
38  const QVariant &defaultValue)
39 {
40  const QVariantHash data = loadSessionData(c, sid);
41 
42  return data.value(key, defaultValue);
43 }
44 
46  const QByteArray &sid,
47  const QString &key,
48  const QVariant &value)
49 {
50  QVariantHash data = loadSessionData(c, sid);
51 
52  data.insert(key, value);
53  c->setStash(SESSION_STORE_FILE_DATA, data);
54  c->setStash(SESSION_STORE_FILE_SAVE, true);
55 
56  return true;
57 }
58 
60 {
61  QVariantHash data = loadSessionData(c, sid);
62 
63  data.remove(key);
64  c->setStash(SESSION_STORE_FILE_DATA, data);
65  c->setStash(SESSION_STORE_FILE_SAVE, true);
66 
67  return true;
68 }
69 
70 static QString rootPath()
71 {
72  static QString rootPath =
73  QDir::tempPath() + u'/' + QCoreApplication::applicationName() + u"/session/data";
74  return rootPath;
75 }
76 
78 {
79  Q_UNUSED(c)
80  if (!expires) {
81  QDir dir(rootPath());
82  dir.removeRecursively();
83  }
84  return true;
85 }
86 
87 QVariantHash loadSessionData(Context *c, const QByteArray &sid)
88 {
89  QVariantHash data;
90  const QVariant sessionVariant = c->stash(SESSION_STORE_FILE_DATA);
91  if (!sessionVariant.isNull()) {
92  data = sessionVariant.toHash();
93  return data;
94  }
95 
96  const QString root = rootPath();
97 
98  auto file = new QFile(root + u'/' + QString::fromLatin1(sid), c);
99  if (!file->open(QIODevice::ReadWrite)) {
100  if (!QDir().mkpath(root)) {
101  qCWarning(C_SESSION_FILE) << "Failed to create path for session object" << root;
102  return data;
103  }
104 
105  if (!file->open(QIODevice::ReadWrite)) {
106  return data;
107  }
108  }
109 
110  // Commit data when Context gets deleted
111  QObject::connect(c->app(), &Application::afterDispatch, c, [c, file] {
112  if (!c->stash(SESSION_STORE_FILE_SAVE).toBool()) {
113  return;
114  }
115 
116  const QVariantHash data = c->stash(SESSION_STORE_FILE_DATA).toHash();
117 
118  if (data.isEmpty()) {
119  QFile::remove(file->fileName());
120  } else {
121  QLockFile lock(file->fileName() + QLatin1String(".lock"));
122  if (lock.lock()) {
123  QDataStream in(file);
124 
125  if (file->pos()) {
126  file->seek(0);
127  }
128 
129  in << data;
130 
131  if (file->pos() < file->size()) {
132  file->resize(file->pos());
133  }
134 
135  file->flush();
136  lock.unlock();
137  }
138  }
139  });
140 
141  // Load data
142  QLockFile lock(file->fileName() + QLatin1String(".lock"));
143  if (lock.lock()) {
144  QDataStream in(file);
145  in >> data;
146  lock.unlock();
147  }
148 
149  c->setStash(SESSION_STORE_FILE_DATA, data);
150 
151  return data;
152 }
153 
154 #include "moc_sessionstorefile.cpp"
void afterDispatch(Cutelyst::Context *c)
The Cutelyst Context.
Definition: context.h:42
void stash(const QVariantHash &unite)
Definition: context.cpp:562
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:212
Application * app() const noexcept
Definition: context.cpp:91
SessionStoreFile(QObject *parent=nullptr)
virtual bool storeSessionData(Context *c, const QByteArray &sid, const QString &key, const QVariant &value) final
virtual bool deleteSessionData(Context *c, const QByteArray &sid, const QString &key) final
virtual QVariant getSessionData(Context *c, const QByteArray &sid, const QString &key, const QVariant &defaultValue) final
virtual bool deleteExpiredSessions(Context *c, quint64 expires) final
Abstract class to create a session store.
Definition: session.h:36
The Cutelyst namespace holds all public Cutelyst API.
bool removeRecursively()
QString tempPath()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString fromLatin1(QByteArrayView str)
bool isNull() const const
QHash< QString, QVariant > toHash() const const