QGpgME  10.3.4.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  T_result result() const
107  {
108  const QMutexLocker locker(&m_mutex);
109  return m_result;
110  }
111 
112 private:
113  void run() Q_DECL_OVERRIDE {
114  const QMutexLocker locker(&m_mutex);
115  m_result = m_function();
116  }
117 private:
118  mutable QMutex m_mutex;
119  std::function<T_result()> m_function;
120  T_result m_result;
121 };
122 
123 template <typename T_base, typename T_result = std::tuple<GpgME::Error, QString, GpgME::Error> >
124 class ThreadedJobMixin : public T_base, public GpgME::ProgressProvider
125 {
126 public:
128  typedef T_result result_type;
129 
130 protected:
131  static_assert(std::tuple_size<T_result>::value > 2,
132  "Result tuple too small");
133  static_assert(std::is_same <
134  typename std::tuple_element <
135  std::tuple_size<T_result>::value - 2,
136  T_result
137  >::type,
138  QString
139  >::value,
140  "Second to last result type not a QString");
141  static_assert(std::is_same <
142  typename std::tuple_element <
143  std::tuple_size<T_result>::value - 1,
144  T_result
145  >::type,
146  GpgME::Error
147  >::value,
148  "Last result type not a GpgME::Error");
149 
150  explicit ThreadedJobMixin(GpgME::Context *ctx)
151  : T_base(nullptr), m_ctx(ctx), m_thread(), m_auditLog(), m_auditLogError()
152  {
153  }
154 
155  void lateInitialization()
156  {
157  assert(m_ctx);
158  QObject::connect(&m_thread, &QThread::finished, this,
159  &mixin_type::slotFinished);
160  m_ctx->setProgressProvider(this);
161  QGpgME::g_context_map.insert(this, m_ctx.get());
162  }
163 
165  {
166  QGpgME::g_context_map.remove(this);
167  }
168 
169  template <typename T_binder>
170  void run(const T_binder &func)
171  {
172  m_thread.setFunction(std::bind(func, this->context()));
173  m_thread.start();
174  }
175  template <typename T_binder>
176  void run(const T_binder &func, const std::shared_ptr<QIODevice> &io)
177  {
178  if (io) {
179  io->moveToThread(&m_thread);
180  }
181  // the arguments passed here to the functor are stored in a QThread, and are not
182  // necessarily destroyed (living outside the UI thread) at the time the result signal
183  // is emitted and the signal receiver wants to clean up IO devices.
184  // To avoid such races, we pass std::weak_ptr's to the functor.
185  m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io)));
186  m_thread.start();
187  }
188  template <typename T_binder>
189  void run(const T_binder &func, const std::shared_ptr<QIODevice> &io1, const std::shared_ptr<QIODevice> &io2)
190  {
191  if (io1) {
192  io1->moveToThread(&m_thread);
193  }
194  if (io2) {
195  io2->moveToThread(&m_thread);
196  }
197  // the arguments passed here to the functor are stored in a QThread, and are not
198  // necessarily destroyed (living outside the UI thread) at the time the result signal
199  // is emitted and the signal receiver wants to clean up IO devices.
200  // To avoid such races, we pass std::weak_ptr's to the functor.
201  m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io1), std::weak_ptr<QIODevice>(io2)));
202  m_thread.start();
203  }
204  GpgME::Context *context() const
205  {
206  return m_ctx.get();
207  }
208 
209  virtual void resultHook(const result_type &) {}
210 
211  void slotFinished()
212  {
213  const T_result r = m_thread.result();
214  m_auditLog = std::get < std::tuple_size<T_result>::value - 2 > (r);
215  m_auditLogError = std::get < std::tuple_size<T_result>::value - 1 > (r);
216  resultHook(r);
217  Q_EMIT this->done();
218  doEmitResult(r);
219  this->deleteLater();
220  }
221  void slotCancel() Q_DECL_OVERRIDE {
222  if (m_ctx)
223  {
224  m_ctx->cancelPendingOperation();
225  }
226  }
227  QString auditLogAsHtml() const Q_DECL_OVERRIDE
228  {
229  return m_auditLog;
230  }
231  GpgME::Error auditLogError() const Q_DECL_OVERRIDE
232  {
233  return m_auditLogError;
234  }
235  void showProgress(const char * /*what*/,
236  int /*type*/, int current, int total) Q_DECL_OVERRIDE {
237  // will be called from the thread exec'ing the operation, so
238  // just bounce everything to the owning thread:
239  // ### hope this is thread-safe (meta obj is const, and
240  // ### portEvent is thread-safe, so should be ok)
241  QMetaObject::invokeMethod(this, "progress", Qt::QueuedConnection,
242  // TODO port
243  Q_ARG(QString, QString()),
244  Q_ARG(int, current),
245  Q_ARG(int, total));
246  }
247 private:
248  template <typename T1, typename T2>
249  void doEmitResult(const std::tuple<T1, T2> &tuple)
250  {
251  Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple));
252  }
253 
254  template <typename T1, typename T2, typename T3>
255  void doEmitResult(const std::tuple<T1, T2, T3> &tuple)
256  {
257  Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
258  }
259 
260  template <typename T1, typename T2, typename T3, typename T4>
261  void doEmitResult(const std::tuple<T1, T2, T3, T4> &tuple)
262  {
263  Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple));
264  }
265 
266  template <typename T1, typename T2, typename T3, typename T4, typename T5>
267  void doEmitResult(const std::tuple<T1, T2, T3, T4, T5> &tuple)
268  {
269  Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple));
270  }
271 
272 private:
273  std::shared_ptr<GpgME::Context> m_ctx;
274  Thread<T_result> m_thread;
275  QString m_auditLog;
276  GpgME::Error m_auditLogError;
277 };
278 
279 }
280 }
281 
282 #endif /* __QGPGME_THREADEDJOBMIXING_H__ */
QGpgME::_detail::ThreadedJobMixin
Definition: threadedjobmixin.h:124
QGpgME::_detail::ToThreadMover
Definition: threadedjobmixin.h:78
QGpgME::_detail::Thread
Definition: threadedjobmixin.h:95
QGpgME::_detail::PatternConverter
Definition: threadedjobmixin.h:64