swift
infodatareader.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2016 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QJsonDocument>
7 #include <QJsonObject>
8 #include <QTimer>
9 
10 #include "core/application.h"
11 #include "core/webdataservices.h"
12 #include "misc/logmessage.h"
14 #include "misc/sequence.h"
15 #include "misc/verify.h"
16 
17 using namespace swift::misc;
18 using namespace swift::misc::network;
19 using namespace swift::misc::db;
20 using namespace swift::core::data;
21 
22 namespace swift::core::db
23 {
24  CInfoDataReader::CInfoDataReader(QObject *owner, const CDatabaseReaderConfigList &config,
26  : CDatabaseReader(owner, config, "CInfoDataReader"), m_mode(mode)
27  {
28  Q_ASSERT_X(mode == CDbFlags::DbReading || mode == CDbFlags::Shared, Q_FUNC_INFO, "Wrong mode");
29  }
30 
32  {
33  QReadLocker l(&m_lockInfoObjects);
34  return m_infoObjects;
35  }
36 
38  {
39  QReadLocker l(&m_lockInfoObjects);
40  return m_infoObjects.size();
41  }
42 
43  bool CInfoDataReader::areAllInfoObjectsRead() const { return this->getInfoObjectCount() > 4; }
44 
45  void CInfoDataReader::synchronizeCaches(CEntityFlags::Entity entities)
46  {
47  // no caching used here
48  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Using this for CInfoDataReader makes no sense");
49  Q_UNUSED(entities);
50  }
51 
52  void CInfoDataReader::admitCaches(CEntityFlags::Entity entities)
53  {
54  // no caching used here
55  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Using this for CInfoDataReader makes no sense");
56  Q_UNUSED(entities);
57  }
58 
59  void CInfoDataReader::invalidateCaches(CEntityFlags::Entity entities)
60  {
61  // no caching used here
62  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Using this for CInfoDataReader makes no sense");
63  Q_UNUSED(entities);
64  }
65 
66  QDateTime CInfoDataReader::getCacheTimestamp(CEntityFlags::Entity entity) const
67  {
68  // no own caching used here
69  Q_UNUSED(entity);
70  Q_ASSERT_X(CEntityFlags::isSingleEntity(entity), Q_FUNC_INFO, "Need single entity");
71  Q_ASSERT_X(sApp, Q_FUNC_INFO, "Need sApp");
72 
73  if (entity == CEntityFlags::DbInfoObjectEntity || entity == CEntityFlags::SharedInfoObjectEntity)
74  {
75  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Using this for CInfoDataReader makes no sense");
76  return QDateTime();
77  }
78 
79  // Forward to web data services so I get cache data from other readers
81  return sApp->getWebDataServices()->getCacheTimestamp(entity);
82  }
83 
84  int CInfoDataReader::getCacheCount(CEntityFlags::Entity entity) const
85  {
86  // no own caching used here
87  Q_UNUSED(entity);
88  Q_ASSERT_X(CEntityFlags::isSingleEntity(entity), Q_FUNC_INFO, "Need single entity");
89  Q_ASSERT_X(sApp, Q_FUNC_INFO, "Need sApp");
90 
91  if (entity == CEntityFlags::DbInfoObjectEntity || entity == CEntityFlags::SharedInfoObjectEntity)
92  {
93  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Using this for CInfoDataReader makes no sense");
94  return 0;
95  }
96 
97  // Forward to web data services so I get cache data from other readers
99  return sApp->getWebDataServices()->getCacheCount(entity);
100  }
101 
102  CEntityFlags::Entity CInfoDataReader::getEntitiesWithCacheCount() const
103  {
104  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Using this for CInfoDataReader makes no sense");
105  return CEntityFlags::NoEntity;
106  }
107 
108  CEntityFlags::Entity CInfoDataReader::getEntitiesWithCacheTimestampNewerThan(const QDateTime &threshold) const
109  {
110  Q_UNUSED(threshold);
111  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Using this for CInfoDataReader makes no sense");
112  return CEntityFlags::NoEntity;
113  }
114 
115  bool CInfoDataReader::hasChangedUrl(CEntityFlags::Entity entity, CUrl &oldUrlInfo, CUrl &newUrlInfo) const
116  {
117  // not implemented
118  Q_UNUSED(entity);
119 
120  // init the URLs
121  oldUrlInfo = this->getBaseUrl(CDbFlags::DbReading);
122  newUrlInfo = this->getBaseUrl(CDbFlags::DbReading);
123  return false;
124  }
125 
127 
129  {
130  if (!this->doWorkCheck()) { return; }
131 
132  const CUrl url(this->getInfoObjectsUrl());
133  const CUrlLogList urlLogList(this->getUrlLogList()); // thread safe copy
134 
135  if (urlLogList.hasPending())
136  {
137  CLogMessage(this).info(u"Info data reading still pending, summary: '%1'") << urlLogList.getSummary();
138  return;
139  }
140  if (!url.isEmpty())
141  {
142  this->getFromNetworkAndLog(url, { this, &CInfoDataReader::parseInfoObjectsData });
143  emit this->dataRead(this->getEntityForMode(), CEntityFlags::ReadStarted, 0, url);
144  }
145  else { this->logNoWorkingUrl(this->getEntityForMode()); }
146  }
147 
148  void CInfoDataReader::parseInfoObjectsData(QNetworkReply *nwReplyPtr)
149  {
150  // wrap pointer, make sure any exit cleans up reply
151  // required to use delete later as object is created in a different thread
152  QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(nwReplyPtr);
153  if (!this->doWorkCheck()) { return; }
154 
155  const CDatabaseReader::JsonDatastoreResponse res =
157  if (res.hasErrorMessage())
158  {
159  CLogMessage::preformatted(res.lastWarningOrAbove());
160  emit this->dataRead(this->getEntityForMode(), CEntityFlags::ReadFailed, 0, res.getUrl());
161  return;
162  }
163 
164  // get all or incremental set
165  const CDbInfoList infoObjects = CDbInfoList::fromDatabaseJson(res.getJsonArray());
166  const int n = infoObjects.size();
167 
168  // Service URL => DB data
169  // DB data directory => shared files
170  const QString urlStr = nwReply->url().toString();
171  Q_UNUSED(urlStr) // debug only
172 
173  // this part needs to be synchronized
174  {
175  QWriteLocker wl(&m_lockInfoObjects);
176  m_infoObjects = infoObjects;
177  }
178 
179  this->emitAndLogDataRead(this->getEntityForMode(), n, res);
180  }
181 
182  CUrl CInfoDataReader::getDbInfoObjectsUrl() const
183  {
184  return getBaseUrl(CDbFlags::DbReading).withAppendedPath("jsondbinfo.php");
185  }
186 
187  CUrl CInfoDataReader::getSharedInfoObjectsUrl() const
188  {
189  return getBaseUrl(CDbFlags::Shared).withAppendedPath(CDbInfo::sharedInfoFileName());
190  }
191 
192  CEntityFlags::EntityFlag CInfoDataReader::getEntityForMode() const
193  {
194  if (m_mode == CDbFlags::DbReading) { return CEntityFlags::DbInfoObjectEntity; }
195  if (m_mode == CDbFlags::Shared) { return CEntityFlags::SharedInfoObjectEntity; }
196  qFatal("Wrong mode");
197  return CEntityFlags::NoEntity;
198  }
199 
200  void CInfoDataReader::read(CEntityFlags::Entity entities, CDbFlags::DataRetrievalModeFlag mode,
201  const QDateTime &newerThan)
202  {
203  Q_UNUSED(entities)
204  Q_UNUSED(mode)
205  Q_UNUSED(newerThan)
206  Q_ASSERT_X(false, Q_FUNC_INFO, "Not implemented for CInfoDataReader");
207  }
208 
210  {
211  switch (m_mode)
212  {
213  case CDbFlags::DbReading: return getDbInfoObjectsUrl();
214  case CDbFlags::Shared: return getSharedInfoObjectsUrl();
215  default: qFatal("Wrong mode");
216  }
217  return CUrl();
218  }
219 
220  CStatusMessageList CInfoDataReader::readFromJsonFiles(const QString &dir, CEntityFlags::Entity whatToRead,
221  bool overrideNewer)
222  {
223  Q_UNUSED(dir)
224  Q_UNUSED(whatToRead)
225  Q_UNUSED(overrideNewer)
226  Q_ASSERT_X(false, Q_FUNC_INFO, "Not supported");
227 
228  return CStatusMessage(this).error(u"Not supported");
229  }
230 
231  bool CInfoDataReader::readFromJsonFilesInBackground(const QString &dir, CEntityFlags::Entity whatToRead,
232  bool overrideNewer)
233  {
234  Q_UNUSED(dir)
235  Q_UNUSED(whatToRead)
236  Q_UNUSED(overrideNewer)
237  Q_ASSERT_X(false, Q_FUNC_INFO, "Not supported");
238  return false;
239  }
240 
241  CEntityFlags::Entity CInfoDataReader::getSupportedEntities() const { return this->getEntityForMode(); }
242 } // namespace swift::core::db
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Definition: application.cpp:71
data::CGlobalSetup getGlobalSetup() const
Global setup.
CWebDataServices * getWebDataServices() const
Get the web data services.
swift::misc::network::CUrlLogList getUrlLogList() const
Get the URL log list.
QNetworkReply * getFromNetworkAndLog(const swift::misc::network::CUrl &url, const swift::misc::CSlot< void(QNetworkReply *)> &callback)
Get request from network, and log with m_urlReadLog.
bool doWorkCheck() const
Still enabled etc.?
QDateTime getCacheTimestamp(swift::misc::network::CEntityFlags::Entity entity) const
Corresponding cache timestamp if applicable.
int getCacheCount(swift::misc::network::CEntityFlags::Entity entity) const
Cache count for entity.
swift::misc::network::CUrl getDbInfoReaderUrl() const
Info data reader URL.
Definition: globalsetup.cpp:39
Value object encapsulating a list of reader configs.
Specialized version of threaded reader for DB data.
void emitAndLogDataRead(swift::misc::network::CEntityFlags::Entity entity, int number, const JsonDatastoreResponse &res)
Emit signal and log when data have been read.
void logNoWorkingUrl(swift::misc::network::CEntityFlags::Entity entity)
Log if no working URL exists, using m_noWorkingUrlSeverity.
swift::misc::network::CUrl getBaseUrl(swift::misc::db::CDbFlags::DataRetrievalModeFlag mode) const
Base URL for mode (either a shared or DB URL)
void dataRead(swift::misc::network::CEntityFlags::Entity entities, swift::misc::network::CEntityFlags::ReadState state, int number, const QUrl &url)
Combined read signal.
CDatabaseReader::JsonDatastoreResponse setStatusAndTransformReplyIntoDatastoreResponse(QNetworkReply *nwReply)
Check if terminated or error, otherwise split into array of objects.
int getInfoObjectCount() const
Get info list size (either shared or from DB)
virtual void read(swift::misc::network::CEntityFlags::Entity entities, swift::misc::db::CDbFlags::DataRetrievalModeFlag mode, const QDateTime &newerThan)
Read / re-read data file.
swift::misc::db::CDbInfoList getInfoObjects() const
Get info list (either shared or from DB)
virtual void synchronizeCaches(swift::misc::network::CEntityFlags::Entity entities)
Admit caches for given entities.
void readInfoData()
Allow to call directly, special for info objects reader.
virtual int getCacheCount(swift::misc::network::CEntityFlags::Entity entity) const
Cache`s number of entities.
virtual swift::misc::CStatusMessageList readFromJsonFiles(const QString &dir, swift::misc::network::CEntityFlags::Entity whatToRead, bool overrideNewer)
Data read from local data.
swift::misc::network::CUrl getInfoObjectsUrl() const
URL depending on mode, i.e. shared/DB.
virtual void invalidateCaches(swift::misc::network::CEntityFlags::Entity entities)
Invalidate the caches for given entities.
virtual bool hasChangedUrl(swift::misc::network::CEntityFlags::Entity entity, swift::misc::network::CUrl &oldUrlInfo, swift::misc::network::CUrl &newUrlInfo) const
Changed URL, means the cache values have been read from elsewhere.
virtual void admitCaches(swift::misc::network::CEntityFlags::Entity entities)
Admit caches for given entities.
virtual swift::misc::network::CEntityFlags::Entity getEntitiesWithCacheTimestampNewerThan(const QDateTime &threshold) const
Entities already having data in cache (based on timestamp assumption)
virtual swift::misc::network::CEntityFlags::Entity getEntitiesWithCacheCount() const
Entities already having data in cache.
virtual QDateTime getCacheTimestamp(swift::misc::network::CEntityFlags::Entity entity) const
Get cache timestamp.
virtual swift::misc::network::CUrl getDbServiceBaseUrl() const
Get the service URL, individual for each reader.
bool areAllInfoObjectsRead() const
All data read?
virtual bool readFromJsonFilesInBackground(const QString &dir, swift::misc::network::CEntityFlags::Entity whatToRead, bool overrideNewer)
Data read from local data.
virtual swift::misc::network::CEntityFlags::Entity getSupportedEntities() const
Supported entities by this reader.
Class for emitting a log message.
Definition: logmessage.h:27
static void preformatted(const CStatusMessage &statusMessage)
Sends a verbatim, preformatted message to the log.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
Streamable status message, e.g.
Status messages, e.g. from Core -> GUI.
DataRetrievalModeFlag
Which data to read, requires corresponding readers.
Definition: dbflags.h:25
Value object encapsulating a list of info objects.
Definition: dbinfolist.h:27
EntityFlag
Which data to read, requires corresponding readers.
Definition: entityflags.h:26
Value object encapsulating information of a location, kind of simplified CValueObject compliant versi...
Definition: url.h:27
bool isEmpty() const
Empty.
Definition: url.cpp:54
CUrl withAppendedPath(const QString &path) const
Append path.
Definition: url.cpp:115
Value object encapsulating a list of voice rooms.
Definition: urlloglist.h:26
bool hasPending() const
Any pending calls.
Definition: urlloglist.cpp:48
QString getSummary() const
Summary.
Definition: urlloglist.cpp:129
Core data traits (aka cached values) and classes.
Classes interacting with the swift database (aka "datastore").
Free functions in swift::misc.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition: verify.h:26