Cutelyst  2.5.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 
66 bool SessionStoreFile::deleteSessionData(Context *c, const QString &sid, const QString &key)
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 
78 {
79  Q_UNUSED(c)
80  Q_UNUSED(expires)
81  return true;
82 }
83 
84 QVariantHash loadSessionData(Context *c, const QString &sid)
85 {
86  QVariantHash data;
87  const QVariant sessionVariant = c->stash(SESSION_STORE_FILE_DATA);
88  if (!sessionVariant.isNull()) {
89  data = sessionVariant.toHash();
90  return data;
91  }
92 
93  const static QString root = QDir::tempPath()
94  + QLatin1Char('/')
95  + QCoreApplication::applicationName()
96  + QLatin1String("/session/data");
97 
98  auto file = new QFile(root + QLatin1Char('/') + 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, [=] () {
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"
Application * app() const
Definition: context.cpp:104
void afterDispatch(Context *c)
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:207
SessionStoreFile(QObject *parent=nullptr)
The Cutelyst Context.
Definition: context.h:50
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
virtual QVariant getSessionData(Context *c, const QString &sid, const QString &key, const QVariant &defaultValue) final
virtual bool storeSessionData(Context *c, const QString &sid, const QString &key, const QVariant &value) final
virtual bool deleteExpiredSessions(Context *c, quint64 expires) final
virtual bool deleteSessionData(Context *c, const QString &sid, const QString &key) final
void stash(const QVariantHash &unite)
Definition: context.h:515