1 /*!
2  * \copyright Copyright (c) 2015-2021 Governikus GmbH & Co. KG, Germany
3  */
4 
5 #include "ReaderManagerWorker.h"
6 
7 #include "Initializer.h"
8 #include "Reader.h"
9 
10 #include <QLoggingCategory>
11 #include <QPluginLoader>
12 #include <QThread>
13 
14 Q_DECLARE_LOGGING_CATEGORY(card)
15 
16 using namespace governikus;
17 
__anon1f26c66a0102null18 INIT_FUNCTION([] {
19 			qRegisterMetaType<QSharedPointer<CardConnectionWorker> >("QSharedPointer<CardConnectionWorker>");
20 		})
21 
22 
ReaderManagerWorker()23 ReaderManagerWorker::ReaderManagerWorker()
24 	: QObject()
25 	, mPlugIns()
26 {
27 }
28 
29 
~ReaderManagerWorker()30 ReaderManagerWorker::~ReaderManagerWorker()
31 {
32 	Q_ASSERT(QObject::thread() == QThread::currentThread());
33 	qCDebug(card) << "Worker removed";
34 }
35 
36 
shutdown()37 void ReaderManagerWorker::shutdown()
38 {
39 	qCDebug(card) << "Shutdown ReaderManagerWorker";
40 	for (auto& plugin : qAsConst(mPlugIns))
41 	{
42 		plugin->stopScan();
43 
44 		qCDebug(card) << "Shutdown plugin:" << plugin->metaObject()->className();
45 		plugin->shutdown();
46 
47 		// Plugins and therefore their members are not auto destructed due to a bug in Qt.
48 		// https://bugreports.qt.io/browse/QTBUG-17458
49 		plugin->deleteLater();
50 	}
51 	mPlugIns.clear();
52 }
53 
54 
onThreadStarted()55 void ReaderManagerWorker::onThreadStarted()
56 {
57 	Q_ASSERT(QObject::thread() == QThread::currentThread());
58 
59 	qCDebug(card) << "Thread started";
60 	registerPlugIns();
61 
62 	Q_EMIT fireInitialized();
63 }
64 
65 
registerPlugIns()66 void ReaderManagerWorker::registerPlugIns()
67 {
68 	qCDebug(card) << "Try to register plugins";
69 	const auto& plugins = QPluginLoader::staticPlugins();
70 	for (const auto& plugin : plugins)
71 	{
72 		if (isPlugIn(plugin.metaData()))
73 		{
74 			qCDebug(card) << "Register and initialize plugin:" << plugin.metaData();
75 			ReaderManagerPlugIn* pluginInstance = qobject_cast<ReaderManagerPlugIn*>(plugin.instance());
76 			if (pluginInstance == nullptr)
77 			{
78 				qCWarning(card) << "Cannot cast to plugin instance:" << plugin.instance();
79 			}
80 			else
81 			{
82 				registerPlugIn(pluginInstance);
83 				pluginInstance->init();
84 
85 				Q_EMIT firePluginAdded(pluginInstance->getInfo());
86 			}
87 		}
88 	}
89 }
90 
91 
isPlugIn(const QJsonObject & pJson) const92 bool ReaderManagerWorker::isPlugIn(const QJsonObject& pJson) const
93 {
94 	return pJson.value(QStringLiteral("IID")).toString() == QLatin1String("governikus.ReaderManagerPlugIn");
95 }
96 
97 
registerPlugIn(ReaderManagerPlugIn * pPlugIn)98 void ReaderManagerWorker::registerPlugIn(ReaderManagerPlugIn* pPlugIn)
99 {
100 	Q_ASSERT(pPlugIn != nullptr);
101 	Q_ASSERT(!mPlugIns.contains(pPlugIn));
102 
103 	mPlugIns << pPlugIn;
104 
105 	connect(pPlugIn, &ReaderManagerPlugIn::fireReaderAdded, this, &ReaderManagerWorker::fireReaderAdded);
106 	connect(pPlugIn, &ReaderManagerPlugIn::fireReaderRemoved, this, &ReaderManagerWorker::fireReaderRemoved);
107 	connect(pPlugIn, &ReaderManagerPlugIn::fireReaderPropertiesUpdated, this, &ReaderManagerWorker::fireReaderPropertiesUpdated);
108 	connect(pPlugIn, &ReaderManagerPlugIn::fireStatusChanged, this, &ReaderManagerWorker::fireStatusChanged);
109 	connect(pPlugIn, &ReaderManagerPlugIn::fireCardInserted, this, &ReaderManagerWorker::fireCardInserted);
110 	connect(pPlugIn, &ReaderManagerPlugIn::fireCardRemoved, this, &ReaderManagerWorker::fireCardRemoved);
111 	connect(pPlugIn, &ReaderManagerPlugIn::fireCardRetryCounterChanged, this, &ReaderManagerWorker::fireCardRetryCounterChanged);
112 }
113 
114 
reset(ReaderManagerPlugInType pType)115 void ReaderManagerWorker::reset(ReaderManagerPlugInType pType)
116 {
117 	Q_ASSERT(QObject::thread() == QThread::currentThread());
118 
119 	for (auto& plugin : qAsConst(mPlugIns))
120 	{
121 		if (plugin->getInfo().getPlugInType() == pType)
122 		{
123 			qCDebug(card) << "Reset plugin:" << plugin->metaObject()->className();
124 			plugin->reset();
125 		}
126 	}
127 }
128 
129 
startScan(ReaderManagerPlugInType pType,bool pAutoConnect)130 void ReaderManagerWorker::startScan(ReaderManagerPlugInType pType, bool pAutoConnect)
131 {
132 	Q_ASSERT(QObject::thread() == QThread::currentThread());
133 
134 	for (auto& plugin : qAsConst(mPlugIns))
135 	{
136 		if (plugin->getInfo().getPlugInType() == pType)
137 		{
138 			qCDebug(card) << "Start scan on plugin:" << plugin->metaObject()->className();
139 			plugin->startScan(pAutoConnect);
140 		}
141 	}
142 }
143 
144 
stopScan(ReaderManagerPlugInType pType,const QString & pError)145 void ReaderManagerWorker::stopScan(ReaderManagerPlugInType pType, const QString& pError)
146 {
147 	Q_ASSERT(QObject::thread() == QThread::currentThread());
148 
149 	for (auto& plugin : qAsConst(mPlugIns))
150 	{
151 		if (plugin->getInfo().getPlugInType() == pType)
152 		{
153 			qCDebug(card) << "Stop scan on plugin:" << plugin->metaObject()->className();
154 			plugin->stopScan(pError);
155 		}
156 	}
157 }
158 
159 
isScanRunning() const160 bool ReaderManagerWorker::isScanRunning() const
161 {
162 	Q_ASSERT(QObject::thread() == QThread::currentThread());
163 
164 	for (const auto& plugin : qAsConst(mPlugIns))
165 	{
166 		if (plugin->isScanRunning())
167 		{
168 			return true;
169 		}
170 	}
171 	return false;
172 }
173 
174 
isScanRunning(ReaderManagerPlugInType pType) const175 bool ReaderManagerWorker::isScanRunning(ReaderManagerPlugInType pType) const
176 {
177 	Q_ASSERT(QObject::thread() == QThread::currentThread());
178 
179 	for (const auto& plugin : qAsConst(mPlugIns))
180 	{
181 		if (plugin->getInfo().getPlugInType() == pType && plugin->isScanRunning())
182 		{
183 			return true;
184 		}
185 	}
186 	return false;
187 }
188 
189 
getReaderInfos() const190 QVector<ReaderInfo> ReaderManagerWorker::getReaderInfos() const
191 {
192 	Q_ASSERT(QObject::thread() == QThread::currentThread());
193 
194 	QVector<ReaderInfo> list;
195 	for (const auto& plugIn : qAsConst(mPlugIns))
196 	{
197 		const auto& readerList = plugIn->getReaders();
198 		for (const Reader* const reader : readerList)
199 		{
200 			list += reader->getReaderInfo();
201 		}
202 	}
203 	return list;
204 }
205 
206 
updateReaderInfo(const QString & pReaderName)207 void ReaderManagerWorker::updateReaderInfo(const QString& pReaderName)
208 {
209 	Q_ASSERT(QObject::thread() == QThread::currentThread());
210 
211 	Reader* reader = getReader(pReaderName);
212 	if (reader == nullptr)
213 	{
214 		qCWarning(card) << "Requested reader does not exist:" << pReaderName;
215 		return;
216 	}
217 	reader->update();
218 }
219 
220 
getReader(const QString & pReaderName) const221 Reader* ReaderManagerWorker::getReader(const QString& pReaderName) const
222 {
223 	Q_ASSERT(QObject::thread() == QThread::currentThread());
224 
225 	for (auto& plugin : qAsConst(mPlugIns))
226 	{
227 		const auto& readerList = plugin->getReaders();
228 		for (Reader* reader : readerList)
229 		{
230 			if (reader->getName() == pReaderName)
231 			{
232 				return reader;
233 			}
234 		}
235 	}
236 
237 	qCWarning(card) << "Requested reader does not exist:" << pReaderName;
238 	return nullptr;
239 }
240 
241 
createCardConnectionWorker(const QString & pReaderName)242 void ReaderManagerWorker::createCardConnectionWorker(const QString& pReaderName)
243 {
244 	Q_ASSERT(QObject::thread() == QThread::currentThread());
245 
246 	QSharedPointer<CardConnectionWorker> worker;
247 	if (auto reader = getReader(pReaderName))
248 	{
249 		worker = reader->createCardConnectionWorker();
250 	}
251 	Q_EMIT fireCardConnectionWorkerCreated(worker);
252 }
253 
254 
updateRetryCounters()255 void ReaderManagerWorker::updateRetryCounters()
256 {
257 	Q_ASSERT(QObject::thread() == QThread::currentThread());
258 
259 	const auto& readerInfos = getReaderInfos();
260 	for (const auto& readerInfo : readerInfos)
261 	{
262 		QSharedPointer<CardConnectionWorker> worker;
263 		if (const auto& reader = getReader(readerInfo.getName()))
264 		{
265 			worker = reader->createCardConnectionWorker();
266 			if (worker)
267 			{
268 				worker->updateRetryCounter();
269 			}
270 		}
271 	}
272 }
273