QGpgME 20.5.1.0000638
Qt API for GpgME
Loading...
Searching...
No Matches
threadedjobmixin.h
1/*
2 threadedjobmixin.h
3
4 This file is part of qgpgme, the Qt API binding for gpgme
5 Copyright (c) 2008 Klarälvdalens Datakonsult AB
6 Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
7 Software engineering by Intevation GmbH
8
9 QGpgME is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 QGpgME is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23 In addition, as a special exception, the copyright holders give
24 permission to link the code of this program with any edition of
25 the Qt library by Trolltech AS, Norway (or with modified versions
26 of Qt that use the same license as Qt), and distribute linked
27 combinations including the two. You must obey the GNU General
28 Public License in all respects for all of the code used other than
29 Qt. If you modify this file, you may extend this exception to
30 your version of the file, but you are not obligated to do so. If
31 you do not wish to do so, delete this exception statement from
32 your version.
33*/
34
35#ifndef __QGPGME_THREADEDJOBMIXING_H__
36#define __QGPGME_THREADEDJOBMIXING_H__
37
38#include <QMutex>
39#include <QMutexLocker>
40#include <QThread>
41#include <QString>
42#include <QIODevice>
43
44#ifdef BUILDING_QGPGME
45# include "context.h"
46# include "interfaces/progressprovider.h"
47#else
48# include <gpgme++/context.h>
49# include <gpgme++/interfaces/progressprovider.h>
50#endif
51
52#include "job.h"
53
54#include <cassert>
55#include <functional>
56
57namespace QGpgME
58{
59namespace _detail
60{
61
62QString audit_log_as_html(GpgME::Context *ctx, GpgME::Error &err);
63
65{
66 const QList<QByteArray> m_list;
67 mutable const char **m_patterns;
68public:
69 explicit PatternConverter(const QByteArray &ba);
70 explicit PatternConverter(const QString &s);
71 explicit PatternConverter(const QList<QByteArray> &lba);
72 explicit PatternConverter(const QStringList &sl);
74
75 const char **patterns() const;
76};
77
79{
80 QObject *const m_object;
81 QThread *const m_thread;
82public:
83 ToThreadMover(QObject *o, QThread *t) : m_object(o), m_thread(t) {}
84 ToThreadMover(QObject &o, QThread *t) : m_object(&o), m_thread(t) {}
85 ToThreadMover(const std::shared_ptr<QObject> &o, QThread *t) : m_object(o.get()), m_thread(t) {}
87 {
88 if (m_object && m_thread) {
89 m_object->moveToThread(m_thread);
90 }
91 }
92};
93
94template <typename T_result>
95class Thread : public QThread
96{
97public:
98 explicit Thread(QObject *parent = Q_NULLPTR) : QThread(parent) {}
99
100 void setFunction(const std::function<T_result()> &function)
101 {
102 const QMutexLocker locker(&m_mutex);
103 m_function = function;
104 }
105
106 bool hasFunction()
107 {
108 const QMutexLocker locker(&m_mutex);
109 return static_cast<bool>(m_function);
110 }
111
112 T_result result() const
113 {
114 const QMutexLocker locker(&m_mutex);
115 return m_result;
116 }
117
118private:
119 void run() override {
120 const QMutexLocker locker(&m_mutex);
121 m_result = m_function();
122 }
123private:
124 mutable QMutex m_mutex;
125 std::function<T_result()> m_function;
126 T_result m_result;
127};
128
129template <typename T_base, typename T_result = std::tuple<GpgME::Error, QString, GpgME::Error> >
130class ThreadedJobMixin : public T_base, public GpgME::ProgressProvider
131{
132public:
134 typedef T_result result_type;
135
136 void run()
137 {
138 Q_ASSERT(m_thread.hasFunction() && "Call setWorkerFunction() before run()");
139 m_thread.start();
140 }
141
142protected:
143 static_assert(std::tuple_size<T_result>::value > 2,
144 "Result tuple too small");
145 static_assert(std::is_same <
146 typename std::tuple_element <
147 std::tuple_size<T_result>::value - 2,
149 >::type,
150 QString
151 >::value,
152 "Second to last result type not a QString");
153 static_assert(std::is_same <
154 typename std::tuple_element <
155 std::tuple_size<T_result>::value - 1,
157 >::type,
158 GpgME::Error
159 >::value,
160 "Last result type not a GpgME::Error");
161
162 explicit ThreadedJobMixin(GpgME::Context *ctx)
163 : T_base(nullptr), m_ctx(ctx), m_thread(), m_auditLog(), m_auditLogError()
164 {
165 }
166
167 void lateInitialization()
168 {
169 assert(m_ctx);
170 QObject::connect(&m_thread, &QThread::finished, this,
171 &mixin_type::slotFinished);
172 m_ctx->setProgressProvider(this);
173 QGpgME::g_context_map.insert(this, m_ctx.get());
174 }
175
177 {
178 QGpgME::g_context_map.remove(this);
179 }
180
181 template <typename T_binder>
182 void setWorkerFunction(const T_binder &func)
183 {
184 m_thread.setFunction([this, func]() { return func(this->context()); });
185 }
186
187public:
188 template <typename T_binder>
189 void run(const T_binder &func)
190 {
191 m_thread.setFunction(std::bind(func, this->context()));
192 m_thread.start();
193 }
194 template <typename T_binder>
195 void run(const T_binder &func, const std::shared_ptr<QIODevice> &io)
196 {
197 if (io) {
198 io->moveToThread(&m_thread);
199 }
200 // the arguments passed here to the functor are stored in a QThread, and are not
201 // necessarily destroyed (living outside the UI thread) at the time the result signal
202 // is emitted and the signal receiver wants to clean up IO devices.
203 // To avoid such races, we pass std::weak_ptr's to the functor.
204 m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io)));
205 m_thread.start();
206 }
207 template <typename T_binder>
208 void run(const T_binder &func, const std::shared_ptr<QIODevice> &io1, const std::shared_ptr<QIODevice> &io2)
209 {
210 if (io1) {
211 io1->moveToThread(&m_thread);
212 }
213 if (io2) {
214 io2->moveToThread(&m_thread);
215 }
216 // the arguments passed here to the functor are stored in a QThread, and are not
217 // necessarily destroyed (living outside the UI thread) at the time the result signal
218 // is emitted and the signal receiver wants to clean up IO devices.
219 // To avoid such races, we pass std::weak_ptr's to the functor.
220 m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io1), std::weak_ptr<QIODevice>(io2)));
221 m_thread.start();
222 }
223
224protected:
225 GpgME::Context *context() const
226 {
227 return m_ctx.get();
228 }
229
230 virtual void resultHook(const result_type &) {}
231
232 void slotFinished()
233 {
234 const T_result r = m_thread.result();
235 m_auditLog = std::get < std::tuple_size<T_result>::value - 2 > (r);
236 m_auditLogError = std::get < std::tuple_size<T_result>::value - 1 > (r);
237 resultHook(r);
238 Q_EMIT this->done();
239 doEmitResult(r);
240 this->deleteLater();
241 }
242 void slotCancel() override {
243 if (m_ctx)
244 {
245 m_ctx->cancelPendingOperation();
246 }
247 }
248 QString auditLogAsHtml() const override
249 {
250 return m_auditLog;
251 }
252 GpgME::Error auditLogError() const override
253 {
254 return m_auditLogError;
255 }
256 void showProgress(const char *what,
257 int type, int current, int total) override {
258 QMetaObject::invokeMethod(this, [this, current, total]() {
259 Q_EMIT this->jobProgress(current, total);
260 }, Qt::QueuedConnection);
261 const QString what_ = QString::fromUtf8(what);
262 QMetaObject::invokeMethod(this, [this, what_, type, current, total]() {
263 Q_EMIT this->rawProgress(what_, type, current, total);
264 }, Qt::QueuedConnection);
265 QMetaObject::invokeMethod(this, [this, what_, current, total]() {
268 Q_EMIT this->progress(what_, current, total);
270 }, Qt::QueuedConnection);
271 }
272private:
273 template <typename T1, typename T2>
274 void doEmitResult(const std::tuple<T1, T2> &tuple)
275 {
276 Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple));
277 }
278
279 template <typename T1, typename T2, typename T3>
280 void doEmitResult(const std::tuple<T1, T2, T3> &tuple)
281 {
282 Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
283 }
284
285 template <typename T1, typename T2, typename T3, typename T4>
286 void doEmitResult(const std::tuple<T1, T2, T3, T4> &tuple)
287 {
288 Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple));
289 }
290
291 template <typename T1, typename T2, typename T3, typename T4, typename T5>
292 void doEmitResult(const std::tuple<T1, T2, T3, T4, T5> &tuple)
293 {
294 Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple));
295 }
296
297private:
298 std::shared_ptr<GpgME::Context> m_ctx;
299 Thread<T_result> m_thread;
300 QString m_auditLog;
301 GpgME::Error m_auditLogError;
302};
303
304}
305}
306
307#endif /* __QGPGME_THREADEDJOBMIXING_H__ */
Definition threadedjobmixin.h:65
Definition threadedjobmixin.h:96
Definition threadedjobmixin.h:131
Definition threadedjobmixin.h:79
Definition qgpgmebackend.h:43