Cutelyst  3.4.0
sessionstorefile.cpp
1 /*
2  * Copyright (C) 2015-2018 Daniel Nicoletti <dantti12@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include "sessionstorefile.h"
19 
20 #include <Cutelyst/Context>
21 #include <Cutelyst/Application>
22 
23 #include <QDir>
24 #include <QFile>
25 #include <QLockFile>
26 #include <QDataStream>
27 #include <QLoggingCategory>
28 #include <QCoreApplication>
29 
30 using namespace Cutelyst;
31 
32 Q_LOGGING_CATEGORY(C_SESSION_FILE, "cutelyst.plugin.sessionfile", QtWarningMsg)
33 
34 #define SESSION_STORE_FILE_SAVE QStringLiteral("_c_session_store_file_save")
35 #define SESSION_STORE_FILE_DATA QStringLiteral("_c_session_store_file_data")
36 
37 static QVariantHash loadSessionData(Context *c, const QString &sid);
38 
40 {
41 
42 }
43 
44 SessionStoreFile::~SessionStoreFile()
45 {
46 }
47 
48 QVariant SessionStoreFile::getSessionData(Context *c, const QString &sid, const QString &key, const QVariant &defaultValue)
49 {
50  const QVariantHash data = loadSessionData(c, sid);
51 
52  return data.value(key, defaultValue);
53 }
54 
55 bool SessionStoreFile::storeSessionData(Context *c, const QString &sid, const QString &key, const QVariant &value)
56 {
57  QVariantHash data = loadSessionData(c, sid);
58 
59  data.insert(key, value);
60  c->setStash(SESSION_STORE_FILE_DATA, data);
61  c->setStash(SESSION_STORE_FILE_SAVE, true);
62 
63  return true;
64 }
65 
67 {
68  QVariantHash data = loadSessionData(c, sid);
69 
70  data.remove(key);
71  c->setStash(SESSION_STORE_FILE_DATA, data);
72  c->setStash(SESSION_STORE_FILE_SAVE, true);
73 
74  return true;
75 }
76 
77 static QString rootPath()
78 {
79  static QString rootPath = QDir::tempPath()
80  + QLatin1Char('/')
82  + QLatin1String("/session/data");
83  return rootPath;
84 }
85 
87 {
88  Q_UNUSED(c)
89  if (!expires) {
90  QDir dir(rootPath());
91  dir.removeRecursively();
92  }
93  return true;
94 }
95 
96 QVariantHash loadSessionData(Context *c, const QString &sid)
97 {
98  QVariantHash data;
99  const QVariant sessionVariant = c->stash(SESSION_STORE_FILE_DATA);
100  if (!sessionVariant.isNull()) {
101  data = sessionVariant.toHash();
102  return data;
103  }
104 
105  const QString root = rootPath();
106 
107  auto file = new QFile(root + QLatin1Char('/') + sid, c);
108  if (!file->open(QIODevice::ReadWrite)) {
109  if (!QDir().mkpath(root)) {
110  qCWarning(C_SESSION_FILE) << "Failed to create path for session object" << root;
111  return data;
112  }
113 
114  if (!file->open(QIODevice::ReadWrite)) {
115  return data;
116  }
117  }
118 
119  // Commit data when Context gets deleted
120  QObject::connect(c->app(), &Application::afterDispatch, c, [c,file] {
121  if (!c->stash(SESSION_STORE_FILE_SAVE).toBool()) {
122  return;
123  }
124 
125  const QVariantHash data = c->stash(SESSION_STORE_FILE_DATA).toHash();
126 
127  if (data.isEmpty()) {
128  QFile::remove(file->fileName());
129  } else {
130  QLockFile lock(file->fileName() + QLatin1String(".lock"));
131  if (lock.lock()) {
132  QDataStream in(file);
133 
134  if (file->pos()) {
135  file->seek(0);
136  }
137 
138  in << data;
139 
140  if (file->pos() < file->size()) {
141  file->resize(file->pos());
142  }
143 
144  file->flush();
145  lock.unlock();
146  }
147  }
148  });
149 
150  // Load data
151  QLockFile lock(file->fileName() + QLatin1String(".lock"));
152  if (lock.lock()) {
153  QDataStream in(file);
154  in >> data;
155  lock.unlock();
156  }
157 
158  c->setStash(SESSION_STORE_FILE_DATA, data);
159 
160  return data;
161 }
162 
163 #include "moc_sessionstorefile.cpp"
void afterDispatch(Cutelyst::Context *c)
The Cutelyst Context.
Definition: context.h:52
void stash(const QVariantHash &unite)
Definition: context.cpp:553
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:225
Application * app() const noexcept
Definition: context.cpp:104
SessionStoreFile(QObject *parent=nullptr)
virtual bool deleteSessionData(Context *c, const QString &sid, const QString &key) final
virtual bool deleteExpiredSessions(Context *c, quint64 expires) final
virtual bool storeSessionData(Context *c, const QString &sid, const QString &key, const QVariant &value) final
virtual QVariant getSessionData(Context *c, const QString &sid, const QString &key, const QVariant &defaultValue) final
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:8
bool removeRecursively()
QString tempPath()
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool isNull() const const
QHash< QString, QVariant > toHash() const const