QGpgME  20.5.1.0000000
Qt API for GpgME
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 
57 namespace QGpgME
58 {
59 namespace _detail
60 {
61 
62 QString audit_log_as_html(GpgME::Context *ctx, GpgME::Error &err);
63 
65 {
66  const QList<QByteArray> m_list;
67  mutable const char **m_patterns;
68 public:
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;
82 public:
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) {}
86  ~ToThreadMover()
87  {
88  if (m_object && m_thread) {
89  m_object->moveToThread(m_thread);
90  }
91  }
92 };
93 
94 template <typename T_result>
95 class Thread : public QThread
96 {
97 public:
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 
118 private:
119  void run() override {
120  const QMutexLocker locker(&m_mutex);
121  m_result = m_function();
122  }
123 private:
124  mutable QMutex m_mutex;
125  std::function<T_result()> m_function;
126  T_result m_result;
127 };
128 
129 template <typename T_base, typename T_result = std::tuple<GpgME::Error, QString, GpgME::Error> >
130 class ThreadedJobMixin : public T_base, public GpgME::ProgressProvider
131 {
132 public:
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 
142 protected:
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,
148  T_result
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,
156  T_result
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 
187 public:
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 
224 protected:
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]() {
266  QT_WARNING_PUSH
267  QT_WARNING_DISABLE_DEPRECATED
268  Q_EMIT this->progress(what_, current, total);
269  QT_WARNING_POP
270  }, Qt::QueuedConnection);
271  }
272 private:
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 
297 private:
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